Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb . add support for loading code + config of AR301...
details: https://anonhg.NetBSD.org/src/rev/c7eacf3f8026
branches: trunk
changeset: 786763:c7eacf3f8026
user: aymeric <aymeric%NetBSD.org@localhost>
date: Thu May 09 12:44:31 2013 +0000
description:
. add support for loading code + config of AR3012 based chips
. make it easy to add vendor and product ids for similar hardware
diffstat:
sys/dev/usb/aubtfwl.c | 192 ++++++++++++++++++++++++++++++++++++++++++----
sys/dev/usb/aubtfwlreg.h | 24 +++++
2 files changed, 196 insertions(+), 20 deletions(-)
diffs (truncated from 335 to 300 lines):
diff -r 283a112682d3 -r c7eacf3f8026 sys/dev/usb/aubtfwl.c
--- a/sys/dev/usb/aubtfwl.c Thu May 09 12:41:13 2013 +0000
+++ b/sys/dev/usb/aubtfwl.c Thu May 09 12:44:31 2013 +0000
@@ -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 @@
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 @@
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 @@
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));
+
+ memset(&req, 0, sizeof req);
- error = firmware_open("ubt", "ath3k-1.fw", &fwh); /* XXX revisit name */
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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_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 */
Home |
Main Index |
Thread Index |
Old Index