/* * Copyright (c) 2003 * Daan Vreeken . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daan Vreeken. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Daan Vreeken OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Atmel at76c503 USB Wireless LAN driver * * Written by Daan Vreeken */ /* * ...intro verhaaltje gaat hier... */ /*#include */ /*#include */ #include #include #include /*#include */ /*#include */ #include #include #include #include #include /*#include */ /*#include */ #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_DEPEND(atuwi, usb, 1, 1, 1); MODULE_DEPEND(atuwi, ether, 1, 1, 1); /* * Various supported device vendors/products/radio type. */ Static struct atuwi_type atuwi_devs[] = { { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503, RadioRFMD }, { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300, RadioIntersil }, { 0, 0 } }; Static struct usb_qdat atuwi_qdat; Static int atuwi_match(device_ptr_t); Static int atuwi_attach(device_ptr_t); Static int atuwi_detach(device_ptr_t); Static void atuwi_shutdown(device_ptr_t); Static int atuwi_tx_list_init(struct atuwi_softc *); Static int atuwi_rx_list_init(struct atuwi_softc *); Static int atuwi_newbuf(struct atuwi_softc *, struct atuwi_chain *, struct mbuf *); Static int atuwi_encap(struct atuwi_softc *, struct mbuf *, int); Static void atuwi_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status); Static void atuwi_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status); Static void atuwi_start(struct ifnet *); Static void atuwi_rxstart(struct ifnet *); Static int atuwi_ioctl(struct ifnet *, u_long, caddr_t); Static void atuwi_init(void *); Static void atuwi_stop(struct atuwi_softc *); Static void atuwi_watchdog(struct ifnet *); Static device_method_t atuwi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, atuwi_match), DEVMETHOD(device_attach, atuwi_attach), DEVMETHOD(device_detach, atuwi_detach), DEVMETHOD(device_shutdown, atuwi_shutdown), { 0, 0 } }; Static driver_t atuwi_driver = { "atuwi", atuwi_methods, sizeof(struct atuwi_softc) }; Static devclass_t atuwi_devclass; DRIVER_MODULE(atuwi, uhub, atuwi_driver, atuwi_devclass, usbd_driver_load, 0); /* atuwi_reset * * Resets the usb device and handles reloading it's descriptors etc. * * Once it's working I think this could better be moved to usb_subr.c as * usbd_reset_device or something like that */ Static int atuwi_reset(struct atuwi_softc *sc) { usbd_status err; u_int8_t temp_address; usb_port_status_t stat; int retry = 0; usb_interface_descriptor_t *id; /* * This next part I'm not sure about... * I must be doing something wrong / missing something * (when we're done the sc->atuwi_iface->device ptr == 0xdeadc0de * and that's not a good thing :) */ /* send a reset to the device */ usbd_reset_port(sc->atuwi_udev->myhub,sc->atuwi_udev->powersrc->portno, &stat); /* save our address & set it to 0 for now */ temp_address = sc->atuwi_udev->address; /* we need to set it to 0 to be able to send a 'set address' */ sc->atuwi_udev->address=0; /* get the device descriptor since it has changed */ err = usbd_get_desc(sc->atuwi_udev, UDESC_DEVICE, 0, USB_MAX_IPACKET, &sc->atuwi_udev->ddesc); while (err && retry < 8) { usbd_delay_ms(sc->atuwi_udev,100); err = usbd_get_desc(sc->atuwi_udev,UDESC_DEVICE,0,USB_MAX_IPACKET,&sc->atuwi_udev->ddesc); } if (err) { printf("atuwi: could not get desc!\n"); return err; } USETW(sc->atuwi_udev->def_ep_desc.wMaxPacketSize, sc->atuwi_udev->ddesc.bMaxPacketSize); /* reload the device descriptor since it has changed */ err = usbd_reload_device_desc(sc->atuwi_udev); if (err) { printf("atuwi: reload device desc failed!\n"); return err; } /* now change the address of the device back to our previous address */ err = usbd_set_address(sc->atuwi_udev, temp_address); if (err) { printf("atuwi: set_address failed! (%d)\n",temp_address); return err; } /* store it again in the descriptor */ sc->atuwi_udev->address=temp_address; /* set device to config=1 */ err = usbd_set_config_no(sc->atuwi_udev, 1, 0); if (err) { printf("atuwi: set_config_index failed!\n"); return err; } if (usbd_fill_iface_data(sc->atuwi_iface->device, sc->atuwi_iface->index,0)) { printf("atuwi: fill iface data failed!\n"); return err; } /* update interface descriptor */ sc->atuwi_iface->idesc = usbd_find_idesc(sc->atuwi_udev->cdesc,0,0); /* update endpoints pointer */ sc->atuwi_iface->endpoints=sc->atuwi_udev->ifaces[0].endpoints; id = usbd_get_interface_descriptor(sc->atuwi_iface); printf("atuwi: ---------> num endpoints=%d\n", id->bNumEndpoints); return 0; } Static usbd_status atuwi_usb_request(struct atuwi_softc *sc, u_int8_t type, u_int8_t request, u_int16_t value, u_int16_t index, u_int16_t length, u_int8_t *data) { usb_device_request_t req; usbd_xfer_handle xfer; usbd_status err; req.bmRequestType=type; req.bRequest=request; USETW(req.wValue,value); USETW(req.wIndex,index); USETW(req.wLength,length); ATUWI_LOCK(sc); xfer = usbd_alloc_xfer(sc->atuwi_udev); usbd_setup_default_xfer(xfer, sc->atuwi_udev, 0, 500000, &req, data, length, USBD_SHORT_XFER_OK, 0); err = usbd_sync_transfer(xfer); usbd_free_xfer(xfer); ATUWI_UNLOCK(sc); return(err); } Static int atuwi_send_command(struct atuwi_softc *sc, u_int8_t *command, int size) { return atuwi_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, 0x0000, size, command); } Static int atuwi_get_cmd_status(struct atuwi_softc *sc, u_int8_t Cmd, u_int8_t *Status) { return atuwi_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, Cmd, 0x0000, 40, Status); } Static int atuwi_wait_completion(struct atuwi_softc *sc, u_int8_t cmd, u_int8_t *status) { int err; u_int8_t statusreq[40]; while (1) { err = atuwi_get_cmd_status(sc,cmd,statusreq); if (err) return err; if ((statusreq[5]!=STATUS_IN_PROGRESS) && (statusreq[5]!=STATUS_IDLE)) { if (status!=NULL) *status=statusreq[5]; return 0; } usbd_delay_ms(sc->atuwi_udev,25); } } #define NR(x) (void *)(x) /* * The linux driver uses seperate routines for every mib request they do * (eg. set_radio / set_preamble / set_frag / etc etc ) * We just define a list of types, sizes and offsets and use those */ /* Name Type Size Index */ #define MIB_LOCAL 0x01 #define MIB_LOCAL__BEACON_ENABLE MIB_LOCAL, 1, 2 #define MIB_LOCAL__AUTO_RATE_FALLBACK MIB_LOCAL, 1, 3 #define MIB_LOCAL__SSID_SIZE MIB_LOCAL, 1, 7 #define MIB_LOCAL__PREAMBLE MIB_LOCAL, 1, 9 #define MIB_MAC_ADDR 0x02 #define MIB_MAC_ADDR__ADDR MIB_MAC_ADDR, 6, 0 #define MIB_MAC 0x03 #define MIB_MAC__FRAG MIB_MAC, 2, 8 #define MIB_MAC__RTS MIB_MAC, 2, 10 #define MIB_MAC__DESIRED_SSID MIB_MAC, 32, 28 #define MIB_MAC_MGMT 0x05 #define MIB_MAC_MGMT__BEACON_PERIOD MIB_MAC_MGMT, 2, 0 #define MIB_MAC_MGMT__CURRENT_BSSID MIB_MAC_MGMT, 6, 14 #define MIB_MAC_MGMT__CURRENT_ESSID MIB_MAC_MGMT, 32, 20 #define MIB_MAC_MGMT__POWER_MODE MIB_MAC_MGMT, 1, 53 #define MIB_MAC_MGMT__IBSS_CHANGE MIB_MAC_MGMT, 1, 54 #define MIB_MAC_WEP 0x06 #define MIB_MAC_WEP__PRIVACY_INVOKED MIB_MAC_WEP, 1, 0 #define MIB_MAC_WEP__ICV_ERROR_COUNT MIB_MAC_WEP, 4, 4 #define MIB_MAC_WEP__EXCLUDED_COUNT MIB_MAC_WEP, 4, 8 #define MIB_PHY 0x07 #define MIB_PHY__CHANNEL MIB_PHY, 1, 20 #define MIB_PHY__REG_DOMAIN MIB_PHY, 1, 23 #define MIB_FW_VERSION 0x08 #define MIB_MDOMAIN 0x09 #define POWER_MODE_ACTIVE 1 #define POWER_MODE_SAVE 2 #define POWER_MODE_SMART 3 #define PREAMBLE_SHORT 1 #define PREAMBLE_LONG 0 Static int atuwi_send_mib(struct atuwi_softc *sc, u_int8_t Type, u_int8_t Size, u_int8_t Index, void *Data) { int err; /* * We don't construct a MIB packet first and then memcpy it into an * Atmel-command-packet, we just construct it the right way at once :) */ struct { /* AT76c503 command header */ u_int8_t AtCmd; u_int8_t AtReserved; u_int16_t AtSize; /* MIB header */ u_int8_t MIBType; u_int8_t MIBSize; u_int8_t MIBIndex; u_int8_t MIBReserved; /* MIB data */ u_int8_t Data[72]; } FullRequest; /* * For 1 and 2 byte requests we assume a direct value, * everything bigger than 2 bytes we assume a pointer to the data */ switch (Size) { case 0: break; case 1: FullRequest.Data[0]=(u_int32_t)Data & 0x000000ff; break; case 2: FullRequest.Data[0]=(u_int32_t)Data & 0x000000ff; FullRequest.Data[1]=(u_int32_t)Data >> 8; break; default: memcpy(FullRequest.Data,Data,Size); } FullRequest.MIBType=Type; FullRequest.MIBSize=Size; FullRequest.MIBIndex=Index; FullRequest.MIBReserved=0; FullRequest.AtCmd=CMD_SET_MIB; FullRequest.AtReserved=0; FullRequest.AtSize=Size+4; err = atuwi_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, 0x0000, FullRequest.AtSize+4, (u_int8_t *)&FullRequest); if (err) return err; return atuwi_wait_completion(sc,CMD_SET_MIB,NULL); } Static int atuwi_get_mib(struct atuwi_softc *sc, u_int8_t Type, u_int8_t Size, u_int8_t Index, u_int8_t *Buf) { /* linux/at76c503.c - 478 */ return atuwi_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033, Type << 8, Index, Size, Buf); } #define NO_MODE_YET 0 #define AD_HOC_MODE 1 #define INFRASTRUCTURE_MODE 2 Static int atuwi_start_ibss(struct atuwi_softc *sc) { int err; struct { u_int8_t Cmd; u_int8_t Reserved; u_int16_t Size; u_int8_t BSSID[6]; u_int8_t SSID[32]; u_int8_t BSSType; u_int8_t Channel; u_int8_t SSIDSize; u_int8_t Res[3]; } Request = {CMD_START_IBSS,0,sizeof(Request)-4}; memset(Request.BSSID,0xff,sizeof(Request.BSSID)); memset(Request.SSID,0x00,sizeof(Request.SSID)); memcpy(Request.SSID,sc->atuwi_ssid,sc->atuwi_ssidlen); Request.SSIDSize=sc->atuwi_ssidlen; Request.Channel=sc->atuwi_channel; Request.BSSType=AD_HOC_MODE; memset(Request.Res,0x00,sizeof(Request.Res)); /* Write config to adapter */ err = atuwi_send_command(sc,(u_int8_t *)&Request,sizeof(Request)); if (err) return err; /* Wait for the adapter to do it's thing */ err = atuwi_wait_completion(sc,CMD_START_IBSS,NULL); if (err) return err; /* If we're switching modes (infra -> adhoc) tell the adapter */ if (sc->atuwi_mode!=AD_HOC_MODE) { err = atuwi_send_mib(sc,MIB_MAC_MGMT__IBSS_CHANGE,NR(0)); if (err) return err; sc->atuwi_mode=AD_HOC_MODE; } /* Get the current BSSID */ err=atuwi_get_mib(sc,MIB_MAC_MGMT__CURRENT_BSSID, sc->atuwi_bssid); if (err) return err; printf("atuwi: start_ibss using BSSID=%6D\n", sc->atuwi_bssid, ":"); return 0; } Static int atuwi_switch_radio(struct atuwi_softc *sc, int state) { int err; struct atuwi_cmd CmdRadio = {CMD_RADIO_ON,0,0}; if (sc->atuwi_radio_on != state) { if (state==0) CmdRadio.Cmd=CMD_RADIO_OFF; err = atuwi_send_command(sc, (u_int8_t *)&CmdRadio, sizeof(CmdRadio)); if (err) return err; err = atuwi_wait_completion(sc, CmdRadio.Cmd, NULL); if (err) return err; /* * Some adapters go silent after turning them back on * so we'll send a CMD_START_x to be sure it's listening again */ if (state==1) { if (sc->atuwi_mode==AD_HOC_MODE) { err = atuwi_start_ibss(sc); if (err) return err; } } printf("atuwi: radio turned %s\n", state ? "on" : "off"); sc->atuwi_radio_on=state; } return 0; } Static int atuwi_initial_config(struct atuwi_softc *sc) { int err; u_int8_t rates[4] = {0x82,0x84,0x8B,0x96}; struct atuwi_cmd_card_config CmdConfig = {CMD_STARTUP,0x00,sizeof(CmdConfig)-4}; CmdConfig.Channel=10; CmdConfig.AutoRateFallback=1; memcpy(CmdConfig.BasicRateSet,rates,4); CmdConfig.ShortRetryLimit=16; /* CmdConfig.RTS_Threshold=536; CmdConfig.FragThreshold=1536; */ CmdConfig.RTS_Threshold=1536; CmdConfig.FragThreshold=1536; CmdConfig.PromiscuousMode=0; /* Doesn't seem to work, so set to 0 */ CmdConfig.ExcludeUnencrypted=0; CmdConfig.EncryptionType=0; CmdConfig.PrivacyInvoked=0; /* Setting the SSID here doesn't seem to work, so we don't */ memset(CmdConfig.SSID,0,sizeof(CmdConfig.SSID)); CmdConfig.SSID_Len=0; CmdConfig.WEP_DefaultKeyID=0; memset(CmdConfig.WEP_DefaultKey,0,sizeof(CmdConfig.WEP_DefaultKey)); CmdConfig.ShortPreamble=1; /* CmdConfig.BeaconPeriod=100; */ CmdConfig.BeaconPeriod=250; err = atuwi_send_command(sc, (u_int8_t *)&CmdConfig, sizeof(CmdConfig)); if (err) return err; err = atuwi_wait_completion(sc, CMD_STARTUP, NULL); if (err) return err; err = atuwi_switch_radio(sc, 1); if (err) return err; usbd_delay_ms(sc->atuwi_udev,200); /* preamble type = short */ err = atuwi_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT)); if (err) return err; printf("preamble set\n"); /* frag = 1536 */ err = atuwi_send_mib(sc, MIB_MAC__FRAG, NR(1536)); if (err) return err; printf("frag set\n"); /* rts = 1536 */ err = atuwi_send_mib(sc, MIB_MAC__RTS, NR(1536)); if (err) return err; printf("rts set\n"); /* auto rate fallback = 1 */ err = atuwi_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1)); if (err) return err; printf("set auto fallback\n"); /* power mode = full on, no power saving */ err = atuwi_send_mib(sc, MIB_MAC_MGMT__POWER_MODE, NR(POWER_MODE_ACTIVE)); if (err) return err; printf("set power mode\n"); printf("completed init\n"); return 0; } /* * Get the state of the DFU unit */ Static int8_t atuwi_get_dfu_state(struct atuwi_softc *sc) { u_int8_t State; if (atuwi_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &State)) return -1; return State; } /* * Get MAC opmode */ Static u_int8_t atuwi_get_opmode(struct atuwi_softc *sc) { u_int8_t Mode; if (atuwi_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001, 0x0000, 1, &Mode)) return -1; return Mode; } /* * Upload the internal firmware into the device */ Static int atuwi_upload_internal_firmware(struct atuwi_softc *sc) { int8_t State; int BytesLeft = 0; u_int8_t *Ptr = NULL; int BlockSize; int Block = 0; u_int8_t Status[6]; int err; /* * Just for your information, the Atmel's DFU descriptor looks like this: * * 07 size * 21 type * 01 capabilities : only firmware download, need reset after download * 13 05 detach timeout : max 1299ms between DFU_DETACH and reset * 00 04 max bytes of firmware per transaction : 1024 */ printf("atuwi: doing internal firmware blah blah\n"); /* Choose the right firmware for the device */ switch (sc->atuwi_radio) { case RadioRFMD: Ptr=atuwi_fw_rfmd_int; BytesLeft=sizeof(atuwi_fw_rfmd_int); printf("atuwi: internal RFMD firmware\n"); break; case RadioIntersil: Ptr=atuwi_fw_intersil_int; BytesLeft=sizeof(atuwi_fw_intersil_int); printf("atuwi: internal Intersil firmware\n"); break; } State=atuwi_get_dfu_state(sc); while (BytesLeft >= 0 && State > 0) { switch (State) { case DFUState_DnLoadSync: /* get DFU status */ err = atuwi_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6, Status); if (err) { printf("atuwi: dfu_getstatus failed!\n"); return err; } break; case DFUState_DFUIdle: case DFUState_DnLoadIdle: if (BytesLeft>=DFU_MaxBlockSize) BlockSize=DFU_MaxBlockSize; else BlockSize=BytesLeft; printf("atuwi: firmware block %d\n",Block); err = atuwi_usb_request(sc, DFU_DNLOAD, Block++, 0, BlockSize, Ptr); if (err) { printf("atuwi: dfu_dnload failed\n"); return err; } Ptr+=BlockSize; BytesLeft-=BlockSize; if (BlockSize==0) BytesLeft=-1; break; default: usbd_delay_ms(sc->atuwi_udev,10); } State=atuwi_get_dfu_state(sc); } printf("atuwi: -- End of firmware... waiting for manifestation\n"); if (State!=DFUState_ManifestSync) printf("atuwi: state != manifestsync... eek!\n"); err=atuwi_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, Status); if (err) { printf("atuwi: dfu_getstatus failed!\n"); return err; } printf("atuwi: sending remap\n"); err = atuwi_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL); if (err) { printf("atuwi: remap failed!\n"); return err; } /* After a lot of trying and measuring I found out the device needs * about 56 miliseconds after sending the remap command before * it's ready to communicate again. So we'll wait just a little bit * longer than that to be sure... */ usbd_delay_ms(sc->atuwi_udev,56+100); /* * For now we just return an error here since resetting the device * doesn't fully work (yet) * The user has to halfly unplug the device and plug it in again * (without power-cycling it) to get the firmware to boot */ printf("atuwi: --== please re-insert the adapter without power cycling it ==--\n"); return EIO; /* Reset the device to get the firmware to boot */ printf("atuwi: trying to reset device...\n"); err=atuwi_reset(sc); if (err) { printf("atuwi: reset failed...\n"); return err; } return 0; } Static int atuwi_upload_external_firmware(struct atuwi_softc *sc) { u_int8_t *Ptr = NULL; int BytesLeft = 0; int BlockSize; int Block = 0; u_int8_t Mode; int err; Mode=atuwi_get_opmode(sc); printf("atuwi: opmode: %d\n",Mode); if (Mode==MODE_NETCARD) { printf("atuwi: Don't need external upload\n"); return 0; } if (Mode!=MODE_NOFLASHNETCARD) { printf("atuwi: EEK! mode=%d\n",Mode); } switch (sc->atuwi_radio) { case RadioRFMD: Ptr = atuwi_fw_rfmd_ext; BytesLeft = sizeof(atuwi_fw_rfmd_ext); printf("atuwi: external RFMD firmware\n"); break; case RadioIntersil: Ptr = atuwi_fw_intersil_ext; BytesLeft = sizeof(atuwi_fw_intersil_ext); printf("atuwi: external Intersil firmware\n"); break; } while (BytesLeft) { if (BytesLeft > 1024) BlockSize=1024; else BlockSize=BytesLeft; printf("atuwi: block:%d size:%d\n",Block,BlockSize); err=atuwi_usb_request(sc,UT_WRITE_VENDOR_DEVICE,0x0e,0x0802,Block,BlockSize,Ptr); if (err) { printf("atuwi: could not load external firmware block\n"); return err; } Ptr+=BlockSize; Block++; BytesLeft-=BlockSize; } err=atuwi_usb_request(sc,UT_WRITE_VENDOR_DEVICE,0x0e,0x0802,Block,0,NULL); if (err) { printf("atuwi: could not load last zero-length firmware block\n"); return err; } return 0; } Static int atuwi_get_card_config(struct atuwi_softc *sc) { struct atuwi_rfmd_conf rfmd_conf; struct atuwi_intersil_conf intersil_conf; int err; switch (sc->atuwi_radio) { case RadioRFMD: printf("atuwi: trying to get rfmd config\n"); err = atuwi_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0a02, 0x0000, sizeof(rfmd_conf), (u_int8_t *)&rfmd_conf); if (err) { printf("atuwi: could not get rfmd config!\n"); return err; } memcpy(sc->atuwi_mac_addr,rfmd_conf.MACAddr,6); break; case RadioIntersil: printf("atuwi: trying to get intersil config\n"); err = atuwi_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0902, 0x0000, sizeof(intersil_conf), (u_int8_t *)&intersil_conf); if (err) { printf("atuwi: could not get intersil config!\n"); return err; } memcpy(sc->atuwi_mac_addr,intersil_conf.MACAddr,6); break; } return 0; } /* * Probe for an AT76c503 chip. */ USB_MATCH(atuwi) { USB_MATCH_START(atuwi, uaa); struct atuwi_type *t; if (!uaa->iface) return(UMATCH_NONE); t = atuwi_devs; while(t->atuwi_vid) { if (uaa->vendor == t->atuwi_vid && uaa->product == t->atuwi_did) { return(UMATCH_VENDOR_PRODUCT); } t++; } return(UMATCH_NONE); } /* * Attach the interface. Allocate softc structures, do * setup and ethernet/BPF attach. */ USB_ATTACH(atuwi) { USB_ATTACH_START(atuwi, sc, uaa); char devinfo[1024]; struct ifnet *ifp; usbd_status err; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; struct atuwi_type *t; struct atuwi_fw fw; bzero(sc, sizeof(struct atuwi_softc)); sc->atuwi_iface = uaa->iface; sc->atuwi_udev = uaa->device; sc->atuwi_unit = device_get_unit(self); id = usbd_get_interface_descriptor(uaa->iface); usbd_devinfo(uaa->device, 0, devinfo); device_set_desc_copy(self, devinfo); printf("%s: %s\n", USBDEVNAME(self), devinfo); /* * look up the radio_type for the device * basically does the same as USB_MATCH */ t = atuwi_devs; while(t->atuwi_vid) { if (uaa->vendor == t->atuwi_vid && uaa->product == t->atuwi_did) { sc->atuwi_radio = t->atuwi_radio; } t++; } /* * Check in the interface descriptor if we're in DFU mode * If we're in DFU mode, we upload the external firmware * If we're not, the PC must have rebooted without power-cycling * the device.. I've tried this out, a reboot only requeres the * external firmware to be reloaded :) */ if (id->bInterfaceClass == 0xfe && id->bInterfaceSubClass == 0x01) { printf("atuwi: we're in DFU mode!\n"); /* upload internal firmware */ err=atuwi_upload_internal_firmware(sc); if (err) { USB_ATTACH_ERROR_RETURN; } } /* upload external firmware */ err = atuwi_upload_external_firmware(sc); if (err) { USB_ATTACH_ERROR_RETURN; } /* DEBUG : try to get firmware version */ err=atuwi_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0, (u_int8_t *)&fw); if (!err) { printf("atuwi: firmware: maj:%d min:%d patch:%d build:%d\n", fw.major,fw.minor,fw.patch,fw.build); } else { printf("atuwi: get firmware version failed\n"); } /* Find endpoints. */ for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(uaa->iface, i); if (!ed) { printf("atuwi%d: couldn't get ep %d\n", sc->atuwi_unit, i); USB_ATTACH_ERROR_RETURN; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->atuwi_ed[ATUWI_ENDPT_RX] = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->atuwi_ed[ATUWI_ENDPT_TX] = ed->bEndpointAddress; } } printf("atuwi: rx endp:%d\n",sc->atuwi_ed[ATUWI_ENDPT_RX]); printf("atuwi: tx endp:%d\n",sc->atuwi_ed[ATUWI_ENDPT_TX]); mtx_init(&sc->atuwi_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); ATUWI_LOCK(sc); /* read device config & get MAC address */ err = atuwi_get_card_config(sc); if (err) { printf("atuwi: could not get card config!\n"); ATUWI_UNLOCK(sc); mtx_destroy(&sc->atuwi_mtx); USB_ATTACH_ERROR_RETURN; } /* Set MAC address */ if (atuwi_send_mib(sc,MIB_MAC_ADDR__ADDR,sc->atuwi_mac_addr)) { printf("atuwi: set mac addr failed!\n"); USB_ATTACH_ERROR_RETURN; } printf("atuwi: set mac addr\n"); /* Show the world our MAC address */ printf("atuwi%d: Ethernet address: %6D\n", sc->atuwi_unit, sc->atuwi_mac_addr, ":"); bcopy(sc->atuwi_mac_addr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); /* sc->arpcom.ac_enaddr[1]=0xa5; */ ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = sc->atuwi_unit; ifp->if_name = "atuwi"; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = atuwi_ioctl; ifp->if_output = ether_output; ifp->if_start = atuwi_start; ifp->if_watchdog = atuwi_watchdog; ifp->if_init = atuwi_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; sc->atuwi_ssidlen=strlen("vitsch-wlan"); bcopy("vitsch-wlan",sc->atuwi_ssid,sc->atuwi_ssidlen); sc->atuwi_channel=10; sc->atuwi_mode=NO_MODE_YET; atuwi_qdat.ifp = ifp; atuwi_qdat.if_rxstart = atuwi_rxstart; /* * Call MI attach routine. */ /* ether_ifattach(ifp, sc->atuwi_desc.atuwi_macaddr); */ ether_ifattach(ifp, sc->atuwi_mac_addr); usb_register_netisr(); sc->atuwi_dying = 0; /* Call atuwi_init once to get the adapter to start (in adhoc) */ printf("atuwi: trying atuwi_init\n"); atuwi_init(sc); ATUWI_UNLOCK(sc); USB_ATTACH_SUCCESS_RETURN; } Static int atuwi_detach(device_ptr_t dev) { struct atuwi_softc *sc; struct ifnet *ifp; sc = device_get_softc(dev); ATUWI_LOCK(sc); ifp = &sc->arpcom.ac_if; printf("atuwi: detach\n"); sc->atuwi_dying = 1; if (ifp != NULL) ether_ifdetach(ifp); if (sc->atuwi_ep[ATUWI_ENDPT_TX] != NULL) usbd_abort_pipe(sc->atuwi_ep[ATUWI_ENDPT_TX]); if (sc->atuwi_ep[ATUWI_ENDPT_RX] != NULL) usbd_abort_pipe(sc->atuwi_ep[ATUWI_ENDPT_RX]); ATUWI_UNLOCK(sc); mtx_destroy(&sc->atuwi_mtx); return(0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ Static int atuwi_newbuf(struct atuwi_softc *sc, struct atuwi_chain *c, struct mbuf *m) { struct mbuf *m_new = NULL; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("atuwi%d: no memory for rx list " "-- packet dropped!\n", sc->atuwi_unit); return(ENOBUFS); } MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { printf("atuwi%d: no memory for rx list " "-- packet dropped!\n", sc->atuwi_unit); m_freem(m_new); return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; } else { m_new = m; m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_new->m_data = m_new->m_ext.ext_buf; } c->atuwi_mbuf = m_new; return(0); } Static int atuwi_rx_list_init(struct atuwi_softc *sc) { struct atuwi_cdata *cd; struct atuwi_chain *c; int i; cd = &sc->atuwi_cdata; for (i = 0; i < ATUWI_RX_LIST_CNT; i++) { c = &cd->atuwi_rx_chain[i]; c->atuwi_sc = sc; c->atuwi_idx = i; if (atuwi_newbuf(sc, c, NULL) == ENOBUFS) return(ENOBUFS); if (c->atuwi_xfer == NULL) { c->atuwi_xfer = usbd_alloc_xfer(sc->atuwi_udev); if (c->atuwi_xfer == NULL) return(ENOBUFS); } c->atuwi_buf = malloc(ATUWI_BUFSZ, M_USBDEV, M_NOWAIT); if (c->atuwi_buf == NULL) return(ENOBUFS); printf("atuwi: rx list init\n"); } return(0); } Static int atuwi_tx_list_init(struct atuwi_softc *sc) { struct atuwi_cdata *cd; struct atuwi_chain *c; int i; printf("atuwi: tx_list_init\n"); cd = &sc->atuwi_cdata; for (i = 0; i < ATUWI_TX_LIST_CNT; i++) { c = &cd->atuwi_tx_chain[i]; c->atuwi_sc = sc; c->atuwi_idx = i; c->atuwi_mbuf = NULL; if (c->atuwi_xfer == NULL) { c->atuwi_xfer = usbd_alloc_xfer(sc->atuwi_udev); if (c->atuwi_xfer == NULL) return(ENOBUFS); } c->atuwi_buf = malloc(ATUWI_BUFSZ, M_USBDEV, M_NOWAIT); if (c->atuwi_buf == NULL) return(ENOBUFS); printf("atuwi: tx_list_init: oh jawel :)\n"); } return(0); } Static void atuwi_rxstart(struct ifnet *ifp) { struct atuwi_softc *sc; struct atuwi_chain *c; sc = ifp->if_softc; ATUWI_LOCK(sc); c = &sc->atuwi_cdata.atuwi_rx_chain[sc->atuwi_cdata.atuwi_rx_prod]; if (atuwi_newbuf(sc, c, NULL) == ENOBUFS) { ifp->if_ierrors++; return; } /* Setup new transfer. */ usbd_setup_xfer(c->atuwi_xfer, sc->atuwi_ep[ATUWI_ENDPT_RX], c, mtod(c->atuwi_mbuf, char *), ATUWI_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atuwi_rxeof); usbd_transfer(c->atuwi_xfer); ATUWI_UNLOCK(sc); return; } /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ Static void atuwi_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct atuwi_softc *sc; struct atuwi_chain *c; struct mbuf *m; struct ifnet *ifp; int total_len = 0; struct atuwi_rxpkt *Pkt; int offset; u_int8_t *Ptr; struct tlv *TLV; u_int8_t *End; u_int8_t Tmp; c = priv; sc = c->atuwi_sc; ATUWI_LOCK(sc); ifp = &sc->arpcom.ac_if; if (!(ifp->if_flags & IFF_RUNNING)) { ATUWI_UNLOCK(sc); return; } if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { ATUWI_UNLOCK(sc); return; } if (status == USBD_IOERROR) { printf("atuwi: rx: EEK! lost device?\n"); ATUWI_UNLOCK(sc); return; } if (usbd_ratecheck(&sc->atuwi_rx_notice)) printf("atuwi%d: usb error on rx: %s\n", sc->atuwi_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->atuwi_ep[ATUWI_ENDPT_RX]); goto done; } m = c->atuwi_mbuf; usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); if (total_len <= 1) goto done; Pkt=mtod(m,struct atuwi_rxpkt *); /* Is it a managment packet? */ if ((Pkt->WiHeader.frame_ctl & 0x0c) == 0x00) { /* Show beacon src MAC & signal strength */ printf("atuwi: mgmt mac=%6D signal=%d\n", Pkt->WiHeader.addr2,":", Pkt->AtHeader.rssi); /* Show beacon SSID string */ Ptr=(u_int8_t *)Pkt->WiHeader.addr4+12; End=Ptr+Pkt->AtHeader.wlength-24-12-4; TLV=(struct tlv *)Ptr; while (Ptrlength>0) { if (TLV->type==0x00) { /* SSID */ Tmp=TLV->value[TLV->length]; TLV->value[TLV->length]=0; printf("atuwi: ssid=%s\n",TLV->value); TLV->value[TLV->length]=Tmp; } Ptr+=2+TLV->length; TLV=(struct tlv *)Ptr; } goto done; } /* Everything but data packets we just ignore */ if ((Pkt->WiHeader.frame_ctl & 0x0c) != 0x08) goto done; /* Woohaa! It's an ethernet packet! */ printf("atuwi: received a packet! rx-rate:%0d\n", Pkt->AtHeader.rx_rate); /* printf("atuwi: rx f:%02x rssi:%02x q:%02x nl:%02x time:%02x %02x %02x %02x\n", Pkt->AtHeader.fragmentation, Pkt->AtHeader.rssi, Pkt->AtHeader.link_quality, Pkt->AtHeader.noise_level, Pkt->AtHeader.rx_time[0], Pkt->AtHeader.rx_time[1], Pkt->AtHeader.rx_time[2], Pkt->AtHeader.rx_time[3]); */ /* Copy src & dest mac to the right place */ memcpy(Pkt->Packet-14,Pkt->WiHeader.addr1,6); memcpy(Pkt->Packet-8,Pkt->WiHeader.addr2,6); total_len=Pkt->AtHeader.wlength-24-12+14; /* Do some sanity checking... */ if (total_len < sizeof(struct ether_header)) { printf("atuwi: Packet too small?? (size:%d)\n",total_len); ifp->if_ierrors++; goto done; } if (total_len > 1514) { printf("atuwi: AAARRRGGGHHH!! Invalid packet size? (%d)\n",total_len); ifp->if_ierrors++; goto done; } ifp->if_ipackets++; m->m_pkthdr.rcvif = (struct ifnet *)&atuwi_qdat; m->m_pkthdr.len = m->m_len = total_len; /* Adjust mbuf for headers */ offset=sizeof(struct at76c503_rx_buffer)+ sizeof(struct wi_80211_hdr)-12; m->m_pkthdr.len = m->m_len = total_len+offset; m_adj(m,offset); /* Put the packet on the special USB input queue. */ usb_ether_input(m); ATUWI_UNLOCK(sc); return; done: /* Setup new transfer. */ usbd_setup_xfer(c->atuwi_xfer, sc->atuwi_ep[ATUWI_ENDPT_RX], c, mtod(c->atuwi_mbuf, char *), ATUWI_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atuwi_rxeof); usbd_transfer(c->atuwi_xfer); ATUWI_UNLOCK(sc); return; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ Static void atuwi_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) { struct atuwi_softc *sc; struct atuwi_chain *c; struct ifnet *ifp; usbd_status err; c = priv; sc = c->atuwi_sc; ATUWI_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; if (status != USBD_NORMAL_COMPLETION) { if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { ATUWI_UNLOCK(sc); return; } printf("atuwi%d: usb error on tx: %s\n", sc->atuwi_unit, usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall(sc->atuwi_ep[ATUWI_ENDPT_TX]); ATUWI_UNLOCK(sc); return; } usbd_get_xfer_status(c->atuwi_xfer, NULL, NULL, NULL, &err); if (c->atuwi_mbuf != NULL) { c->atuwi_mbuf->m_pkthdr.rcvif = ifp; usb_tx_done(c->atuwi_mbuf); c->atuwi_mbuf = NULL; } if (err) ifp->if_oerrors++; else ifp->if_opackets++; ATUWI_UNLOCK(sc); return; } Static int atuwi_encap(struct atuwi_softc *sc, struct mbuf *m, int idx) { int total_len; struct atuwi_chain *c; usbd_status err; struct atuwi_txpkt *Pkt; c = &sc->atuwi_cdata.atuwi_tx_chain[idx]; /* * Copy the mbuf data into a contiguous buffer, leaving * enough room for the atmel & 802.11 headers */ total_len = m->m_pkthdr.len; m_copydata(m, 0, m->m_pkthdr.len, c->atuwi_buf + sizeof(struct at76c503_tx_buffer)+sizeof(struct wi_80211_hdr) - 2 * ETHER_ADDR_LEN); c->atuwi_mbuf = m; total_len += sizeof(struct wi_80211_hdr)-12; Pkt=(struct atuwi_txpkt *)c->atuwi_buf; Pkt->AtHeader.wlength=total_len; Pkt->AtHeader.tx_rate=4; /* auto */ Pkt->AtHeader.padding=0; memset(Pkt->AtHeader.reserved,0x00,4); Pkt->WiHeader.frame_ctl=0x08; /* data packet */ Pkt->WiHeader.dur_id=0x8000; /* ? */ memcpy(Pkt->WiHeader.addr1,Pkt->Packet-12,6); /* dest */ memcpy(Pkt->WiHeader.addr2,Pkt->Packet-6,6); /* src */ memcpy(Pkt->WiHeader.addr3,sc->atuwi_bssid,6); /* bssid */ memset(Pkt->WiHeader.addr4,0x00,6); Pkt->WiHeader.seq_ctl=0; total_len+=sizeof(struct at76c503_tx_buffer); usbd_setup_xfer(c->atuwi_xfer, sc->atuwi_ep[ATUWI_ENDPT_TX], c, c->atuwi_buf, total_len, 0, 10000, atuwi_txeof); /* Let's get this thing into the air! */ err = usbd_transfer(c->atuwi_xfer); if (err != USBD_IN_PROGRESS) { atuwi_stop(sc); return(EIO); } sc->atuwi_cdata.atuwi_tx_cnt++; return(0); } Static void atuwi_start(struct ifnet *ifp) { struct atuwi_softc *sc; struct mbuf *m_head = NULL; sc = ifp->if_softc; ATUWI_LOCK(sc); if (ifp->if_flags & IFF_OACTIVE) { ATUWI_UNLOCK(sc); return; } IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) { ATUWI_UNLOCK(sc); return; } if (atuwi_encap(sc, m_head, 0)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; ATUWI_UNLOCK(sc); return; } /* * If there's a BPF listener, bounce a copy of this frame * to him. */ BPF_MTAP(ifp, m_head); ifp->if_flags |= IFF_OACTIVE; /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; ATUWI_UNLOCK(sc); return; } Static void atuwi_init(void *xsc) { struct atuwi_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; struct atuwi_chain *c; usbd_status err; int i; ATUWI_LOCK(sc); printf("atuwi: init\n"); if (ifp->if_flags & IFF_RUNNING) { ATUWI_UNLOCK(sc); return; } /* Do initial setup */ err = atuwi_initial_config(sc); if (err) { printf("atuwi: initial config failed!\n"); ATUWI_UNLOCK(sc); return; } printf("atuwi: initialised tranceiver\n"); /* Set tranceiver in IBSS mode */ if (atuwi_start_ibss(sc)) { printf("atuwi: start ibss failed!\n"); } printf("atuwi: start ibss\n"); /* sc->atuwi_rxfilt = ATUWI_RXFILT_UNICAST|ATUWI_RXFILT_BROADCAST; */ /* If we want promiscuous mode, set the allframes bit. */ /* if (ifp->if_flags & IFF_PROMISC) sc->atuwi_rxfilt |= ATUWI_RXFILT_PROMISC; */ /* Init TX ring. */ if (atuwi_tx_list_init(sc) == ENOBUFS) { printf("atuwi%d: tx list init failed\n", sc->atuwi_unit); ATUWI_UNLOCK(sc); return; } /* Init RX ring. */ if (atuwi_rx_list_init(sc) == ENOBUFS) { printf("atuwi%d: rx list init failed\n", sc->atuwi_unit); ATUWI_UNLOCK(sc); return; } /* Load the multicast filter. */ /*atuwi_setmulti(sc); */ /* Open RX and TX pipes. */ err = usbd_open_pipe(sc->atuwi_iface, sc->atuwi_ed[ATUWI_ENDPT_RX], USBD_EXCLUSIVE_USE, &sc->atuwi_ep[ATUWI_ENDPT_RX]); if (err) { printf("atuwi%d: open rx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); ATUWI_UNLOCK(sc); return; } err = usbd_open_pipe(sc->atuwi_iface, sc->atuwi_ed[ATUWI_ENDPT_TX], USBD_EXCLUSIVE_USE, &sc->atuwi_ep[ATUWI_ENDPT_TX]); if (err) { printf("atuwi%d: open tx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); ATUWI_UNLOCK(sc); return; } /* Start up the receive pipe. */ for (i = 0; i < ATUWI_RX_LIST_CNT; i++) { c = &sc->atuwi_cdata.atuwi_rx_chain[i]; usbd_setup_xfer(c->atuwi_xfer, sc->atuwi_ep[ATUWI_ENDPT_RX], c, mtod(c->atuwi_mbuf, char *), ATUWI_BUFSZ, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atuwi_rxeof); usbd_transfer(c->atuwi_xfer); } ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; ATUWI_UNLOCK(sc); return; } Static int atuwi_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct atuwi_softc *sc = ifp->if_softc; int err = 0; struct ifreq *ifr; struct ieee80211req *ireq; /* struct wi_req wreq; */ struct thread *td = curthread; int change; /* DEBUG */ u_int8_t tmp[32]; ATUWI_LOCK(sc); ifr = (struct ifreq *)data; ireq = (struct ieee80211req *)data; change=ifp->if_flags ^ sc->atuwi_if_flags; switch(command) { case SIOCSIFFLAGS: err = suser(td); if (err) break; if (change & IFF_UP) { if (ifp->if_flags & IFF_UP) { err = atuwi_switch_radio(sc,1); break; } else { err = atuwi_switch_radio(sc,0); break; } } /* if (ifp->if_flags & IFF_UP) { \* * Do we need anything from this bunch of spaghetti? if (ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->atuwi_if_flags & IFF_PROMISC)) { sc->atuwi_rxfilt |= ATUWI_RXFILT_PROMISC; atuwi_setword(sc, ATUWI_CMD_SET_PKT_FILTER, sc->atuwi_rxfilt); } else if (ifp->if_flags & IFF_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->atuwi_if_flags & IFF_PROMISC) { sc->atuwi_rxfilt &= ~ATUWI_RXFILT_PROMISC; atuwi_setword(sc, ATUWI_CMD_SET_PKT_FILTER, sc->atuwi_rxfilt); } else if (!(ifp->if_flags & IFF_RUNNING)) atuwi_init(sc); *\ printf("atuwi: ioctl calling atuwi_init()\n"); atuwi_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) atuwi_stop(sc); } */ err = 0; break; case SIOCADDMULTI: err=0; printf("atuwi: ioctl: add multi\n"); break; case SIOCDELMULTI: /*atuwi_setmulti(sc);*/ err = 0; printf("atuwi: ioctl: del multi\n"); break; case SIOCG80211: switch(ireq->i_type) { case IEEE80211_IOC_SSID: err=copyout(sc->atuwi_ssid,ireq->i_data,sc->atuwi_ssidlen); ireq->i_len=sc->atuwi_ssidlen; break; case IEEE80211_IOC_NUMSSIDS: ireq->i_val = 1; break; case IEEE80211_IOC_CHANNEL: ireq->i_val=sc->atuwi_channel; /* DEBUG */ err=atuwi_get_mib(sc,MIB_MAC_MGMT__CURRENT_BSSID,tmp); if (err) break; printf("atuwi: DEBUG: current BSSID=%6D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_MGMT__BEACON_PERIOD,tmp); if (err) break; printf("atuwi: DEBUG: beacon period=%2D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_WEP__PRIVACY_INVOKED,tmp); if (err) break; printf("atuwi: DEBUG: privacy invoked=%1D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_WEP__ICV_ERROR_COUNT,tmp); if (err) break; printf("atuwi: DEBUG: icv error count=%4D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_WEP__EXCLUDED_COUNT,tmp); if (err) break; printf("atuwi: DEBUG: wep excluded count=%4D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_MGMT__POWER_MODE,tmp); if (err) break; printf("atuwi: DEBUG: power mode=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_PHY__CHANNEL,tmp); if (err) break; printf("autwi: DEBUG: channel=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_PHY__REG_DOMAIN,tmp); if (err) break; printf("autwi: DEBUG: reg domain=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_LOCAL__SSID_SIZE,tmp); if (err) break; printf("autwi: DEBUG: ssid size=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_LOCAL__BEACON_ENABLE,tmp); if (err) break; printf("autwi: DEBUG: beacon enable=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_LOCAL__AUTO_RATE_FALLBACK,tmp); if (err) break; printf("autwi: DEBUG: auto rate fallback=%d\n",tmp[0]); err=atuwi_get_mib(sc,MIB_MAC_ADDR__ADDR,tmp); if (err) break; printf("autwi: DEBUG: mac addr=%6D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC__DESIRED_SSID,tmp); if (err) break; printf("autwi: DEBUG: desired ssid=%32D\n",tmp,":"); err=atuwi_get_mib(sc,MIB_MAC_MGMT__CURRENT_ESSID,tmp); if (err) break; printf("atuwi: DEBUG: current ESSID=%32D\n",tmp,":"); break; default: printf("atuwi: ioctl: unknown 80211: %04x %d\n",ireq->i_type,ireq->i_type); err = EINVAL; } break; case SIOCS80211: err = suser(td); if (err) break; switch(ireq->i_type) { case IEEE80211_IOC_SSID: if (ireq->i_len<0 || ireq->i_len>32) { err=EINVAL; break; } err=copyin(ireq->i_data,sc->atuwi_ssid,ireq->i_len); if (err) break; sc->atuwi_ssidlen=ireq->i_len; err=atuwi_start_ibss(sc); if (err) { printf("atuwi: could not set ssid??\n"); break; } break; case IEEE80211_IOC_CHANNEL: if (ireq->i_val<0 || ireq->i_val>14) { err=EINVAL; break; } sc->atuwi_channel=ireq->i_val; err=atuwi_start_ibss(sc); if (err) { printf("atuwi: could not set channel??\n"); break; } break; } break; case SIOCGWAVELAN: printf("atuwi: ioctl: get wavelan\n"); err = ether_ioctl(ifp, command, data); break; /* err = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); if (err) break; printf("atuwi: lal\n"); if (wreq.wi_len > WI_MAX_DATALEN) { err = EINVAL; break; } printf("atuwi: ioctl: wi_type=%04x %d\n\n",wreq.wi_type,wreq.wi_type); err=EINVAL; break; */ default: printf("atuwi: ioctl: default\n"); err = ether_ioctl(ifp, command, data); break; } sc->atuwi_if_flags = ifp->if_flags; ATUWI_UNLOCK(sc); return(err); } Static void atuwi_watchdog(struct ifnet *ifp) { struct atuwi_softc *sc; struct atuwi_chain *c; usbd_status stat; sc = ifp->if_softc; ATUWI_LOCK(sc); ifp->if_oerrors++; printf("atuwi%d: watchdog timeout\n", sc->atuwi_unit); c = &sc->atuwi_cdata.atuwi_tx_chain[0]; usbd_get_xfer_status(c->atuwi_xfer, NULL, NULL, NULL, &stat); atuwi_txeof(c->atuwi_xfer, c, stat); if (ifp->if_snd.ifq_head != NULL) atuwi_start(ifp); ATUWI_UNLOCK(sc); return; } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ Static void atuwi_stop(struct atuwi_softc *sc) { usbd_status err; struct ifnet *ifp; int i; ATUWI_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; /* Stop transfers. */ if (sc->atuwi_ep[ATUWI_ENDPT_RX] != NULL) { err = usbd_abort_pipe(sc->atuwi_ep[ATUWI_ENDPT_RX]); if (err) { printf("atuwi%d: abort rx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); } err = usbd_close_pipe(sc->atuwi_ep[ATUWI_ENDPT_RX]); if (err) { printf("atuwi%d: close rx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); } sc->atuwi_ep[ATUWI_ENDPT_RX] = NULL; } if (sc->atuwi_ep[ATUWI_ENDPT_TX] != NULL) { err = usbd_abort_pipe(sc->atuwi_ep[ATUWI_ENDPT_TX]); if (err) { printf("atuwi%d: abort tx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); } err = usbd_close_pipe(sc->atuwi_ep[ATUWI_ENDPT_TX]); if (err) { printf("atuwi%d: close tx pipe failed: %s\n", sc->atuwi_unit, usbd_errstr(err)); } sc->atuwi_ep[ATUWI_ENDPT_TX] = NULL; } /* Free RX resources. */ for (i = 0; i < ATUWI_RX_LIST_CNT; i++) { if (sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_buf != NULL) { free(sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_buf, M_USBDEV); sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_buf = NULL; } if (sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_mbuf != NULL) { m_freem(sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_mbuf); sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_mbuf = NULL; } if (sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_xfer != NULL) { usbd_free_xfer(sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_xfer); sc->atuwi_cdata.atuwi_rx_chain[i].atuwi_xfer = NULL; } } /* Free TX resources. */ for (i = 0; i < ATUWI_TX_LIST_CNT; i++) { if (sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_buf != NULL) { free(sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_buf, M_USBDEV); sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_buf = NULL; } if (sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_mbuf != NULL) { m_freem(sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_mbuf); sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_mbuf = NULL; } if (sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_xfer != NULL) { usbd_free_xfer(sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_xfer); sc->atuwi_cdata.atuwi_tx_chain[i].atuwi_xfer = NULL; } } ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ATUWI_UNLOCK(sc); return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ Static void atuwi_shutdown(device_ptr_t dev) { struct atuwi_softc *sc; sc = device_get_softc(dev); atuwi_stop(sc); return; }