Annotation of sys/dev/usb/if_atu.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_atu.c,v 1.86 2007/07/18 18:10:31 damien Exp $ */
! 2: /*
! 3: * Copyright (c) 2003, 2004
! 4: * Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: * 3. All advertising materials mentioning features or use of this software
! 15: * must display the following acknowledgement:
! 16: * This product includes software developed by Daan Vreeken.
! 17: * 4. Neither the name of the author nor the names of any co-contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL Daan Vreeken OR THE VOICES IN HIS HEAD
! 25: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 31: * THE POSSIBILITY OF SUCH DAMAGE.
! 32: */
! 33:
! 34: /*
! 35: * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a USB WLAN driver
! 36: * version 0.5 - 2004-08-03
! 37: *
! 38: * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net>
! 39: * http://vitsch.net/bsd/atuwi
! 40: *
! 41: * Contributed to by :
! 42: * Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul,
! 43: * Suihong Liang, Arjan van Leeuwen, Stuart Walsh
! 44: *
! 45: * Ported to OpenBSD by Theo de Raadt and David Gwynne.
! 46: */
! 47:
! 48: #include "bpfilter.h"
! 49:
! 50: #include <sys/param.h>
! 51: #include <sys/sockio.h>
! 52: #include <sys/mbuf.h>
! 53: #include <sys/kernel.h>
! 54: #include <sys/socket.h>
! 55: #include <sys/systm.h>
! 56: #include <sys/malloc.h>
! 57: #include <sys/kthread.h>
! 58: #include <sys/queue.h>
! 59: #include <sys/device.h>
! 60:
! 61: #include <machine/bus.h>
! 62:
! 63: #include <dev/usb/usb.h>
! 64: #include <dev/usb/usbdi.h>
! 65: #include <dev/usb/usbdi_util.h>
! 66: #include <dev/usb/usbdivar.h>
! 67:
! 68: #include <dev/usb/usbdevs.h>
! 69:
! 70: #if NBPFILTER > 0
! 71: #include <net/bpf.h>
! 72: #endif
! 73:
! 74: #include <net/if.h>
! 75: #include <net/if_dl.h>
! 76: #include <net/if_media.h>
! 77:
! 78: #ifdef INET
! 79: #include <netinet/in.h>
! 80: #include <netinet/if_ether.h>
! 81: #endif
! 82:
! 83: #include <net80211/ieee80211_var.h>
! 84: #include <net80211/ieee80211_radiotap.h>
! 85:
! 86: #ifdef USB_DEBUG
! 87: #define ATU_DEBUG
! 88: #endif
! 89:
! 90: #include <dev/usb/if_atureg.h>
! 91:
! 92: #ifdef ATU_DEBUG
! 93: #define DPRINTF(x) do { if (atudebug) printf x; } while (0)
! 94: #define DPRINTFN(n,x) do { if (atudebug>(n)) printf x; } while (0)
! 95: int atudebug = 1;
! 96: #else
! 97: #define DPRINTF(x)
! 98: #define DPRINTFN(n,x)
! 99: #endif
! 100:
! 101: int atu_match(struct device *, void *, void *);
! 102: void atu_attach(struct device *, struct device *, void *);
! 103: int atu_detach(struct device *, int);
! 104: int atu_activate(struct device *, enum devact);
! 105:
! 106: struct cfdriver atu_cd = {
! 107: NULL, "atu", DV_IFNET
! 108: };
! 109:
! 110: const struct cfattach atu_ca = {
! 111: sizeof(struct atu_softc),
! 112: atu_match,
! 113: atu_attach,
! 114: atu_detach,
! 115: atu_activate,
! 116: };
! 117:
! 118: /*
! 119: * Various supported device vendors/products/radio type.
! 120: */
! 121: struct atu_type atu_devs[] = {
! 122: { USB_VENDOR_3COM, USB_PRODUCT_3COM_3CRSHEW696,
! 123: RadioRFMD, ATU_NO_QUIRK },
! 124: { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_BWU613,
! 125: RadioRFMD, ATU_NO_QUIRK },
! 126: { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_2664W,
! 127: AT76C503_rfmd_acc, ATU_NO_QUIRK },
! 128: { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300,
! 129: RadioIntersil, ATU_NO_QUIRK },
! 130: { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL400,
! 131: RadioRFMD, ATU_NO_QUIRK },
! 132: { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_802UAT1,
! 133: RadioRFMD, ATU_NO_QUIRK },
! 134: { USB_VENDOR_ADDTRON, USB_PRODUCT_ADDTRON_AWU120,
! 135: RadioIntersil, ATU_NO_QUIRK },
! 136: { USB_VENDOR_AINCOMM, USB_PRODUCT_AINCOMM_AWU2000B,
! 137: RadioRFMD2958, ATU_NO_QUIRK },
! 138: { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_VOYAGER1010,
! 139: RadioIntersil, ATU_NO_QUIRK },
! 140: { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013I,
! 141: RadioIntersil, ATU_NO_QUIRK },
! 142: { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013,
! 143: RadioRFMD, ATU_NO_QUIRK },
! 144: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I1,
! 145: RadioIntersil, ATU_NO_QUIRK },
! 146: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I2,
! 147: AT76C503_i3863, ATU_NO_QUIRK },
! 148: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503RFMD,
! 149: RadioRFMD, ATU_NO_QUIRK },
! 150: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD,
! 151: AT76C505_rfmd, ATU_NO_QUIRK },
! 152: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD2958,
! 153: RadioRFMD2958, ATU_NO_QUIRK },
! 154: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505A, /* SMC2662 V.4 */
! 155: RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY },
! 156: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505AS, /* quirk? */
! 157: RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY },
! 158: { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_WN210,
! 159: RadioRFMD, ATU_NO_QUIRK },
! 160: { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D6050,
! 161: RadioRFMD, ATU_NO_QUIRK },
! 162: { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C11U,
! 163: RadioIntersil, ATU_NO_QUIRK },
! 164: { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_WL210,
! 165: RadioIntersil, ATU_NO_QUIRK },
! 166: { USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQWLAN,
! 167: RadioRFMD, ATU_NO_QUIRK },
! 168: { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_STICK,
! 169: RadioRFMD2958, ATU_NO_QUIRK },
! 170: { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CHUSB611G,
! 171: RadioRFMD2958, ATU_NO_QUIRK },
! 172: { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL200U,
! 173: RadioRFMD, ATU_NO_QUIRK },
! 174: { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL240U,
! 175: RadioRFMD2958, ATU_NO_QUIRK },
! 176: { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_XH1153,
! 177: RadioRFMD, ATU_NO_QUIRK },
! 178: { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120E,
! 179: RadioRFMD, ATU_NO_QUIRK },
! 180: { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWLBM101,
! 181: RadioRFMD, ATU_NO_QUIRK },
! 182: { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_WLAN, /* quirk? */
! 183: RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY },
! 184: { USB_VENDOR_HP, USB_PRODUCT_HP_HN210W,
! 185: RadioIntersil, ATU_NO_QUIRK },
! 186: { USB_VENDOR_INTEL, USB_PRODUCT_INTEL_AP310,
! 187: RadioIntersil, ATU_NO_QUIRK },
! 188: { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11A,
! 189: RadioIntersil, ATU_NO_QUIRK },
! 190: { USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_2662WAR,
! 191: RadioRFMD, ATU_NO_QUIRK },
! 192: { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11,
! 193: RadioIntersil, ATU_NO_QUIRK },
! 194: { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_WUSB11,
! 195: RadioRFMD, ATU_NO_QUIRK },
! 196: { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_NWU11B,
! 197: RadioRFMD, ATU_NO_QUIRK },
! 198: { USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V28,
! 199: RadioRFMD2958, ATU_NO_QUIRK },
! 200: { USB_VENDOR_MSI, USB_PRODUCT_MSI_WLAN,
! 201: RadioRFMD2958, ATU_NO_QUIRK },
! 202: { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101,
! 203: RadioIntersil, ATU_NO_QUIRK },
! 204: { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101B,
! 205: RadioRFMD, ATU_NO_QUIRK },
! 206: { USB_VENDOR_OQO, USB_PRODUCT_OQO_WIFI01,
! 207: RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY },
! 208: { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US11S,
! 209: RadioRFMD, ATU_NO_QUIRK },
! 210: { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_SWL2100W,
! 211: AT76C503_i3863, ATU_NO_QUIRK },
! 212: { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WLL013,
! 213: RadioRFMD, ATU_NO_QUIRK },
! 214: { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV1,
! 215: RadioIntersil, ATU_NO_QUIRK },
! 216: { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV2,
! 217: AT76C503_rfmd_acc, ATU_NO_QUIRK },
! 218: { USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_U300C,
! 219: RadioIntersil, ATU_NO_QUIRK },
! 220: { USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750,
! 221: RadioIntersil, ATU_NO_QUIRK },
! 222: };
! 223:
! 224: struct atu_radfirm {
! 225: enum atu_radio_type atur_type;
! 226: char *atur_internal;
! 227: char *atur_external;
! 228: u_int8_t max_rssi;
! 229: } atu_radfirm[] = {
! 230: { RadioRFMD, "atu-rfmd-int", "atu-rfmd-ext", 0 },
! 231: { RadioRFMD2958, "atu-rfmd2958-int", "atu-rfmd2958-ext", 81 },
! 232: { RadioRFMD2958_SMC, "atu-rfmd2958smc-int", "atu-rfmd2958smc-ext", 0 },
! 233: { RadioIntersil, "atu-intersil-int", "atu-intersil-ext", 0 },
! 234: {
! 235: AT76C503_i3863,
! 236: "atu-at76c503-i3863-int",
! 237: "atu-at76c503-i3863-ext",
! 238: 0
! 239: },
! 240: {
! 241: AT76C503_rfmd_acc,
! 242: "atu-at76c503-rfmd-acc-int",
! 243: "atu-at76c503-rfmd-acc-ext",
! 244: 0
! 245: },
! 246: {
! 247: AT76C505_rfmd,
! 248: "atu-at76c505-rfmd-int",
! 249: "atu-at76c505-rfmd-ext",
! 250: 0
! 251: }
! 252: };
! 253:
! 254: int atu_newbuf(struct atu_softc *, struct atu_chain *, struct mbuf *);
! 255: void atu_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 256: void atu_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 257: void atu_start(struct ifnet *);
! 258: int atu_ioctl(struct ifnet *, u_long, caddr_t);
! 259: int atu_init(struct ifnet *);
! 260: void atu_stop(struct ifnet *, int);
! 261: void atu_watchdog(struct ifnet *);
! 262: usbd_status atu_usb_request(struct atu_softc *sc, u_int8_t type,
! 263: u_int8_t request, u_int16_t value, u_int16_t index,
! 264: u_int16_t length, u_int8_t *data);
! 265: int atu_send_command(struct atu_softc *sc, u_int8_t *command, int size);
! 266: int atu_get_cmd_status(struct atu_softc *sc, u_int8_t cmd,
! 267: u_int8_t *status);
! 268: int atu_wait_completion(struct atu_softc *sc, u_int8_t cmd,
! 269: u_int8_t *status);
! 270: int atu_send_mib(struct atu_softc *sc, u_int8_t type,
! 271: u_int8_t size, u_int8_t index, void *data);
! 272: int atu_get_mib(struct atu_softc *sc, u_int8_t type,
! 273: u_int8_t size, u_int8_t index, u_int8_t *buf);
! 274: #if 0
! 275: int atu_start_ibss(struct atu_softc *sc);
! 276: #endif
! 277: int atu_start_scan(struct atu_softc *sc);
! 278: int atu_switch_radio(struct atu_softc *sc, int state);
! 279: int atu_initial_config(struct atu_softc *sc);
! 280: int atu_join(struct atu_softc *sc, struct ieee80211_node *node);
! 281: int8_t atu_get_dfu_state(struct atu_softc *sc);
! 282: u_int8_t atu_get_opmode(struct atu_softc *sc, u_int8_t *mode);
! 283: void atu_internal_firmware(void *);
! 284: void atu_external_firmware(void *);
! 285: int atu_get_card_config(struct atu_softc *sc);
! 286: int atu_media_change(struct ifnet *ifp);
! 287: void atu_media_status(struct ifnet *ifp, struct ifmediareq *req);
! 288: int atu_tx_list_init(struct atu_softc *);
! 289: int atu_rx_list_init(struct atu_softc *);
! 290: void atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch,
! 291: int listlen);
! 292:
! 293: void atu_task(void *);
! 294: int atu_newstate(struct ieee80211com *, enum ieee80211_state, int);
! 295: int atu_tx_start(struct atu_softc *, struct ieee80211_node *,
! 296: struct atu_chain *, struct mbuf *);
! 297: void atu_complete_attach(struct atu_softc *);
! 298: u_int8_t atu_calculate_padding(int);
! 299:
! 300: usbd_status
! 301: atu_usb_request(struct atu_softc *sc, u_int8_t type,
! 302: u_int8_t request, u_int16_t value, u_int16_t index, u_int16_t length,
! 303: u_int8_t *data)
! 304: {
! 305: usb_device_request_t req;
! 306: usbd_xfer_handle xfer;
! 307: usbd_status err;
! 308: int total_len = 0, s;
! 309:
! 310: req.bmRequestType = type;
! 311: req.bRequest = request;
! 312: USETW(req.wValue, value);
! 313: USETW(req.wIndex, index);
! 314: USETW(req.wLength, length);
! 315:
! 316: #ifdef ATU_DEBUG
! 317: if (atudebug) {
! 318: if ((data == NULL) || (type & UT_READ)) {
! 319: DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x "
! 320: "len=%02x\n", sc->atu_dev.dv_xname, request,
! 321: value, index, length));
! 322: } else {
! 323: DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x "
! 324: "len=%02x [%8D]\n", sc->atu_dev.dv_xname,
! 325: request, value, index, length, data, " "));
! 326: }
! 327: }
! 328: #endif /* ATU_DEBUG */
! 329:
! 330: s = splnet();
! 331:
! 332: xfer = usbd_alloc_xfer(sc->atu_udev);
! 333: usbd_setup_default_xfer(xfer, sc->atu_udev, 0, 500000, &req, data,
! 334: length, USBD_SHORT_XFER_OK, 0);
! 335:
! 336: err = usbd_sync_transfer(xfer);
! 337:
! 338: usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
! 339:
! 340: #ifdef ATU_DEBUG
! 341: if (atudebug) {
! 342: if (type & UT_READ) {
! 343: DPRINTFN(20, ("%s: transfered 0x%x bytes in\n",
! 344: sc->atu_dev.dv_xname, total_len));
! 345: DPRINTFN(20, ("%s: dump [%10D]\n",
! 346: sc->atu_dev.dv_xname, data, " "));
! 347: } else {
! 348: if (total_len != length)
! 349: DPRINTF(("%s: ARG! wrote only %x bytes\n",
! 350: sc->atu_dev.dv_xname, total_len));
! 351: }
! 352: }
! 353: #endif /* ATU_DEBUG */
! 354:
! 355: usbd_free_xfer(xfer);
! 356:
! 357: splx(s);
! 358: return(err);
! 359: }
! 360:
! 361: int
! 362: atu_send_command(struct atu_softc *sc, u_int8_t *command, int size)
! 363: {
! 364: return atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000,
! 365: 0x0000, size, command);
! 366: }
! 367:
! 368: int
! 369: atu_get_cmd_status(struct atu_softc *sc, u_int8_t cmd, u_int8_t *status)
! 370: {
! 371: /*
! 372: * all other drivers (including Windoze) request 40 bytes of status
! 373: * and get a short-xfer of just 6 bytes. we can save 34 bytes of
! 374: * buffer if we just request those 6 bytes in the first place :)
! 375: */
! 376: /*
! 377: return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd,
! 378: 0x0000, 40, status);
! 379: */
! 380: return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd,
! 381: 0x0000, 6, status);
! 382: }
! 383:
! 384: int
! 385: atu_wait_completion(struct atu_softc *sc, u_int8_t cmd, u_int8_t *status)
! 386: {
! 387: int idle_count = 0, err;
! 388: u_int8_t statusreq[6];
! 389:
! 390: DPRINTFN(15, ("%s: wait-completion: cmd=%02x\n",
! 391: sc->atu_dev.dv_xname, cmd));
! 392:
! 393: while (1) {
! 394: err = atu_get_cmd_status(sc, cmd, statusreq);
! 395: if (err)
! 396: return err;
! 397:
! 398: #ifdef ATU_DEBUG
! 399: if (atudebug) {
! 400: DPRINTFN(20, ("%s: status=%s cmd=%02x\n",
! 401: sc->atu_dev.dv_xname,
! 402: ether_sprintf(statusreq), cmd));
! 403: }
! 404: #endif /* ATU_DEBUG */
! 405:
! 406: /*
! 407: * during normal operations waiting on STATUS_IDLE
! 408: * will never happen more than once
! 409: */
! 410: if ((statusreq[5] == STATUS_IDLE) && (idle_count++ > 20)) {
! 411: DPRINTF(("%s: AAARRGGG!!! FIX ME!\n",
! 412: sc->atu_dev.dv_xname));
! 413: return 0;
! 414: }
! 415:
! 416: if ((statusreq[5] != STATUS_IN_PROGRESS) &&
! 417: (statusreq[5] != STATUS_IDLE)) {
! 418: if (status != NULL)
! 419: *status = statusreq[5];
! 420: return 0;
! 421: }
! 422: usbd_delay_ms(sc->atu_udev, 25);
! 423: }
! 424: }
! 425:
! 426: int
! 427: atu_send_mib(struct atu_softc *sc, u_int8_t type, u_int8_t size,
! 428: u_int8_t index, void *data)
! 429: {
! 430: int err;
! 431: struct atu_cmd_set_mib request;
! 432:
! 433: /*
! 434: * We don't construct a MIB packet first and then memcpy it into an
! 435: * Atmel-command-packet, we just construct it the right way at once :)
! 436: */
! 437:
! 438: memset(&request, 0, sizeof(request));
! 439:
! 440: request.AtCmd = CMD_SET_MIB;
! 441: USETW(request.AtSize, size + 4);
! 442:
! 443: request.MIBType = type;
! 444: request.MIBSize = size;
! 445: request.MIBIndex = index;
! 446: request.MIBReserved = 0;
! 447:
! 448: /*
! 449: * For 1 and 2 byte requests we assume a direct value,
! 450: * everything bigger than 2 bytes we assume a pointer to the data
! 451: */
! 452: switch (size) {
! 453: case 0:
! 454: break;
! 455: case 1:
! 456: request.data[0]=(long)data & 0x000000ff;
! 457: break;
! 458: case 2:
! 459: request.data[0]=(long)data & 0x000000ff;
! 460: request.data[1]=(long)data >> 8;
! 461: break;
! 462: default:
! 463: memcpy(request.data, data, size);
! 464: break;
! 465: }
! 466:
! 467: err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000,
! 468: 0x0000, size+8, (uByte *)&request);
! 469: if (err)
! 470: return (err);
! 471:
! 472: DPRINTFN(15, ("%s: sendmib : waitcompletion...\n",
! 473: sc->atu_dev.dv_xname));
! 474: return atu_wait_completion(sc, CMD_SET_MIB, NULL);
! 475: }
! 476:
! 477: int
! 478: atu_get_mib(struct atu_softc *sc, u_int8_t type, u_int8_t size,
! 479: u_int8_t index, u_int8_t *buf)
! 480: {
! 481:
! 482: /* linux/at76c503.c - 478 */
! 483: return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033,
! 484: type << 8, index, size, buf);
! 485: }
! 486:
! 487: #if 0
! 488: int
! 489: atu_start_ibss(struct atu_softc *sc)
! 490: {
! 491: int err;
! 492: struct atu_cmd_start_ibss Request;
! 493:
! 494: Request.Cmd = CMD_START_IBSS;
! 495: Request.Reserved = 0;
! 496: Request.Size = sizeof(Request) - 4;
! 497:
! 498: memset(Request.BSSID, 0x00, sizeof(Request.BSSID));
! 499: memset(Request.SSID, 0x00, sizeof(Request.SSID));
! 500: memcpy(Request.SSID, sc->atu_ssid, sc->atu_ssidlen);
! 501: Request.SSIDSize = sc->atu_ssidlen;
! 502: if (sc->atu_desired_channel != IEEE80211_CHAN_ANY)
! 503: Request.Channel = (u_int8_t)sc->atu_desired_channel;
! 504: else
! 505: Request.Channel = ATU_DEFAULT_CHANNEL;
! 506: Request.BSSType = AD_HOC_MODE;
! 507: memset(Request.Res, 0x00, sizeof(Request.Res));
! 508:
! 509: /* Write config to adapter */
! 510: err = atu_send_command(sc, (u_int8_t *)&Request, sizeof(Request));
! 511: if (err) {
! 512: DPRINTF(("%s: start ibss failed!\n",
! 513: sc->atu_dev.dv_xname));
! 514: return err;
! 515: }
! 516:
! 517: /* Wait for the adapter to do its thing */
! 518: err = atu_wait_completion(sc, CMD_START_IBSS, NULL);
! 519: if (err) {
! 520: DPRINTF(("%s: error waiting for start_ibss\n",
! 521: sc->atu_dev.dv_xname));
! 522: return err;
! 523: }
! 524:
! 525: /* Get the current BSSID */
! 526: err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, sc->atu_bssid);
! 527: if (err) {
! 528: DPRINTF(("%s: could not get BSSID!\n",
! 529: sc->atu_dev.dv_xname));
! 530: return err;
! 531: }
! 532:
! 533: DPRINTF(("%s: started a new IBSS (BSSID=%s)\n",
! 534: sc->atu_dev.dv_xname, ether_sprintf(sc->atu_bssid)));
! 535: return 0;
! 536: }
! 537: #endif
! 538:
! 539: int
! 540: atu_start_scan(struct atu_softc *sc)
! 541: {
! 542: struct ieee80211com *ic = &sc->sc_ic;
! 543: struct atu_cmd_do_scan Scan;
! 544: usbd_status err;
! 545: int Cnt;
! 546:
! 547: memset(&Scan, 0, sizeof(Scan));
! 548:
! 549: Scan.Cmd = CMD_START_SCAN;
! 550: Scan.Reserved = 0;
! 551: USETW(Scan.Size, sizeof(Scan) - 4);
! 552:
! 553: /* use the broadcast BSSID (in active scan) */
! 554: for (Cnt=0; Cnt<6; Cnt++)
! 555: Scan.BSSID[Cnt] = 0xff;
! 556:
! 557: memcpy(Scan.SSID, ic->ic_des_essid, ic->ic_des_esslen);
! 558: Scan.SSID_Len = ic->ic_des_esslen;
! 559:
! 560: /* default values for scan */
! 561: Scan.ScanType = ATU_SCAN_ACTIVE;
! 562: if (sc->atu_desired_channel != IEEE80211_CHAN_ANY)
! 563: Scan.Channel = (u_int8_t)sc->atu_desired_channel;
! 564: else
! 565: Scan.Channel = sc->atu_channel;
! 566:
! 567: /* we like scans to be quick :) */
! 568: /* the time we wait before sending probe's */
! 569: USETW(Scan.ProbeDelay, 0);
! 570: /* the time we stay on one channel */
! 571: USETW(Scan.MinChannelTime, 100);
! 572: USETW(Scan.MaxChannelTime, 200);
! 573: /* whether or not we scan all channels */
! 574: Scan.InternationalScan = 0xc1;
! 575:
! 576: #ifdef ATU_DEBUG
! 577: if (atudebug) {
! 578: DPRINTFN(20, ("%s: scan cmd len=%02x\n",
! 579: sc->atu_dev.dv_xname, sizeof(Scan)));
! 580: DPRINTFN(20, ("%s: scan cmd: %52D\n", sc->atu_dev.dv_xname,
! 581: (u_int8_t *)&Scan, " "));
! 582: }
! 583: #endif /* ATU_DEBUG */
! 584:
! 585: /* Write config to adapter */
! 586: err = atu_send_command(sc, (u_int8_t *)&Scan, sizeof(Scan));
! 587: if (err)
! 588: return err;
! 589:
! 590: /*
! 591: * We don't wait for the command to finish... the mgmt-thread will do
! 592: * that for us
! 593: */
! 594: /*
! 595: err = atu_wait_completion(sc, CMD_START_SCAN, NULL);
! 596: if (err)
! 597: return err;
! 598: */
! 599: return 0;
! 600: }
! 601:
! 602: int
! 603: atu_switch_radio(struct atu_softc *sc, int state)
! 604: {
! 605: usbd_status err;
! 606: struct atu_cmd CmdRadio;
! 607:
! 608: if (sc->atu_radio == RadioIntersil) {
! 609: /*
! 610: * Intersil doesn't seem to need/support switching the radio
! 611: * on/off
! 612: */
! 613: return 0;
! 614: }
! 615:
! 616: memset(&CmdRadio, 0, sizeof(CmdRadio));
! 617: CmdRadio.Cmd = CMD_RADIO_ON;
! 618:
! 619: if (sc->atu_radio_on != state) {
! 620: if (state == 0)
! 621: CmdRadio.Cmd = CMD_RADIO_OFF;
! 622:
! 623: err = atu_send_command(sc, (u_int8_t *)&CmdRadio,
! 624: sizeof(CmdRadio));
! 625: if (err)
! 626: return err;
! 627:
! 628: err = atu_wait_completion(sc, CmdRadio.Cmd, NULL);
! 629: if (err)
! 630: return err;
! 631:
! 632: DPRINTFN(10, ("%s: radio turned %s\n",
! 633: sc->atu_dev.dv_xname, state ? "on" : "off"));
! 634: sc->atu_radio_on = state;
! 635: }
! 636: return 0;
! 637: }
! 638:
! 639: int
! 640: atu_initial_config(struct atu_softc *sc)
! 641: {
! 642: struct ieee80211com *ic = &sc->sc_ic;
! 643: u_int32_t i;
! 644: usbd_status err;
! 645: /* u_int8_t rates[4] = {0x82, 0x84, 0x8B, 0x96};*/
! 646: u_int8_t rates[4] = {0x82, 0x04, 0x0B, 0x16};
! 647: struct atu_cmd_card_config cmd;
! 648: u_int8_t reg_domain;
! 649:
! 650: DPRINTFN(10, ("%s: sending mac-addr\n", sc->atu_dev.dv_xname));
! 651: err = atu_send_mib(sc, MIB_MAC_ADDR__ADDR, ic->ic_myaddr);
! 652: if (err) {
! 653: DPRINTF(("%s: error setting mac-addr\n",
! 654: sc->atu_dev.dv_xname));
! 655: return err;
! 656: }
! 657:
! 658: /*
! 659: DPRINTF(("%s: sending reg-domain\n", sc->atu_dev.dv_xname));
! 660: err = atu_send_mib(sc, MIB_PHY__REG_DOMAIN, NR(0x30));
! 661: if (err) {
! 662: DPRINTF(("%s: error setting mac-addr\n",
! 663: sc->atu_dev.dv_xname));
! 664: return err;
! 665: }
! 666: */
! 667:
! 668: memset(&cmd, 0, sizeof(cmd));
! 669: cmd.Cmd = CMD_STARTUP;
! 670: cmd.Reserved = 0;
! 671: USETW(cmd.Size, sizeof(cmd) - 4);
! 672:
! 673: if (sc->atu_desired_channel != IEEE80211_CHAN_ANY)
! 674: cmd.Channel = (u_int8_t)sc->atu_desired_channel;
! 675: else
! 676: cmd.Channel = sc->atu_channel;
! 677: cmd.AutoRateFallback = 1;
! 678: memcpy(cmd.BasicRateSet, rates, 4);
! 679:
! 680: /* ShortRetryLimit should be 7 according to 802.11 spec */
! 681: cmd.ShortRetryLimit = 7;
! 682: USETW(cmd.RTS_Threshold, 2347);
! 683: USETW(cmd.FragThreshold, 2346);
! 684:
! 685: /* Doesn't seem to work, but we'll set it to 1 anyway */
! 686: cmd.PromiscuousMode = 1;
! 687:
! 688: /* this goes into the beacon we transmit */
! 689: cmd.PrivacyInvoked = (ic->ic_flags & IEEE80211_F_WEPON) ? 1 : 0;
! 690:
! 691: cmd.ExcludeUnencrypted = 0;
! 692: switch (ic->ic_nw_keys[ic->ic_wep_txkey].k_cipher) {
! 693: case IEEE80211_CIPHER_WEP40:
! 694: cmd.EncryptionType = ATU_WEP_40BITS;
! 695: break;
! 696: case IEEE80211_CIPHER_WEP104:
! 697: cmd.EncryptionType = ATU_WEP_104BITS;
! 698: break;
! 699: default:
! 700: cmd.EncryptionType = ATU_WEP_OFF;
! 701: break;
! 702: }
! 703:
! 704: cmd.WEP_DefaultKeyID = ic->ic_wep_txkey;
! 705: for (i = 0; i < IEEE80211_WEP_NKID; i++) {
! 706: memcpy(cmd.WEP_DefaultKey[i], ic->ic_nw_keys[i].k_key,
! 707: ic->ic_nw_keys[i].k_len);
! 708: }
! 709:
! 710: /* Setting the SSID here doesn't seem to do anything */
! 711: memcpy(cmd.SSID, ic->ic_des_essid, ic->ic_des_esslen);
! 712: cmd.SSID_Len = ic->ic_des_esslen;
! 713:
! 714: cmd.ShortPreamble = 0;
! 715: USETW(cmd.BeaconPeriod, 100);
! 716: /* cmd.BeaconPeriod = 65535; */
! 717:
! 718: /*
! 719: * TODO:
! 720: * read reg domain MIB_PHY @ 0x17 (1 byte), (reply = 0x30)
! 721: * we should do something usefull with this info. right now it's just
! 722: * ignored
! 723: */
! 724: err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, ®_domain);
! 725: if (err) {
! 726: DPRINTF(("%s: could not get regdomain!\n",
! 727: sc->atu_dev.dv_xname));
! 728: } else {
! 729: DPRINTF(("%s: we're in reg domain 0x%x according to the "
! 730: "adapter\n", sc->atu_dev.dv_xname, reg_domain));
! 731: }
! 732:
! 733: #ifdef ATU_DEBUG
! 734: if (atudebug) {
! 735: DPRINTFN(20, ("%s: configlen=%02x\n", sc->atu_dev.dv_xname,
! 736: sizeof(cmd)));
! 737: DPRINTFN(20, ("%s: configdata= %108D\n",
! 738: sc->atu_dev.dv_xname, (u_int8_t *)&cmd, " "));
! 739: }
! 740: #endif /* ATU_DEBUG */
! 741:
! 742: /* Windoze : driver says exclude-unencrypted=1 & encr-type=1 */
! 743:
! 744: err = atu_send_command(sc, (u_int8_t *)&cmd, sizeof(cmd));
! 745: if (err)
! 746: return err;
! 747: err = atu_wait_completion(sc, CMD_STARTUP, NULL);
! 748: if (err)
! 749: return err;
! 750:
! 751: /* Turn on radio now */
! 752: err = atu_switch_radio(sc, 1);
! 753: if (err)
! 754: return err;
! 755:
! 756: /* preamble type = short */
! 757: err = atu_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT));
! 758: if (err)
! 759: return err;
! 760:
! 761: /* frag = 1536 */
! 762: err = atu_send_mib(sc, MIB_MAC__FRAG, NR(2346));
! 763: if (err)
! 764: return err;
! 765:
! 766: /* rts = 1536 */
! 767: err = atu_send_mib(sc, MIB_MAC__RTS, NR(2347));
! 768: if (err)
! 769: return err;
! 770:
! 771: /* auto rate fallback = 1 */
! 772: err = atu_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1));
! 773: if (err)
! 774: return err;
! 775:
! 776: /* power mode = full on, no power saving */
! 777: err = atu_send_mib(sc, MIB_MAC_MGMT__POWER_MODE,
! 778: NR(POWER_MODE_ACTIVE));
! 779: if (err)
! 780: return err;
! 781:
! 782: DPRINTFN(10, ("%s: completed initial config\n",
! 783: sc->atu_dev.dv_xname));
! 784: return 0;
! 785: }
! 786:
! 787: int
! 788: atu_join(struct atu_softc *sc, struct ieee80211_node *node)
! 789: {
! 790: struct atu_cmd_join join;
! 791: u_int8_t status;
! 792: usbd_status err;
! 793:
! 794: memset(&join, 0, sizeof(join));
! 795:
! 796: join.Cmd = CMD_JOIN;
! 797: join.Reserved = 0x00;
! 798: USETW(join.Size, sizeof(join) - 4);
! 799:
! 800: DPRINTFN(15, ("%s: pre-join sc->atu_bssid=%s\n",
! 801: sc->atu_dev.dv_xname, ether_sprintf(sc->atu_bssid)));
! 802: DPRINTFN(15, ("%s: mode=%d\n", sc->atu_dev.dv_xname,
! 803: sc->atu_mode));
! 804: memcpy(join.bssid, node->ni_bssid, IEEE80211_ADDR_LEN);
! 805: memcpy(join.essid, node->ni_essid, node->ni_esslen);
! 806: join.essid_size = node->ni_esslen;
! 807: if (node->ni_capinfo & IEEE80211_CAPINFO_IBSS)
! 808: join.bss_type = AD_HOC_MODE;
! 809: else
! 810: join.bss_type = INFRASTRUCTURE_MODE;
! 811: join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan);
! 812:
! 813: USETW(join.timeout, ATU_JOIN_TIMEOUT);
! 814: join.reserved = 0x00;
! 815:
! 816: DPRINTFN(10, ("%s: trying to join BSSID=%s\n",
! 817: sc->atu_dev.dv_xname, ether_sprintf(join.bssid)));
! 818: err = atu_send_command(sc, (u_int8_t *)&join, sizeof(join));
! 819: if (err) {
! 820: DPRINTF(("%s: ERROR trying to join IBSS\n",
! 821: sc->atu_dev.dv_xname));
! 822: return err;
! 823: }
! 824: err = atu_wait_completion(sc, CMD_JOIN, &status);
! 825: if (err) {
! 826: DPRINTF(("%s: error joining BSS!\n",
! 827: sc->atu_dev.dv_xname));
! 828: return err;
! 829: }
! 830: if (status != STATUS_COMPLETE) {
! 831: DPRINTF(("%s: error joining... [status=%02x]\n",
! 832: sc->atu_dev.dv_xname, status));
! 833: return status;
! 834: } else {
! 835: DPRINTFN(10, ("%s: joined BSS\n", sc->atu_dev.dv_xname));
! 836: }
! 837: return err;
! 838: }
! 839:
! 840: /*
! 841: * Get the state of the DFU unit
! 842: */
! 843: int8_t
! 844: atu_get_dfu_state(struct atu_softc *sc)
! 845: {
! 846: u_int8_t state;
! 847:
! 848: if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state))
! 849: return -1;
! 850: return state;
! 851: }
! 852:
! 853: /*
! 854: * Get MAC opmode
! 855: */
! 856: u_int8_t
! 857: atu_get_opmode(struct atu_softc *sc, u_int8_t *mode)
! 858: {
! 859:
! 860: return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001,
! 861: 0x0000, 1, mode);
! 862: }
! 863:
! 864: /*
! 865: * Upload the internal firmware into the device
! 866: */
! 867: void
! 868: atu_internal_firmware(void *arg)
! 869: {
! 870: struct atu_softc *sc = arg;
! 871: u_char state, *ptr = NULL, *firm = NULL, status[6];
! 872: int block_size, block = 0, err, i;
! 873: size_t bytes_left = 0;
! 874: char *name = "unknown-device";
! 875:
! 876: /*
! 877: * Uploading firmware is done with the DFU (Device Firmware Upgrade)
! 878: * interface. See "Universal Serial Bus - Device Class Specification
! 879: * for Device Firmware Upgrade" pdf for details of the protocol.
! 880: * Maybe this could be moved to a seperate 'firmware driver' once more
! 881: * device drivers need it... For now we'll just do it here.
! 882: *
! 883: * Just for your information, the Atmel's DFU descriptor looks like
! 884: * this:
! 885: *
! 886: * 07 size
! 887: * 21 type
! 888: * 01 capabilities : only firmware download, need reset
! 889: * after download
! 890: * 13 05 detach timeout : max 1299ms between DFU_DETACH and
! 891: * reset
! 892: * 00 04 max bytes of firmware per transaction : 1024
! 893: */
! 894:
! 895: /* Choose the right firmware for the device */
! 896: for (i = 0; i < sizeof(atu_radfirm)/sizeof(atu_radfirm[0]); i++)
! 897: if (sc->atu_radio == atu_radfirm[i].atur_type)
! 898: name = atu_radfirm[i].atur_internal;
! 899:
! 900: DPRINTF(("%s: loading firmware %s...\n",
! 901: sc->atu_dev.dv_xname, name));
! 902: err = loadfirmware(name, &firm, &bytes_left);
! 903: if (err != 0) {
! 904: printf("%s: %s loadfirmware error %d\n",
! 905: sc->atu_dev.dv_xname, name, err);
! 906: return;
! 907: }
! 908:
! 909: ptr = firm;
! 910: state = atu_get_dfu_state(sc);
! 911:
! 912: while (block >= 0 && state > 0) {
! 913: switch (state) {
! 914: case DFUState_DnLoadSync:
! 915: /* get DFU status */
! 916: err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6,
! 917: status);
! 918: if (err) {
! 919: DPRINTF(("%s: dfu_getstatus failed!\n",
! 920: sc->atu_dev.dv_xname));
! 921: free(firm, M_DEVBUF);
! 922: return;
! 923: }
! 924: /* success means state => DnLoadIdle */
! 925: state = DFUState_DnLoadIdle;
! 926: continue;
! 927: break;
! 928:
! 929: case DFUState_DFUIdle:
! 930: case DFUState_DnLoadIdle:
! 931: if (bytes_left>=DFU_MaxBlockSize)
! 932: block_size = DFU_MaxBlockSize;
! 933: else
! 934: block_size = bytes_left;
! 935: DPRINTFN(15, ("%s: firmware block %d\n",
! 936: sc->atu_dev.dv_xname, block));
! 937:
! 938: err = atu_usb_request(sc, DFU_DNLOAD, block++, 0,
! 939: block_size, ptr);
! 940: if (err) {
! 941: DPRINTF(("%s: dfu_dnload failed\n",
! 942: sc->atu_dev.dv_xname));
! 943: free(firm, M_DEVBUF);
! 944: return;
! 945: }
! 946:
! 947: ptr += block_size;
! 948: bytes_left -= block_size;
! 949: if (block_size == 0)
! 950: block = -1;
! 951: break;
! 952:
! 953: default:
! 954: DPRINTFN(20, ("%s: sleeping for a while\n",
! 955: sc->atu_dev.dv_xname));
! 956: usbd_delay_ms(sc->atu_udev, 100);
! 957: break;
! 958: }
! 959:
! 960: state = atu_get_dfu_state(sc);
! 961: }
! 962: free(firm, M_DEVBUF);
! 963:
! 964: if (state != DFUState_ManifestSync) {
! 965: DPRINTF(("%s: state != manifestsync... eek!\n",
! 966: sc->atu_dev.dv_xname));
! 967: }
! 968:
! 969: err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status);
! 970: if (err) {
! 971: DPRINTF(("%s: dfu_getstatus failed!\n",
! 972: sc->atu_dev.dv_xname));
! 973: return;
! 974: }
! 975:
! 976: DPRINTFN(15, ("%s: sending remap\n", sc->atu_dev.dv_xname));
! 977: err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL);
! 978: if ((err) && (!ISSET(sc->atu_quirk, ATU_QUIRK_NO_REMAP))) {
! 979: DPRINTF(("%s: remap failed!\n", sc->atu_dev.dv_xname));
! 980: return;
! 981: }
! 982:
! 983: /* after a lot of trying and measuring I found out the device needs
! 984: * about 56 miliseconds after sending the remap command before
! 985: * it's ready to communicate again. So we'll wait just a little bit
! 986: * longer than that to be sure...
! 987: */
! 988: usbd_delay_ms(sc->atu_udev, 56+100);
! 989:
! 990: printf("%s: reattaching after firmware upload\n",
! 991: sc->atu_dev.dv_xname);
! 992: usb_needs_reattach(sc->atu_udev);
! 993: }
! 994:
! 995: void
! 996: atu_external_firmware(void *arg)
! 997: {
! 998: struct atu_softc *sc = arg;
! 999: u_char *ptr = NULL, *firm = NULL;
! 1000: int block_size, block = 0, err, i;
! 1001: size_t bytes_left = 0;
! 1002: char *name = "unknown-device";
! 1003:
! 1004: for (i = 0; i < sizeof(atu_radfirm)/sizeof(atu_radfirm[0]); i++)
! 1005: if (sc->atu_radio == atu_radfirm[i].atur_type)
! 1006: name = atu_radfirm[i].atur_external;
! 1007:
! 1008: DPRINTF(("%s: loading external firmware %s\n",
! 1009: sc->atu_dev.dv_xname, name));
! 1010: err = loadfirmware(name, &firm, &bytes_left);
! 1011: if (err != 0) {
! 1012: printf("%s: %s loadfirmware error %d\n",
! 1013: sc->atu_dev.dv_xname, name, err);
! 1014: return;
! 1015: }
! 1016: ptr = firm;
! 1017:
! 1018: while (bytes_left) {
! 1019: if (bytes_left > 1024)
! 1020: block_size = 1024;
! 1021: else
! 1022: block_size = bytes_left;
! 1023:
! 1024: DPRINTFN(15, ("%s: block:%d size:%d\n",
! 1025: sc->atu_dev.dv_xname, block, block_size));
! 1026: err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e,
! 1027: 0x0802, block, block_size, ptr);
! 1028: if (err) {
! 1029: DPRINTF(("%s: could not load external firmware "
! 1030: "block\n", sc->atu_dev.dv_xname));
! 1031: free(firm, M_DEVBUF);
! 1032: return;
! 1033: }
! 1034:
! 1035: ptr += block_size;
! 1036: block++;
! 1037: bytes_left -= block_size;
! 1038: }
! 1039: free(firm, M_DEVBUF);
! 1040:
! 1041: err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0802,
! 1042: block, 0, NULL);
! 1043: if (err) {
! 1044: DPRINTF(("%s: could not load last zero-length firmware "
! 1045: "block\n", sc->atu_dev.dv_xname));
! 1046: return;
! 1047: }
! 1048:
! 1049: /*
! 1050: * The SMC2662w V.4 seems to require some time to do its thing with
! 1051: * the external firmware... 20 ms isn't enough, but 21 ms works 100
! 1052: * times out of 100 tries. We'll wait a bit longer just to be sure
! 1053: */
! 1054: if (sc->atu_quirk & ATU_QUIRK_FW_DELAY)
! 1055: usbd_delay_ms(sc->atu_udev, 21 + 100);
! 1056:
! 1057: DPRINTFN(10, ("%s: external firmware upload done\n",
! 1058: sc->atu_dev.dv_xname));
! 1059: /* complete configuration after the firmwares have been uploaded */
! 1060: atu_complete_attach(sc);
! 1061: }
! 1062:
! 1063: int
! 1064: atu_get_card_config(struct atu_softc *sc)
! 1065: {
! 1066: struct ieee80211com *ic = &sc->sc_ic;
! 1067: struct atu_rfmd_conf rfmd_conf;
! 1068: struct atu_intersil_conf intersil_conf;
! 1069: int err;
! 1070:
! 1071: switch (sc->atu_radio) {
! 1072:
! 1073: case RadioRFMD:
! 1074: case RadioRFMD2958:
! 1075: case RadioRFMD2958_SMC:
! 1076: case AT76C503_rfmd_acc:
! 1077: case AT76C505_rfmd:
! 1078: err = atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33,
! 1079: 0x0a02, 0x0000, sizeof(rfmd_conf),
! 1080: (u_int8_t *)&rfmd_conf);
! 1081: if (err) {
! 1082: DPRINTF(("%s: could not get rfmd config!\n",
! 1083: sc->atu_dev.dv_xname));
! 1084: return err;
! 1085: }
! 1086: memcpy(ic->ic_myaddr, rfmd_conf.MACAddr, IEEE80211_ADDR_LEN);
! 1087: break;
! 1088:
! 1089: case RadioIntersil:
! 1090: case AT76C503_i3863:
! 1091: err = atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33,
! 1092: 0x0902, 0x0000, sizeof(intersil_conf),
! 1093: (u_int8_t *)&intersil_conf);
! 1094: if (err) {
! 1095: DPRINTF(("%s: could not get intersil config!\n",
! 1096: sc->atu_dev.dv_xname));
! 1097: return err;
! 1098: }
! 1099: memcpy(ic->ic_myaddr, intersil_conf.MACAddr,
! 1100: IEEE80211_ADDR_LEN);
! 1101: break;
! 1102: }
! 1103: return 0;
! 1104: }
! 1105:
! 1106: /*
! 1107: * Probe for an AT76c503 chip.
! 1108: */
! 1109: int
! 1110: atu_match(struct device *parent, void *match, void *aux)
! 1111: {
! 1112: struct usb_attach_arg *uaa = aux;
! 1113: int i;
! 1114:
! 1115: if (!uaa->iface)
! 1116: return(UMATCH_NONE);
! 1117:
! 1118: for (i = 0; i < sizeof(atu_devs)/sizeof(atu_devs[0]); i++) {
! 1119: struct atu_type *t = &atu_devs[i];
! 1120:
! 1121: if (uaa->vendor == t->atu_vid &&
! 1122: uaa->product == t->atu_pid) {
! 1123: return(UMATCH_VENDOR_PRODUCT);
! 1124: }
! 1125: }
! 1126: return(UMATCH_NONE);
! 1127: }
! 1128:
! 1129: int
! 1130: atu_media_change(struct ifnet *ifp)
! 1131: {
! 1132: #ifdef ATU_DEBUG
! 1133: struct atu_softc *sc = ifp->if_softc;
! 1134: #endif /* ATU_DEBUG */
! 1135: int err;
! 1136:
! 1137: DPRINTFN(10, ("%s: atu_media_change\n", sc->atu_dev.dv_xname));
! 1138:
! 1139: err = ieee80211_media_change(ifp);
! 1140: if (err == ENETRESET) {
! 1141: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) ==
! 1142: (IFF_RUNNING|IFF_UP))
! 1143: atu_init(ifp);
! 1144: err = 0;
! 1145: }
! 1146:
! 1147: return (err);
! 1148: }
! 1149:
! 1150: void
! 1151: atu_media_status(struct ifnet *ifp, struct ifmediareq *req)
! 1152: {
! 1153: #ifdef ATU_DEBUG
! 1154: struct atu_softc *sc = ifp->if_softc;
! 1155: #endif /* ATU_DEBUG */
! 1156:
! 1157: DPRINTFN(10, ("%s: atu_media_status\n", sc->atu_dev.dv_xname));
! 1158:
! 1159: ieee80211_media_status(ifp, req);
! 1160: }
! 1161:
! 1162: void
! 1163: atu_task(void *arg)
! 1164: {
! 1165: struct atu_softc *sc = (struct atu_softc *)arg;
! 1166: struct ieee80211com *ic = &sc->sc_ic;
! 1167: struct ifnet *ifp = &ic->ic_if;
! 1168: usbd_status err;
! 1169: int s;
! 1170:
! 1171: DPRINTFN(10, ("%s: atu_task\n", sc->atu_dev.dv_xname));
! 1172:
! 1173: if (sc->sc_state != ATU_S_OK)
! 1174: return;
! 1175:
! 1176: switch (sc->sc_cmd) {
! 1177: case ATU_C_SCAN:
! 1178:
! 1179: err = atu_start_scan(sc);
! 1180: if (err) {
! 1181: DPRINTFN(1, ("%s: atu_init: couldn't start scan!\n",
! 1182: sc->atu_dev.dv_xname));
! 1183: return;
! 1184: }
! 1185:
! 1186: err = atu_wait_completion(sc, CMD_START_SCAN, NULL);
! 1187: if (err) {
! 1188: DPRINTF(("%s: atu_init: error waiting for scan\n",
! 1189: sc->atu_dev.dv_xname));
! 1190: return;
! 1191: }
! 1192:
! 1193: DPRINTF(("%s: ==========================> END OF SCAN!\n",
! 1194: sc->atu_dev.dv_xname));
! 1195:
! 1196: s = splnet();
! 1197: /* ieee80211_next_scan(ifp); */
! 1198: ieee80211_end_scan(ifp);
! 1199: splx(s);
! 1200:
! 1201: DPRINTF(("%s: ----------------------======> END OF SCAN2!\n",
! 1202: sc->atu_dev.dv_xname));
! 1203: break;
! 1204:
! 1205: case ATU_C_JOIN:
! 1206: atu_join(sc, ic->ic_bss);
! 1207: }
! 1208: }
! 1209:
! 1210: int
! 1211: atu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
! 1212: {
! 1213: struct ifnet *ifp = &ic->ic_if;
! 1214: struct atu_softc *sc = ifp->if_softc;
! 1215: enum ieee80211_state ostate = ic->ic_state;
! 1216:
! 1217: DPRINTFN(10, ("%s: atu_newstate: %s -> %s\n", sc->atu_dev.dv_xname,
! 1218: ieee80211_state_name[ostate], ieee80211_state_name[nstate]));
! 1219:
! 1220: switch (nstate) {
! 1221: case IEEE80211_S_SCAN:
! 1222: memcpy(ic->ic_chan_scan, ic->ic_chan_active,
! 1223: sizeof(ic->ic_chan_active));
! 1224: ieee80211_free_allnodes(ic);
! 1225:
! 1226: /* tell the event thread that we want a scan */
! 1227: sc->sc_cmd = ATU_C_SCAN;
! 1228: usb_add_task(sc->atu_udev, &sc->sc_task);
! 1229:
! 1230: /* handle this ourselves */
! 1231: ic->ic_state = nstate;
! 1232: return (0);
! 1233:
! 1234: case IEEE80211_S_AUTH:
! 1235: case IEEE80211_S_RUN:
! 1236: if (ostate == IEEE80211_S_SCAN) {
! 1237: sc->sc_cmd = ATU_C_JOIN;
! 1238: usb_add_task(sc->atu_udev, &sc->sc_task);
! 1239: }
! 1240: break;
! 1241: default:
! 1242: /* nothing to do */
! 1243: break;
! 1244: }
! 1245:
! 1246: return (*sc->sc_newstate)(ic, nstate, arg);
! 1247: }
! 1248:
! 1249: /*
! 1250: * Attach the interface. Allocate softc structures, do
! 1251: * setup and ethernet/BPF attach.
! 1252: */
! 1253: void
! 1254: atu_attach(struct device *parent, struct device *self, void *aux)
! 1255: {
! 1256: struct atu_softc *sc = (struct atu_softc *)self;
! 1257: struct usb_attach_arg *uaa = aux;
! 1258: char *devinfop;
! 1259: usbd_status err;
! 1260: usbd_device_handle dev = uaa->device;
! 1261: u_int8_t mode, channel;
! 1262: int i;
! 1263:
! 1264: sc->sc_state = ATU_S_UNCONFIG;
! 1265:
! 1266: devinfop = usbd_devinfo_alloc(dev, 0);
! 1267: printf("\n%s: %s", sc->atu_dev.dv_xname, devinfop);
! 1268: usbd_devinfo_free(devinfop);
! 1269:
! 1270: err = usbd_set_config_no(dev, ATU_CONFIG_NO, 1);
! 1271: if (err) {
! 1272: printf("%s: setting config no failed\n",
! 1273: sc->atu_dev.dv_xname);
! 1274: return;
! 1275: }
! 1276:
! 1277: err = usbd_device2interface_handle(dev, ATU_IFACE_IDX, &sc->atu_iface);
! 1278: if (err) {
! 1279: printf("%s: getting interface handle failed\n",
! 1280: sc->atu_dev.dv_xname);
! 1281: return;
! 1282: }
! 1283:
! 1284: sc->atu_unit = self->dv_unit;
! 1285: sc->atu_udev = dev;
! 1286:
! 1287: /*
! 1288: * look up the radio_type for the device
! 1289: * basically does the same as USB_MATCH
! 1290: */
! 1291: for (i = 0; i < sizeof(atu_devs)/sizeof(atu_devs[0]); i++) {
! 1292: struct atu_type *t = &atu_devs[i];
! 1293:
! 1294: if (uaa->vendor == t->atu_vid &&
! 1295: uaa->product == t->atu_pid) {
! 1296: sc->atu_radio = t->atu_radio;
! 1297: sc->atu_quirk = t->atu_quirk;
! 1298: }
! 1299: }
! 1300:
! 1301: /*
! 1302: * Check in the interface descriptor if we're in DFU mode
! 1303: * If we're in DFU mode, we upload the external firmware
! 1304: * If we're not, the PC must have rebooted without power-cycling
! 1305: * the device.. I've tried this out, a reboot only requeres the
! 1306: * external firmware to be reloaded :)
! 1307: *
! 1308: * Hmm. The at76c505a doesn't report a DFU descriptor when it's
! 1309: * in DFU mode... Let's just try to get the opmode
! 1310: */
! 1311: err = atu_get_opmode(sc, &mode);
! 1312: DPRINTFN(20, ("%s: opmode: %d\n", sc->atu_dev.dv_xname, mode));
! 1313: if (err || (mode != MODE_NETCARD && mode != MODE_NOFLASHNETCARD)) {
! 1314: DPRINTF(("%s: starting internal firmware download\n",
! 1315: sc->atu_dev.dv_xname));
! 1316:
! 1317: printf("\n");
! 1318:
! 1319: if (rootvp == NULL)
! 1320: mountroothook_establish(atu_internal_firmware, sc);
! 1321: else
! 1322: atu_internal_firmware(sc);
! 1323: /*
! 1324: * atu_internal_firmware will cause a reset of the device
! 1325: * so we don't want to do any more configuration after this
! 1326: * point.
! 1327: */
! 1328: return;
! 1329: }
! 1330:
! 1331: uaa->iface = sc->atu_iface;
! 1332:
! 1333: if (mode != MODE_NETCARD) {
! 1334: DPRINTFN(15, ("%s: device needs external firmware\n",
! 1335: sc->atu_dev.dv_xname));
! 1336:
! 1337: if (mode != MODE_NOFLASHNETCARD) {
! 1338: DPRINTF(("%s: EEK! unexpected opmode=%d\n",
! 1339: sc->atu_dev.dv_xname, mode));
! 1340: }
! 1341:
! 1342: /*
! 1343: * There is no difference in opmode before and after external
! 1344: * firmware upload with the SMC2662 V.4 . So instead we'll try
! 1345: * to read the channel number. If we succeed, external
! 1346: * firmwaremust have been already uploaded...
! 1347: */
! 1348: if (sc->atu_radio != RadioIntersil) {
! 1349: err = atu_get_mib(sc, MIB_PHY__CHANNEL, &channel);
! 1350: if (!err) {
! 1351: DPRINTF(("%s: external firmware has already"
! 1352: " been downloaded\n",
! 1353: sc->atu_dev.dv_xname));
! 1354: atu_complete_attach(sc);
! 1355: return;
! 1356: }
! 1357: }
! 1358:
! 1359: if (rootvp == NULL)
! 1360: mountroothook_establish(atu_external_firmware, sc);
! 1361: else
! 1362: atu_external_firmware(sc);
! 1363:
! 1364: /*
! 1365: * atu_external_firmware will call atu_complete_attach after
! 1366: * it's finished so we can just return.
! 1367: */
! 1368: } else {
! 1369: /* all the firmwares are in place, so complete the attach */
! 1370: atu_complete_attach(sc);
! 1371: }
! 1372: }
! 1373:
! 1374: void
! 1375: atu_complete_attach(struct atu_softc *sc)
! 1376: {
! 1377: struct ieee80211com *ic = &sc->sc_ic;
! 1378: struct ifnet *ifp = &ic->ic_if;
! 1379: usb_interface_descriptor_t *id;
! 1380: usb_endpoint_descriptor_t *ed;
! 1381: usbd_status err;
! 1382: int i;
! 1383: #ifdef ATU_DEBUG
! 1384: struct atu_fw fw;
! 1385: #endif
! 1386:
! 1387: id = usbd_get_interface_descriptor(sc->atu_iface);
! 1388:
! 1389: /* Find endpoints. */
! 1390: for (i = 0; i < id->bNumEndpoints; i++) {
! 1391: ed = usbd_interface2endpoint_descriptor(sc->atu_iface, i);
! 1392: if (!ed) {
! 1393: DPRINTF(("%s: num_endp:%d\n", sc->atu_dev.dv_xname,
! 1394: sc->atu_iface->idesc->bNumEndpoints));
! 1395: DPRINTF(("%s: couldn't get ep %d\n",
! 1396: sc->atu_dev.dv_xname, i));
! 1397: return;
! 1398: }
! 1399: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
! 1400: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 1401: sc->atu_ed[ATU_ENDPT_RX] = ed->bEndpointAddress;
! 1402: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
! 1403: UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
! 1404: sc->atu_ed[ATU_ENDPT_TX] = ed->bEndpointAddress;
! 1405: }
! 1406: }
! 1407:
! 1408: /* read device config & get MAC address */
! 1409: err = atu_get_card_config(sc);
! 1410: if (err) {
! 1411: printf("\n%s: could not get card cfg!\n",
! 1412: sc->atu_dev.dv_xname);
! 1413: return;
! 1414: }
! 1415:
! 1416: #ifdef ATU_DEBUG
! 1417: /* DEBUG : try to get firmware version */
! 1418: err = atu_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0,
! 1419: (u_int8_t *)&fw);
! 1420: if (!err) {
! 1421: DPRINTFN(15, ("%s: firmware: maj:%d min:%d patch:%d "
! 1422: "build:%d\n", sc->atu_dev.dv_xname, fw.major, fw.minor,
! 1423: fw.patch, fw.build));
! 1424: } else {
! 1425: DPRINTF(("%s: get firmware version failed\n",
! 1426: sc->atu_dev.dv_xname));
! 1427: }
! 1428: #endif /* ATU_DEBUG */
! 1429:
! 1430: /* Show the world our MAC address */
! 1431: printf(", address %s\n", ether_sprintf(ic->ic_myaddr));
! 1432:
! 1433: sc->atu_cdata.atu_tx_inuse = 0;
! 1434:
! 1435: bzero(sc->atu_bssid, ETHER_ADDR_LEN);
! 1436: sc->atu_channel = ATU_DEFAULT_CHANNEL;
! 1437: sc->atu_desired_channel = IEEE80211_CHAN_ANY;
! 1438: sc->atu_mode = INFRASTRUCTURE_MODE;
! 1439:
! 1440: ic->ic_softc = sc;
! 1441: ic->ic_phytype = IEEE80211_T_DS;
! 1442: ic->ic_opmode = IEEE80211_M_STA;
! 1443: ic->ic_state = IEEE80211_S_INIT;
! 1444: ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP | IEEE80211_C_SCANALL;
! 1445: ic->ic_max_rssi = atu_radfirm[sc->atu_radio].max_rssi;
! 1446:
! 1447: ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
! 1448:
! 1449: for (i = 1; i <= 14; i++) {
! 1450: ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B |
! 1451: IEEE80211_CHAN_PASSIVE;
! 1452: ic->ic_channels[i].ic_freq = ieee80211_ieee2mhz(i,
! 1453: ic->ic_channels[i].ic_flags);
! 1454: }
! 1455:
! 1456: ic->ic_ibss_chan = &ic->ic_channels[0];
! 1457:
! 1458: ifp->if_softc = sc;
! 1459: memcpy(ifp->if_xname, sc->atu_dev.dv_xname, IFNAMSIZ);
! 1460: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
! 1461: ifp->if_start = atu_start;
! 1462: ifp->if_ioctl = atu_ioctl;
! 1463: ifp->if_watchdog = atu_watchdog;
! 1464: ifp->if_mtu = ATU_DEFAULT_MTU;
! 1465: IFQ_SET_READY(&ifp->if_snd);
! 1466:
! 1467: /* Call MI attach routine. */
! 1468: if_attach(ifp);
! 1469: ieee80211_ifattach(ifp);
! 1470:
! 1471: sc->sc_newstate = ic->ic_newstate;
! 1472: ic->ic_newstate = atu_newstate;
! 1473:
! 1474: /* setup ifmedia interface */
! 1475: ieee80211_media_init(ifp, atu_media_change, atu_media_status);
! 1476:
! 1477: usb_init_task(&sc->sc_task, atu_task, sc);
! 1478:
! 1479: #if NBPFILTER > 0
! 1480: bpfattach(&sc->sc_radiobpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
! 1481: sizeof(struct ieee80211_frame) + 64);
! 1482:
! 1483: bzero(&sc->sc_rxtapu, sizeof(sc->sc_rxtapu));
! 1484: sc->sc_rxtap.rr_ihdr.it_len = sizeof(sc->sc_rxtapu);
! 1485: sc->sc_rxtap.rr_ihdr.it_present = htole32(ATU_RX_RADIOTAP_PRESENT);
! 1486:
! 1487: bzero(&sc->sc_txtapu, sizeof(sc->sc_txtapu));
! 1488: sc->sc_txtap.rt_ihdr.it_len = sizeof(sc->sc_txtapu);
! 1489: sc->sc_txtap.rt_ihdr.it_present = htole32(ATU_TX_RADIOTAP_PRESENT);
! 1490: #endif
! 1491:
! 1492: sc->sc_state = ATU_S_OK;
! 1493: }
! 1494:
! 1495: int
! 1496: atu_detach(struct device *self, int flags)
! 1497: {
! 1498: struct atu_softc *sc = (struct atu_softc *)self;
! 1499: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1500:
! 1501: DPRINTFN(10, ("%s: atu_detach state=%d\n", sc->atu_dev.dv_xname,
! 1502: sc->sc_state));
! 1503:
! 1504: if (sc->sc_state != ATU_S_UNCONFIG) {
! 1505: atu_stop(ifp, 1);
! 1506: ieee80211_ifdetach(ifp);
! 1507: if_detach(ifp);
! 1508:
! 1509: if (sc->atu_ep[ATU_ENDPT_TX] != NULL)
! 1510: usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
! 1511: if (sc->atu_ep[ATU_ENDPT_RX] != NULL)
! 1512: usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
! 1513:
! 1514: usb_rem_task(sc->atu_udev, &sc->sc_task);
! 1515: }
! 1516:
! 1517: return(0);
! 1518: }
! 1519:
! 1520: int
! 1521: atu_activate(struct device *self, enum devact act)
! 1522: {
! 1523: struct atu_softc *sc = (struct atu_softc *)self;
! 1524:
! 1525: switch (act) {
! 1526: case DVACT_ACTIVATE:
! 1527: break;
! 1528: case DVACT_DEACTIVATE:
! 1529: if (sc->sc_state != ATU_S_UNCONFIG)
! 1530: sc->sc_state = ATU_S_DEAD;
! 1531: break;
! 1532: }
! 1533: return (0);
! 1534: }
! 1535:
! 1536: /*
! 1537: * Initialize an RX descriptor and attach an MBUF cluster.
! 1538: */
! 1539: int
! 1540: atu_newbuf(struct atu_softc *sc, struct atu_chain *c, struct mbuf *m)
! 1541: {
! 1542: struct mbuf *m_new = NULL;
! 1543:
! 1544: if (m == NULL) {
! 1545: MGETHDR(m_new, M_DONTWAIT, MT_DATA);
! 1546: if (m_new == NULL) {
! 1547: DPRINTF(("%s: no memory for rx list\n",
! 1548: sc->atu_dev.dv_xname));
! 1549: return(ENOBUFS);
! 1550: }
! 1551:
! 1552: MCLGET(m_new, M_DONTWAIT);
! 1553: if (!(m_new->m_flags & M_EXT)) {
! 1554: DPRINTF(("%s: no memory for rx list\n",
! 1555: sc->atu_dev.dv_xname));
! 1556: m_freem(m_new);
! 1557: return(ENOBUFS);
! 1558: }
! 1559: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 1560: } else {
! 1561: m_new = m;
! 1562: m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
! 1563: m_new->m_data = m_new->m_ext.ext_buf;
! 1564: }
! 1565: c->atu_mbuf = m_new;
! 1566: return(0);
! 1567: }
! 1568:
! 1569: int
! 1570: atu_rx_list_init(struct atu_softc *sc)
! 1571: {
! 1572: struct atu_cdata *cd = &sc->atu_cdata;
! 1573: struct atu_chain *c;
! 1574: int i;
! 1575:
! 1576: DPRINTFN(15, ("%s: atu_rx_list_init: enter\n",
! 1577: sc->atu_dev.dv_xname));
! 1578:
! 1579: for (i = 0; i < ATU_RX_LIST_CNT; i++) {
! 1580: c = &cd->atu_rx_chain[i];
! 1581: c->atu_sc = sc;
! 1582: c->atu_idx = i;
! 1583: if (c->atu_xfer == NULL) {
! 1584: c->atu_xfer = usbd_alloc_xfer(sc->atu_udev);
! 1585: if (c->atu_xfer == NULL)
! 1586: return (ENOBUFS);
! 1587: c->atu_buf = usbd_alloc_buffer(c->atu_xfer,
! 1588: ATU_RX_BUFSZ);
! 1589: if (c->atu_buf == NULL) /* XXX free xfer */
! 1590: return (ENOBUFS);
! 1591: if (atu_newbuf(sc, c, NULL) == ENOBUFS) /* XXX free? */
! 1592: return(ENOBUFS);
! 1593: }
! 1594: }
! 1595: return (0);
! 1596: }
! 1597:
! 1598: int
! 1599: atu_tx_list_init(struct atu_softc *sc)
! 1600: {
! 1601: struct atu_cdata *cd = &sc->atu_cdata;
! 1602: struct atu_chain *c;
! 1603: int i;
! 1604:
! 1605: DPRINTFN(15, ("%s: atu_tx_list_init\n",
! 1606: sc->atu_dev.dv_xname));
! 1607:
! 1608: SLIST_INIT(&cd->atu_tx_free);
! 1609: sc->atu_cdata.atu_tx_inuse = 0;
! 1610:
! 1611: for (i = 0; i < ATU_TX_LIST_CNT; i++) {
! 1612: c = &cd->atu_tx_chain[i];
! 1613: c->atu_sc = sc;
! 1614: c->atu_idx = i;
! 1615: if (c->atu_xfer == NULL) {
! 1616: c->atu_xfer = usbd_alloc_xfer(sc->atu_udev);
! 1617: if (c->atu_xfer == NULL)
! 1618: return(ENOBUFS);
! 1619: c->atu_mbuf = NULL;
! 1620: c->atu_buf = usbd_alloc_buffer(c->atu_xfer,
! 1621: ATU_TX_BUFSZ);
! 1622: if (c->atu_buf == NULL)
! 1623: return(ENOBUFS); /* XXX free xfer */
! 1624: SLIST_INSERT_HEAD(&cd->atu_tx_free, c, atu_list);
! 1625: }
! 1626: }
! 1627: return(0);
! 1628: }
! 1629:
! 1630: void
! 1631: atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch,
! 1632: int listlen)
! 1633: {
! 1634: int i;
! 1635:
! 1636: /* Free resources. */
! 1637: for (i = 0; i < listlen; i++) {
! 1638: if (ch[i].atu_buf != NULL)
! 1639: ch[i].atu_buf = NULL;
! 1640: if (ch[i].atu_mbuf != NULL) {
! 1641: m_freem(ch[i].atu_mbuf);
! 1642: ch[i].atu_mbuf = NULL;
! 1643: }
! 1644: if (ch[i].atu_xfer != NULL) {
! 1645: usbd_free_xfer(ch[i].atu_xfer);
! 1646: ch[i].atu_xfer = NULL;
! 1647: }
! 1648: }
! 1649: }
! 1650:
! 1651: /*
! 1652: * A frame has been uploaded: pass the resulting mbuf chain up to
! 1653: * the higher level protocols.
! 1654: */
! 1655: void
! 1656: atu_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1657: {
! 1658: struct atu_chain *c = (struct atu_chain *)priv;
! 1659: struct atu_softc *sc = c->atu_sc;
! 1660: struct ieee80211com *ic = &sc->sc_ic;
! 1661: struct ifnet *ifp = &ic->ic_if;
! 1662: struct atu_rx_hdr *h;
! 1663: struct ieee80211_frame *wh;
! 1664: struct ieee80211_node *ni;
! 1665: struct mbuf *m;
! 1666: u_int32_t len;
! 1667: int s;
! 1668:
! 1669: DPRINTFN(25, ("%s: atu_rxeof\n", sc->atu_dev.dv_xname));
! 1670:
! 1671: if (sc->sc_state != ATU_S_OK)
! 1672: return;
! 1673:
! 1674: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
! 1675: goto done;
! 1676:
! 1677: if (status != USBD_NORMAL_COMPLETION) {
! 1678: DPRINTF(("%s: status != USBD_NORMAL_COMPLETION\n",
! 1679: sc->atu_dev.dv_xname));
! 1680: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
! 1681: return;
! 1682: }
! 1683: #if 0
! 1684: if (status == USBD_IOERROR) {
! 1685: DPRINTF(("%s: rx: EEK! lost device?\n",
! 1686: sc->atu_dev.dv_xname));
! 1687:
! 1688: /*
! 1689: * My experience with USBD_IOERROR is that trying to
! 1690: * restart the transfer will always fail and we'll
! 1691: * keep on looping restarting transfers untill someone
! 1692: * pulls the plug of the device.
! 1693: * So we don't restart the transfer, but just let it
! 1694: * die... If someone knows of a situation where we can
! 1695: * recover from USBD_IOERROR, let me know.
! 1696: */
! 1697: splx(s);
! 1698: return;
! 1699: }
! 1700: #endif /* 0 */
! 1701:
! 1702: if (usbd_ratecheck(&sc->atu_rx_notice)) {
! 1703: DPRINTF(("%s: usb error on rx: %s\n",
! 1704: sc->atu_dev.dv_xname, usbd_errstr(status)));
! 1705: }
! 1706: if (status == USBD_STALLED)
! 1707: usbd_clear_endpoint_stall_async(
! 1708: sc->atu_ep[ATU_ENDPT_RX]);
! 1709: goto done;
! 1710: }
! 1711:
! 1712: usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
! 1713:
! 1714: if (len <= 1) {
! 1715: DPRINTF(("%s: atu_rxeof: too short\n",
! 1716: sc->atu_dev.dv_xname));
! 1717: goto done;
! 1718: }
! 1719:
! 1720: h = (struct atu_rx_hdr *)c->atu_buf;
! 1721: len = UGETW(h->length) - 4; /* XXX magic number */
! 1722:
! 1723: m = c->atu_mbuf;
! 1724: memcpy(mtod(m, char *), c->atu_buf + ATU_RX_HDRLEN, len);
! 1725: m->m_pkthdr.rcvif = ifp;
! 1726: m->m_pkthdr.len = m->m_len = len;
! 1727:
! 1728: wh = mtod(m, struct ieee80211_frame *);
! 1729: ni = ieee80211_find_rxnode(ic, wh);
! 1730:
! 1731: ifp->if_ipackets++;
! 1732:
! 1733: s = splnet();
! 1734:
! 1735: if (atu_newbuf(sc, c, NULL) == ENOBUFS) {
! 1736: ifp->if_ierrors++;
! 1737: goto done1; /* XXX if we can't allocate, why restart it? */
! 1738: }
! 1739:
! 1740: #if NBPFILTER > 0
! 1741: if (sc->sc_radiobpf != NULL) {
! 1742: struct mbuf mb;
! 1743: struct atu_rx_radiotap_header *rr = &sc->sc_rxtap;
! 1744:
! 1745: rr->rr_flags = 0;
! 1746: rr->rr_chan_freq =
! 1747: htole16(ic->ic_bss->ni_chan->ic_freq);
! 1748: rr->rr_chan_flags =
! 1749: htole16(ic->ic_bss->ni_chan->ic_flags);
! 1750: rr->rr_rssi = h->rssi;
! 1751: rr->rr_max_rssi = ic->ic_max_rssi;
! 1752:
! 1753: mb.m_data = (caddr_t)rr;
! 1754: mb.m_len = sizeof(sc->sc_txtapu);
! 1755: mb.m_next = m;
! 1756: mb.m_nextpkt = NULL;
! 1757: mb.m_type = 0;
! 1758: mb.m_flags = 0;
! 1759: bpf_mtap(sc->sc_radiobpf, &mb, BPF_DIRECTION_IN);
! 1760: }
! 1761: #endif /* NPBFILTER > 0 */
! 1762:
! 1763: if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
! 1764: /*
! 1765: * WEP is decrypted by hardware. Clear WEP bit
! 1766: * header for ieee80211_input().
! 1767: */
! 1768: wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
! 1769: }
! 1770:
! 1771: ieee80211_input(ifp, m, ni, h->rssi, UGETDW(h->rx_time));
! 1772:
! 1773: ieee80211_release_node(ic, ni);
! 1774: done1:
! 1775: splx(s);
! 1776: done:
! 1777: /* Setup new transfer. */
! 1778: usbd_setup_xfer(c->atu_xfer, sc->atu_ep[ATU_ENDPT_RX], c, c->atu_buf,
! 1779: ATU_RX_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
! 1780: atu_rxeof);
! 1781: usbd_transfer(c->atu_xfer);
! 1782: }
! 1783:
! 1784: /*
! 1785: * A frame was downloaded to the chip. It's safe for us to clean up
! 1786: * the list buffers.
! 1787: */
! 1788: void
! 1789: atu_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1790: {
! 1791: struct atu_chain *c = (struct atu_chain *)priv;
! 1792: struct atu_softc *sc = c->atu_sc;
! 1793: struct ifnet *ifp = &sc->sc_ic.ic_if;
! 1794: usbd_status err;
! 1795: int s;
! 1796:
! 1797: DPRINTFN(25, ("%s: atu_txeof status=%d\n", sc->atu_dev.dv_xname,
! 1798: status));
! 1799:
! 1800: if (c->atu_mbuf != NULL) {
! 1801: m_freem(c->atu_mbuf);
! 1802: c->atu_mbuf = NULL;
! 1803: }
! 1804:
! 1805: if (status != USBD_NORMAL_COMPLETION) {
! 1806: if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
! 1807: return;
! 1808:
! 1809: DPRINTF(("%s: usb error on tx: %s\n", sc->atu_dev.dv_xname,
! 1810: usbd_errstr(status)));
! 1811: if (status == USBD_STALLED)
! 1812: usbd_clear_endpoint_stall_async(sc->atu_ep[ATU_ENDPT_TX]);
! 1813: return;
! 1814: }
! 1815:
! 1816: usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err);
! 1817:
! 1818: if (err)
! 1819: ifp->if_oerrors++;
! 1820: else
! 1821: ifp->if_opackets++;
! 1822:
! 1823: s = splnet();
! 1824: SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list);
! 1825: sc->atu_cdata.atu_tx_inuse--;
! 1826: if (sc->atu_cdata.atu_tx_inuse == 0)
! 1827: ifp->if_timer = 0;
! 1828: ifp->if_flags &= ~IFF_OACTIVE;
! 1829: splx(s);
! 1830:
! 1831: atu_start(ifp);
! 1832: }
! 1833:
! 1834: u_int8_t
! 1835: atu_calculate_padding(int size)
! 1836: {
! 1837: size %= 64;
! 1838:
! 1839: if (size < 50)
! 1840: return (50 - size);
! 1841: if (size >=61)
! 1842: return (64 + 50 - size);
! 1843: return (0);
! 1844: }
! 1845:
! 1846: int
! 1847: atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni,
! 1848: struct atu_chain *c, struct mbuf *m)
! 1849: {
! 1850: int len;
! 1851: struct atu_tx_hdr *h;
! 1852: usbd_status err;
! 1853: u_int8_t pad;
! 1854: #if NBPFILTER > 0
! 1855: struct ieee80211com *ic = &sc->sc_ic;
! 1856: #endif
! 1857:
! 1858: DPRINTFN(25, ("%s: atu_tx_start\n", sc->atu_dev.dv_xname));
! 1859:
! 1860: /* Don't try to send when we're shutting down the driver */
! 1861: if (sc->sc_state != ATU_S_OK) {
! 1862: m_freem(m);
! 1863: return(EIO);
! 1864: }
! 1865:
! 1866: #if NBPFILTER > 0
! 1867: if (sc->sc_radiobpf != NULL) {
! 1868: struct mbuf mb;
! 1869: struct atu_tx_radiotap_header *rt = &sc->sc_txtap;
! 1870:
! 1871: rt->rt_flags = 0;
! 1872: rt->rt_chan_freq =
! 1873: htole16(ic->ic_bss->ni_chan->ic_freq);
! 1874: rt->rt_chan_flags =
! 1875: htole16(ic->ic_bss->ni_chan->ic_flags);
! 1876:
! 1877: mb.m_data = (caddr_t)rt;
! 1878: mb.m_len = sizeof(sc->sc_txtapu);
! 1879: mb.m_next = m;
! 1880: mb.m_nextpkt = NULL;
! 1881: mb.m_type = 0;
! 1882: mb.m_flags = 0;
! 1883: bpf_mtap(sc->sc_radiobpf, &mb, BPF_DIRECTION_OUT);
! 1884: }
! 1885: #endif
! 1886:
! 1887: /*
! 1888: * Copy the mbuf data into a contiguous buffer, leaving
! 1889: * enough room for the atmel headers
! 1890: */
! 1891: len = m->m_pkthdr.len;
! 1892:
! 1893: m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN);
! 1894:
! 1895: h = (struct atu_tx_hdr *)c->atu_buf;
! 1896: memset(h, 0, ATU_TX_HDRLEN);
! 1897: USETW(h->length, len);
! 1898: h->tx_rate = 4; /* XXX rate = auto */
! 1899: len += ATU_TX_HDRLEN;
! 1900:
! 1901: pad = atu_calculate_padding(len);
! 1902: len += pad;
! 1903: h->padding = pad;
! 1904:
! 1905: c->atu_length = len;
! 1906: c->atu_mbuf = m;
! 1907:
! 1908: usbd_setup_xfer(c->atu_xfer, sc->atu_ep[ATU_ENDPT_TX],
! 1909: c, c->atu_buf, c->atu_length, USBD_NO_COPY, ATU_TX_TIMEOUT,
! 1910: atu_txeof);
! 1911:
! 1912: /* Let's get this thing into the air! */
! 1913: c->atu_in_xfer = 1;
! 1914: err = usbd_transfer(c->atu_xfer);
! 1915: if (err != USBD_IN_PROGRESS) {
! 1916: DPRINTFN(25, ("%s: atu_tx_start: err=%d\n",
! 1917: sc->atu_dev.dv_xname, err));
! 1918: c->atu_mbuf = NULL;
! 1919: m_freem(m);
! 1920: return(EIO);
! 1921: }
! 1922:
! 1923: return (0);
! 1924: }
! 1925:
! 1926: void
! 1927: atu_start(struct ifnet *ifp)
! 1928: {
! 1929: struct atu_softc *sc = ifp->if_softc;
! 1930: struct ieee80211com *ic = &sc->sc_ic;
! 1931: struct atu_cdata *cd = &sc->atu_cdata;
! 1932: struct ieee80211_node *ni;
! 1933: struct ieee80211_frame *wh;
! 1934: struct atu_chain *c;
! 1935: struct mbuf *m = NULL;
! 1936: int s;
! 1937:
! 1938: DPRINTFN(25, ("%s: atu_start: enter\n", sc->atu_dev.dv_xname));
! 1939:
! 1940: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) {
! 1941: DPRINTFN(30, ("%s: atu_start: not running or up\n",
! 1942: sc->atu_dev.dv_xname));
! 1943: return;
! 1944: }
! 1945:
! 1946: if (ifp->if_flags & IFF_OACTIVE) {
! 1947: DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n",
! 1948: sc->atu_dev.dv_xname));
! 1949: return;
! 1950: }
! 1951:
! 1952: for (;;) {
! 1953: /* grab a TX buffer */
! 1954: s = splnet();
! 1955: c = SLIST_FIRST(&cd->atu_tx_free);
! 1956: if (c != NULL) {
! 1957: SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list);
! 1958: cd->atu_tx_inuse++;
! 1959: if (cd->atu_tx_inuse == ATU_TX_LIST_CNT)
! 1960: ifp->if_flags |= IFF_OACTIVE;
! 1961: }
! 1962: splx(s);
! 1963: if (c == NULL) {
! 1964: DPRINTFN(10, ("%s: out of tx xfers\n",
! 1965: sc->atu_dev.dv_xname));
! 1966: ifp->if_flags |= IFF_OACTIVE;
! 1967: break;
! 1968: }
! 1969:
! 1970: /*
! 1971: * Poll the management queue for frames, it has priority over
! 1972: * normal data frames.
! 1973: */
! 1974: IF_DEQUEUE(&ic->ic_mgtq, m);
! 1975: if (m == NULL) {
! 1976: DPRINTFN(10, ("%s: atu_start: data packet\n",
! 1977: sc->atu_dev.dv_xname));
! 1978: if (ic->ic_state != IEEE80211_S_RUN) {
! 1979: DPRINTFN(25, ("%s: no data till running\n",
! 1980: sc->atu_dev.dv_xname));
! 1981: /* put the xfer back on the list */
! 1982: s = splnet();
! 1983: SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
! 1984: atu_list);
! 1985: cd->atu_tx_inuse--;
! 1986: splx(s);
! 1987: break;
! 1988: }
! 1989:
! 1990: IFQ_DEQUEUE(&ifp->if_snd, m);
! 1991: if (m == NULL) {
! 1992: DPRINTFN(25, ("%s: nothing to send\n",
! 1993: sc->atu_dev.dv_xname));
! 1994: s = splnet();
! 1995: SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
! 1996: atu_list);
! 1997: cd->atu_tx_inuse--;
! 1998: splx(s);
! 1999: break;
! 2000: }
! 2001:
! 2002: #if NBPFILTER > 0
! 2003: if (ifp->if_bpf)
! 2004: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 2005: #endif
! 2006:
! 2007: m = ieee80211_encap(ifp, m, &ni);
! 2008: if (m == NULL)
! 2009: goto bad;
! 2010: wh = mtod(m, struct ieee80211_frame *);
! 2011:
! 2012: #if NBPFILTER > 0
! 2013: if (ic->ic_rawbpf != NULL)
! 2014: bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
! 2015: #endif
! 2016: } else {
! 2017: DPRINTFN(25, ("%s: atu_start: mgmt packet\n",
! 2018: sc->atu_dev.dv_xname));
! 2019:
! 2020: /*
! 2021: * Hack! The referenced node pointer is in the
! 2022: * rcvif field of the packet header. This is
! 2023: * placed there by ieee80211_mgmt_output because
! 2024: * we need to hold the reference with the frame
! 2025: * and there's no other way (other than packet
! 2026: * tags which we consider too expensive to use)
! 2027: * to pass it along.
! 2028: */
! 2029: ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
! 2030: m->m_pkthdr.rcvif = NULL;
! 2031:
! 2032: wh = mtod(m, struct ieee80211_frame *);
! 2033: /* sc->sc_stats.ast_tx_mgmt++; */
! 2034: }
! 2035:
! 2036: if (atu_tx_start(sc, ni, c, m)) {
! 2037: bad:
! 2038: s = splnet();
! 2039: SLIST_INSERT_HEAD(&cd->atu_tx_free, c,
! 2040: atu_list);
! 2041: cd->atu_tx_inuse--;
! 2042: splx(s);
! 2043: /* ifp_if_oerrors++; */
! 2044: if (ni != NULL)
! 2045: ieee80211_release_node(ic, ni);
! 2046: continue;
! 2047: }
! 2048: ifp->if_timer = 5;
! 2049: }
! 2050: }
! 2051:
! 2052: int
! 2053: atu_init(struct ifnet *ifp)
! 2054: {
! 2055: struct atu_softc *sc = ifp->if_softc;
! 2056: struct ieee80211com *ic = &sc->sc_ic;
! 2057: struct atu_chain *c;
! 2058: usbd_status err;
! 2059: int i, s;
! 2060:
! 2061: s = splnet();
! 2062:
! 2063: DPRINTFN(10, ("%s: atu_init\n", sc->atu_dev.dv_xname));
! 2064:
! 2065: if (ifp->if_flags & IFF_RUNNING) {
! 2066: splx(s);
! 2067: return(0);
! 2068: }
! 2069:
! 2070: /* Init TX ring */
! 2071: if (atu_tx_list_init(sc))
! 2072: printf("%s: tx list init failed\n", sc->atu_dev.dv_xname);
! 2073:
! 2074: /* Init RX ring */
! 2075: if (atu_rx_list_init(sc))
! 2076: printf("%s: rx list init failed\n", sc->atu_dev.dv_xname);
! 2077:
! 2078: /* Load the multicast filter. */
! 2079: /*atu_setmulti(sc); */
! 2080:
! 2081: /* Open RX and TX pipes. */
! 2082: err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_RX],
! 2083: USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_RX]);
! 2084: if (err) {
! 2085: DPRINTF(("%s: open rx pipe failed: %s\n",
! 2086: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2087: splx(s);
! 2088: return(EIO);
! 2089: }
! 2090:
! 2091: err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_TX],
! 2092: USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_TX]);
! 2093: if (err) {
! 2094: DPRINTF(("%s: open tx pipe failed: %s\n",
! 2095: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2096: splx(s);
! 2097: return(EIO);
! 2098: }
! 2099:
! 2100: /* Start up the receive pipe. */
! 2101: for (i = 0; i < ATU_RX_LIST_CNT; i++) {
! 2102: c = &sc->atu_cdata.atu_rx_chain[i];
! 2103:
! 2104: usbd_setup_xfer(c->atu_xfer, sc->atu_ep[ATU_ENDPT_RX], c,
! 2105: c->atu_buf, ATU_RX_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
! 2106: USBD_NO_TIMEOUT, atu_rxeof);
! 2107: usbd_transfer(c->atu_xfer);
! 2108: }
! 2109:
! 2110: DPRINTFN(10, ("%s: starting up using MAC=%s\n",
! 2111: sc->atu_dev.dv_xname, ether_sprintf(ic->ic_myaddr)));
! 2112:
! 2113: /* Do initial setup */
! 2114: err = atu_initial_config(sc);
! 2115: if (err) {
! 2116: DPRINTF(("%s: initial config failed!\n",
! 2117: sc->atu_dev.dv_xname));
! 2118: splx(s);
! 2119: return(EIO);
! 2120: }
! 2121: DPRINTFN(10, ("%s: initialised transceiver\n",
! 2122: sc->atu_dev.dv_xname));
! 2123:
! 2124: /* sc->atu_rxfilt = ATU_RXFILT_UNICAST|ATU_RXFILT_BROADCAST; */
! 2125:
! 2126: /* If we want promiscuous mode, set the allframes bit. */
! 2127: /*
! 2128: if (ifp->if_flags & IFF_PROMISC)
! 2129: sc->atu_rxfilt |= ATU_RXFILT_PROMISC;
! 2130: */
! 2131:
! 2132: ifp->if_flags |= IFF_RUNNING;
! 2133: ifp->if_flags &= ~IFF_OACTIVE;
! 2134: splx(s);
! 2135:
! 2136: /* XXX the following HAS to be replaced */
! 2137: s = splnet();
! 2138: err = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 2139: if (err)
! 2140: DPRINTFN(1, ("%s: atu_init: error calling "
! 2141: "ieee80211_net_state", sc->atu_dev.dv_xname));
! 2142: splx(s);
! 2143:
! 2144: return 0;
! 2145: }
! 2146:
! 2147: int
! 2148: atu_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 2149: {
! 2150: struct atu_softc *sc = ifp->if_softc;
! 2151: struct ifaddr *ifa;
! 2152: int err = 0, s;
! 2153:
! 2154: s = splnet();
! 2155: switch (command) {
! 2156: case SIOCSIFADDR:
! 2157: DPRINTFN(15, ("%s: SIOCSIFADDR\n", sc->atu_dev.dv_xname));
! 2158:
! 2159: ifa = (struct ifaddr *)data;
! 2160: ifp->if_flags |= IFF_UP;
! 2161: atu_init(ifp);
! 2162:
! 2163: switch (ifa->ifa_addr->sa_family) {
! 2164: #ifdef INET
! 2165: case AF_INET:
! 2166: arp_ifinit(&sc->sc_ic.ic_ac, ifa);
! 2167: break;
! 2168: #endif /* INET */
! 2169: }
! 2170: break;
! 2171:
! 2172: case SIOCSIFFLAGS:
! 2173: DPRINTFN(15, ("%s: SIOCSIFFLAGS\n", sc->atu_dev.dv_xname));
! 2174:
! 2175: if (ifp->if_flags & IFF_UP) {
! 2176: if (ifp->if_flags & IFF_RUNNING &&
! 2177: ifp->if_flags & IFF_PROMISC &&
! 2178: !(sc->atu_if_flags & IFF_PROMISC)) {
! 2179: /* enable promisc */
! 2180: #if 0
! 2181: sc->atu_rxfilt |= ATU_RXFILT_PROMISC;
! 2182: atu_setword(sc, ATU_CMD_SET_PKT_FILTER,
! 2183: sc->atu_rxfilt);
! 2184: #endif
! 2185: } else if (ifp->if_flags & IFF_RUNNING &&
! 2186: !(ifp->if_flags & IFF_PROMISC) &&
! 2187: sc->atu_if_flags & IFF_PROMISC) {
! 2188: /* disable promisc */
! 2189: #if 0
! 2190: sc->atu_rxfilt &= ~ATU_RXFILT_PROMISC;
! 2191: atu_setword(sc, ATU_CMD_SET_PKT_FILTER,
! 2192: sc->atu_rxfilt);
! 2193: #endif
! 2194: } else if (!(ifp->if_flags & IFF_RUNNING))
! 2195: atu_init(ifp);
! 2196:
! 2197: DPRINTFN(15, ("%s: ioctl calling atu_init()\n",
! 2198: sc->atu_dev.dv_xname));
! 2199: atu_init(ifp);
! 2200: err = atu_switch_radio(sc, 1);
! 2201: } else {
! 2202: if (ifp->if_flags & IFF_RUNNING)
! 2203: atu_stop(ifp, 0);
! 2204: err = atu_switch_radio(sc, 0);
! 2205: }
! 2206: sc->atu_if_flags = ifp->if_flags;
! 2207: err = 0;
! 2208: break;
! 2209:
! 2210: case SIOCADDMULTI:
! 2211: DPRINTFN(15, ("%s: SIOCADDMULTI\n", sc->atu_dev.dv_xname));
! 2212: /* TODO: implement */
! 2213: err = 0;
! 2214: break;
! 2215:
! 2216: case SIOCDELMULTI:
! 2217: DPRINTFN(15, ("%s: SIOCDELMULTI\n", sc->atu_dev.dv_xname));
! 2218: /* TODO: implement */
! 2219: err = 0;
! 2220: break;
! 2221:
! 2222: default:
! 2223: DPRINTFN(15, ("%s: ieee80211_ioctl (%lu)\n",
! 2224: sc->atu_dev.dv_xname, command));
! 2225: err = ieee80211_ioctl(ifp, command, data);
! 2226: break;
! 2227: }
! 2228:
! 2229: if (err == ENETRESET) {
! 2230: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) ==
! 2231: (IFF_RUNNING|IFF_UP)) {
! 2232: DPRINTF(("%s: atu_ioctl(): netreset\n",
! 2233: sc->atu_dev.dv_xname));
! 2234: atu_init(ifp);
! 2235: }
! 2236: err = 0;
! 2237: }
! 2238:
! 2239: splx(s);
! 2240: return (err);
! 2241: }
! 2242:
! 2243: void
! 2244: atu_watchdog(struct ifnet *ifp)
! 2245: {
! 2246: struct atu_softc *sc = ifp->if_softc;
! 2247: struct atu_chain *c;
! 2248: usbd_status stat;
! 2249: int cnt, s;
! 2250:
! 2251: DPRINTF(("%s: atu_watchdog\n", sc->atu_dev.dv_xname));
! 2252:
! 2253: ifp->if_timer = 0;
! 2254:
! 2255: if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
! 2256: return;
! 2257:
! 2258: if (sc->sc_state != ATU_S_OK)
! 2259: return;
! 2260:
! 2261: sc = ifp->if_softc;
! 2262: s = splnet();
! 2263: ifp->if_oerrors++;
! 2264: DPRINTF(("%s: watchdog timeout\n", sc->atu_dev.dv_xname));
! 2265:
! 2266: /*
! 2267: * TODO:
! 2268: * we should change this since we have multiple TX transfers...
! 2269: */
! 2270: for (cnt = 0; cnt < ATU_TX_LIST_CNT; cnt++) {
! 2271: c = &sc->atu_cdata.atu_tx_chain[cnt];
! 2272: if (c->atu_in_xfer) {
! 2273: usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL,
! 2274: &stat);
! 2275: atu_txeof(c->atu_xfer, c, stat);
! 2276: }
! 2277: }
! 2278:
! 2279: if (!IFQ_IS_EMPTY(&ifp->if_snd))
! 2280: atu_start(ifp);
! 2281: splx(s);
! 2282:
! 2283: ieee80211_watchdog(ifp);
! 2284: }
! 2285:
! 2286: /*
! 2287: * Stop the adapter and free any mbufs allocated to the
! 2288: * RX and TX lists.
! 2289: */
! 2290: void
! 2291: atu_stop(struct ifnet *ifp, int disable)
! 2292: {
! 2293: struct atu_softc *sc = ifp->if_softc;
! 2294: struct atu_cdata *cd;
! 2295: usbd_status err;
! 2296: int s;
! 2297:
! 2298: s = splnet();
! 2299: ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
! 2300: ifp->if_timer = 0;
! 2301:
! 2302: /* Stop transfers. */
! 2303: if (sc->atu_ep[ATU_ENDPT_RX] != NULL) {
! 2304: err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
! 2305: if (err) {
! 2306: DPRINTF(("%s: abort rx pipe failed: %s\n",
! 2307: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2308: }
! 2309: err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]);
! 2310: if (err) {
! 2311: DPRINTF(("%s: close rx pipe failed: %s\n",
! 2312: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2313: }
! 2314: sc->atu_ep[ATU_ENDPT_RX] = NULL;
! 2315: }
! 2316:
! 2317: if (sc->atu_ep[ATU_ENDPT_TX] != NULL) {
! 2318: err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
! 2319: if (err) {
! 2320: DPRINTF(("%s: abort tx pipe failed: %s\n",
! 2321: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2322: }
! 2323: err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]);
! 2324: if (err) {
! 2325: DPRINTF(("%s: close tx pipe failed: %s\n",
! 2326: sc->atu_dev.dv_xname, usbd_errstr(err)));
! 2327: }
! 2328: sc->atu_ep[ATU_ENDPT_TX] = NULL;
! 2329: }
! 2330:
! 2331: /* Free RX/TX/MGMT list resources. */
! 2332: cd = &sc->atu_cdata;
! 2333: atu_xfer_list_free(sc, cd->atu_rx_chain, ATU_RX_LIST_CNT);
! 2334: atu_xfer_list_free(sc, cd->atu_tx_chain, ATU_TX_LIST_CNT);
! 2335:
! 2336: /* Let's be nice and turn off the radio before we leave */
! 2337: atu_switch_radio(sc, 0);
! 2338:
! 2339: splx(s);
! 2340: }
CVSweb