summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2006-12-03 16:09:22 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2006-12-03 16:09:22 +0000
commitb0be393953f3dcced2f4b9174eb72a53aa991673 (patch)
treec3c5b9aad601bfce94fe247ae721511daed9a38f
parenta29d77ccae35115a94b84d2c2c7d0fdd15dbdbc4 (diff)
The device doesn't always detach gracefully from the bus after a firmware
upload. We thus force a port reset and a re-exploration on the parent hub after firmware upload. In uath_newstate(), if we're called from a process context, we don't need to schedule a USB task. This fixes a problem in uath_stop(): when moving to the S_INIT state, the task was scheduled after the device was reset. Don't abort the RX firmware command pipe in uath_stop(), otherwise we will never receive commands ACKs from the firmware anymore. We now survive to an ifconfig down up.
-rw-r--r--sys/dev/usb/if_uath.c39
-rw-r--r--sys/dev/usb/if_uathvar.h5
2 files changed, 32 insertions, 12 deletions
diff --git a/sys/dev/usb/if_uath.c b/sys/dev/usb/if_uath.c
index ae98cfd67b3..fa5b90267a6 100644
--- a/sys/dev/usb/if_uath.c
+++ b/sys/dev/usb/if_uath.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_uath.c,v 1.12 2006/11/26 11:14:22 deraadt Exp $ */
+/* $OpenBSD: if_uath.c,v 1.13 2006/12/03 16:09:21 damien Exp $ */
/*-
* Copyright (c) 2006
@@ -70,6 +70,7 @@
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h> /* needs_reattach() */
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
@@ -129,7 +130,7 @@ static const struct uath_type {
UATH_DEV_UG(ZCOM, AR5523)
};
#define uath_lookup(v, p) \
- ((struct uath_type *)usb_lookup(uath_devs, v, p))
+ ((const struct uath_type *)usb_lookup(uath_devs, v, p))
Static void uath_attachhook(void *);
Static int uath_open_pipes(struct uath_softc *);
@@ -221,12 +222,23 @@ uath_attachhook(void *xsc)
return;
}
- if ((error = uath_loadfirmware(sc, fw, size)) != 0) {
+ error = uath_loadfirmware(sc, fw, size);
+ free(fw, M_DEVBUF);
+
+ if (error == 0) {
+ usb_port_status_t status;
+
+ /*
+ * Hack alert: the device doesn't always gracefully detach
+ * from the bus after a firmware upload. We need to force
+ * a port reset and a re-exploration on the parent hub.
+ */
+ usbd_reset_port(sc->sc_uhub, sc->sc_port, &status);
+ usb_needs_reattach(sc->sc_udev);
+ } else {
printf("%s: could not load firmware (error=%s)\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(error));
}
-
- free(fw, M_DEVBUF);
}
USB_ATTACH(uath)
@@ -239,6 +251,8 @@ USB_ATTACH(uath)
int i;
sc->sc_udev = uaa->device;
+ sc->sc_uhub = uaa->device->myhub;
+ sc->sc_port = uaa->port;
devinfop = usbd_devinfo_alloc(uaa->device, 0);
USB_ATTACH_SETUP;
@@ -909,11 +923,14 @@ uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
timeout_del(&sc->scan_to);
timeout_del(&sc->stat_to);
- /* do it in a process context */
sc->sc_state = nstate;
sc->sc_arg = arg;
- usb_add_task(sc->sc_udev, &sc->sc_task);
-
+ if (curproc != NULL) {
+ uath_task(sc);
+ } else {
+ /* do it in a process context */
+ usb_add_task(sc->sc_udev, &sc->sc_task);
+ }
return 0;
}
@@ -982,8 +999,8 @@ uath_cmd(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
if (error != USBD_IN_PROGRESS && error != 0) {
if (flags & UATH_CMD_FLAG_READ)
splx(s);
- printf("%s: could not send command (error=%s)\n",
- USBDEVNAME(sc->sc_dev), usbd_errstr(error));
+ printf("%s: could not send command 0x%x (error=%s)\n",
+ USBDEVNAME(sc->sc_dev), code, usbd_errstr(error));
return error;
}
sc->cmd_idx = (sc->cmd_idx + 1) % UATH_TX_CMD_LIST_COUNT;
@@ -1651,6 +1668,7 @@ uath_reset(struct uath_softc *sc)
for (reg = 0x09; reg <= 0x24; reg++) {
if (reg == 0x0b || reg == 0x0c)
continue;
+ DELAY(100);
if ((error = uath_read_reg(sc, reg, &val)) != 0)
return error;
DPRINTFN(2, ("reg 0x%02x=0x%08x\n", reg, val));
@@ -1991,7 +2009,6 @@ uath_stop(struct ifnet *ifp, int disable)
usbd_abort_pipe(sc->data_tx_pipe);
usbd_abort_pipe(sc->data_rx_pipe);
usbd_abort_pipe(sc->cmd_tx_pipe);
- usbd_abort_pipe(sc->cmd_rx_pipe);
splx(s);
}
diff --git a/sys/dev/usb/if_uathvar.h b/sys/dev/usb/if_uathvar.h
index 8255c55513d..3d99fa9f91f 100644
--- a/sys/dev/usb/if_uathvar.h
+++ b/sys/dev/usb/if_uathvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_uathvar.h,v 1.3 2006/09/20 19:47:17 damien Exp $ */
+/* $OpenBSD: if_uathvar.h,v 1.4 2006/12/03 16:09:21 damien Exp $ */
/*-
* Copyright (c) 2006
@@ -122,6 +122,9 @@ struct uath_softc {
int tx_queued;
usbd_device_handle sc_udev;
+ usbd_device_handle sc_uhub;
+ int sc_port;
+
usbd_interface_handle sc_iface;
usbd_pipe_handle data_tx_pipe;