Module Name: src Committed By: aymeric Date: Thu May 9 12:44:31 UTC 2013
Modified Files: src/sys/dev/usb: aubtfwl.c Added Files: src/sys/dev/usb: aubtfwlreg.h Log Message: . add support for loading code + config of AR3012 based chips . make it easy to add vendor and product ids for similar hardware To generate a diff of this commit: cvs rdiff -u -r1.4 -r1.5 src/sys/dev/usb/aubtfwl.c cvs rdiff -u -r0 -r1.1 src/sys/dev/usb/aubtfwlreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/aubtfwl.c diff -u src/sys/dev/usb/aubtfwl.c:1.4 src/sys/dev/usb/aubtfwl.c:1.5 --- src/sys/dev/usb/aubtfwl.c:1.4 Thu Dec 27 16:42:32 2012 +++ src/sys/dev/usb/aubtfwl.c Thu May 9 12:44:31 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: aubtfwl.c,v 1.4 2012/12/27 16:42:32 skrll Exp $ */ +/* $NetBSD: aubtfwl.c,v 1.5 2013/05/09 12:44:31 aymeric Exp $ */ /* * Copyright (c) 2011 Jonathan A. Kollasch @@ -27,16 +27,18 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: aubtfwl.c,v 1.4 2012/12/27 16:42:32 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: aubtfwl.c,v 1.5 2013/05/09 12:44:31 aymeric Exp $"); #include <sys/param.h> #include <dev/usb/usb.h> #include <dev/usb/usbdevs.h> #include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> #include <dev/usb/usbdi_util.h> #include <dev/firmload.h> -#define AR3K_FIRMWARE_HEADER_SIZE 20 +#include <dev/usb/aubtfwlreg.h> + #define AR3K_FIRMWARE_CHUNK_SIZE 4096 static int aubtfwl_match(device_t, cfdata_t, void *); @@ -46,19 +48,33 @@ static void aubtfwl_attach_hook(device_t struct aubtfwl_softc { usbd_device_handle sc_udev; + int sc_flags; +#define AUBT_IS_AR3012 1 }; CFATTACH_DECL_NEW(aubtfwl, sizeof(struct aubtfwl_softc), aubtfwl_match, aubtfwl_attach, aubtfwl_detach, NULL); +static const struct usb_devno ar3k_devs[] = { + { USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR3011 }, +}; + +static const struct usb_devno ar3k12_devs[] = { + { USB_VENDOR_FOXCONN, USB_PRODUCT_FOXCONN_AR3012 }, +}; + static int aubtfwl_match(device_t parent, cfdata_t match, void *aux) { const struct usb_attach_arg * const uaa = aux; - if (uaa->vendor == USB_VENDOR_ATHEROS2 && - uaa->product == USB_PRODUCT_ATHEROS2_AR3011) + if (usb_lookup(ar3k_devs, uaa->vendor, uaa->product)) return UMATCH_VENDOR_PRODUCT; + if (usb_lookup(ar3k12_devs, uaa->vendor, uaa->product)) { + return (UGETW(uaa->device->ddesc.bcdDevice) > 1)? + UMATCH_NONE : UMATCH_VENDOR_PRODUCT; + } + return UMATCH_NONE; } @@ -70,6 +86,10 @@ aubtfwl_attach(device_t parent, device_t aprint_naive("\n"); aprint_normal("\n"); sc->sc_udev = uaa->device; + sc->sc_flags = 0; + + if (usb_lookup(ar3k12_devs, uaa->vendor, uaa->product)) + sc->sc_flags |= AUBT_IS_AR3012; config_mountroot(self, aubtfwl_attach_hook); } @@ -84,27 +104,27 @@ aubtfwl_detach(device_t self, int flags) return 0; } -static void -aubtfwl_attach_hook(device_t self) -{ +/* Returns 0 if firmware was correctly loaded */ +static int +aubtfwl_firmware_load(device_t self, const char *name) { struct aubtfwl_softc * const sc = device_private(self); usbd_interface_handle iface; usbd_pipe_handle pipe; usbd_xfer_handle xfer; void *buf; usb_device_request_t req; - int error; + int error = 0; firmware_handle_t fwh; size_t fws; size_t fwo = 0; uint32_t n; - - memset(&req, 0, sizeof(req)); - error = firmware_open("ubt", "ath3k-1.fw", &fwh); /* XXX revisit name */ + memset(&req, 0, sizeof req); + + error = firmware_open("ubt", name, &fwh); if (error != 0) { - aprint_error_dev(self, "ath3k-1.fw open fail %d\n", error); - return; + aprint_error_dev(self, "'%s' open fail %d\n", name, error); + return error; } fws = firmware_get_size(fwh); @@ -132,12 +152,14 @@ aubtfwl_attach_hook(device_t self) xfer = usbd_alloc_xfer(sc->sc_udev); if (xfer == NULL) { aprint_error_dev(self, "failed to alloc xfer\n"); + error = 1; goto out_pipe; } - buf = usbd_alloc_buffer(xfer, 4096); + buf = usbd_alloc_buffer(xfer, AR3K_FIRMWARE_CHUNK_SIZE); if (buf == NULL) { aprint_error_dev(self, "failed to alloc buffer\n"); + error = 1; goto out_xfer; } @@ -147,7 +169,7 @@ aubtfwl_attach_hook(device_t self) goto out_xfer; } - req.bRequest = 1; + req.bRequest = AR3K_SEND_FIRMWARE; req.bmRequestType = UT_WRITE_VENDOR_DEVICE; USETW(req.wValue, 0); USETW(req.wIndex, 0); @@ -158,7 +180,7 @@ aubtfwl_attach_hook(device_t self) error = usbd_do_request(sc->sc_udev, &req, buf); if (error != 0) { aprint_error_dev(self, "%s\n", usbd_errstr(error)); - return; + return error; } fwo = AR3K_FIRMWARE_HEADER_SIZE; @@ -166,7 +188,7 @@ aubtfwl_attach_hook(device_t self) n = min(AR3K_FIRMWARE_CHUNK_SIZE, fws - fwo); error = firmware_read(fwh, fwo, buf, n); if (error != 0) { - break;; + break; } error = usbd_bulk_transfer(xfer, pipe, USBD_NO_COPY, USBD_DEFAULT_TIMEOUT, @@ -174,11 +196,13 @@ aubtfwl_attach_hook(device_t self) if (error != USBD_NORMAL_COMPLETION) { aprint_error_dev(self, "xfer failed, %s\n", usbd_errstr(error)); - break;; + break; } fwo += n; } - aprint_verbose_dev(self, "firmware load complete\n"); + + if (error == 0) + aprint_verbose_dev(self, "firmware load complete\n"); out_xfer: usbd_free_xfer(xfer); @@ -187,5 +211,133 @@ out_pipe: out_firmware: firmware_close(fwh); + return !!error; +} + +static int +aubtfwl_get_state(struct aubtfwl_softc *sc, uint8_t *state) { + usb_device_request_t req; + int error = 0; + + memset(&req, 0, sizeof req); + + req.bRequest = AR3K_GET_STATE; + req.bmRequestType = UT_READ_VENDOR_DEVICE; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, sizeof *state); + + error = usbd_do_request(sc->sc_udev, &req, state); + + return error; +} + +static int +aubtfwl_get_version(struct aubtfwl_softc *sc, struct ar3k_version *ver) { + usb_device_request_t req; + int error = 0; + + memset(&req, 0, sizeof req); + + req.bRequest = AR3K_GET_VERSION; + req.bmRequestType = UT_READ_VENDOR_DEVICE; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, sizeof *ver); + + error = usbd_do_request(sc->sc_udev, &req, ver); + +#if BYTE_ORDER == BIG_ENDIAN + if (error == USBD_NORMAL_COMPLETION) { + ver->rom = bswap32(ver->rom); + ver->build = bswap32(ver->build); + ver->ram = bswap32(ver->ram); + } +#endif + return error; +} + +static int +aubtfwl_send_command(struct aubtfwl_softc *sc, uByte cmd) { + usb_device_request_t req; + int error = 0; + + memset(&req, 0, sizeof req); + + req.bRequest = cmd; + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + USETW(req.wValue, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, 0); + + error = usbd_do_request(sc->sc_udev, &req, NULL); + + return error; +} + +static void +aubtfwl_attach_hook(device_t self) +{ + struct aubtfwl_softc * const sc = device_private(self); + char firmware_name[MAXPATHLEN+1]; + struct ar3k_version ver; + uint8_t state; + int clock = 0; + int error = 0; + + if (sc->sc_flags & AUBT_IS_AR3012) { + error = aubtfwl_get_version(sc, &ver); + if (!error) + error = aubtfwl_get_state(sc, &state); + + if (error) { + aprint_error_dev(self, + "couldn't get version or state\n"); + return; + } + + aprint_verbose_dev(self, "state is 0x%02x\n", state); + + if (!(state & AR3K_STATE_IS_PATCHED)) { + snprintf(firmware_name, sizeof firmware_name, + "ar3k/AthrBT_0x%08x.dfu", ver.rom); + error = aubtfwl_firmware_load(self, firmware_name); + + if (error) + return; + } + + switch (ver.clock) { + case AR3K_CLOCK_19M: + clock = 19; + break; + case AR3K_CLOCK_26M: + clock = 26; + break; + case AR3K_CLOCK_40M: + clock = 40; + break; + } + + snprintf(firmware_name, sizeof firmware_name, + "ar3k/ramps_0x%08x_%d.dfu", ver.rom, clock); + aubtfwl_firmware_load(self, firmware_name); + + if ((state & AR3K_STATE_MODE_MASK) != AR3K_STATE_MODE_NORMAL) { + error = aubtfwl_send_command(sc, AR3K_SET_NORMAL_MODE); + if (error) { + aprint_error_dev(self, + "couldn't set normal mode: %s", + usbd_errstr(error)); + return; + } + } + + /* Apparently some devices will fail this, so ignore result */ + (void) aubtfwl_send_command(sc, AR3K_SWITCH_VID_PID); + } else { + aubtfwl_firmware_load(self, "ath3k-1.fw"); + } + return; } Added files: Index: src/sys/dev/usb/aubtfwlreg.h diff -u /dev/null src/sys/dev/usb/aubtfwlreg.h:1.1 --- /dev/null Thu May 9 12:44:31 2013 +++ src/sys/dev/usb/aubtfwlreg.h Thu May 9 12:44:31 2013 @@ -0,0 +1,24 @@ + +#define AR3K_FIRMWARE_HEADER_SIZE 20 + +#define AR3K_SEND_FIRMWARE 1 +#define AR3K_GET_STATE 5 +#define AR3K_SET_NORMAL_MODE 7 +#define AR3K_GET_VERSION 9 +#define AR3K_SWITCH_VID_PID 10 + +#define AR3K_STATE_MODE_MASK 0x3f +#define AR3K_STATE_MODE_NORMAL 14 +#define AR3K_STATE_IS_SYSCFGED 0x40 +#define AR3K_STATE_IS_PATCHED 0x80 + +struct ar3k_version { + uint32_t rom; + uint32_t build; + uint32_t ram; + uint8_t clock; +#define AR3K_CLOCK_26M 0 +#define AR3K_CLOCK_40M 1 +#define AR3K_CLOCK_19M 2 + uint8_t pad[7]; +};