summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorkiyohara <kiyohara@NetBSD.org>2007-06-16 11:18:45 +0000
committerkiyohara <kiyohara@NetBSD.org>2007-06-16 11:18:45 +0000
commitc3234fb8d71d2cb9c235a2fc40dc48d60514c6c7 (patch)
tree8ab7a6b02100e639fafaab53e501dd925508b2bd /sys/dev
parentcc7db3d88beefe28f6ac77dd85bf3a6d5bc111af (diff)
We occasionally access the register from two or more processes. Please
use the simple-queue.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/if_zyd.c55
-rw-r--r--sys/dev/usb/if_zydreg.h12
2 files changed, 49 insertions, 18 deletions
diff --git a/sys/dev/usb/if_zyd.c b/sys/dev/usb/if_zyd.c
index d99782c3d6d..749bbb89364 100644
--- a/sys/dev/usb/if_zyd.c
+++ b/sys/dev/usb/if_zyd.c
@@ -1,5 +1,5 @@
/* $OpenBSD: if_zyd.c,v 1.52 2007/02/11 00:08:04 jsg Exp $ */
-/* $NetBSD: if_zyd.c,v 1.4 2007/06/16 11:09:31 kiyohara Exp $ */
+/* $NetBSD: if_zyd.c,v 1.5 2007/06/16 11:18:45 kiyohara Exp $ */
/*-
* Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
@@ -22,7 +22,7 @@
* ZyDAS ZD1211/ZD1211B USB WLAN driver.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_zyd.c,v 1.4 2007/06/16 11:09:31 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_zyd.c,v 1.5 2007/06/16 11:18:45 kiyohara Exp $");
#include "bpfilter.h"
@@ -328,6 +328,8 @@ USB_ATTACH(zyd)
/* XXXX: alloc temporarily until the layer2 can be configured. */
if_alloc_sadl(ifp);
+ SIMPLEQ_INIT(&sc->sc_rqh);
+
USB_ATTACH_SUCCESS_RETURN;
}
@@ -791,6 +793,7 @@ zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen,
{
usbd_xfer_handle xfer;
struct zyd_cmd cmd;
+ struct rq rq;
uint16_t xferflags;
usbd_status error;
int s = 0;
@@ -804,11 +807,13 @@ zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen,
xferflags = USBD_FORCE_SHORT_XFER;
if (!(flags & ZYD_CMD_FLAG_READ))
xferflags |= USBD_SYNCHRONOUS;
- else
+ else {
s = splusb();
-
- sc->odata = odata;
- sc->olen = olen;
+ rq.idata = idata;
+ rq.odata = odata;
+ rq.len = olen / sizeof (struct zyd_pair);
+ SIMPLEQ_INSERT_TAIL(&sc->sc_rqh, &rq, rq);
+ }
usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_IOUT], 0, &cmd,
sizeof (uint16_t) + ilen, xferflags, ZYD_INTR_TIMEOUT, NULL);
@@ -826,8 +831,10 @@ zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen,
return 0; /* write: don't wait for reply */
}
/* wait at most one second for command reply */
- error = tsleep(sc, PCATCH, "zydcmd", hz);
- sc->odata = NULL; /* in case answer is received too late */
+ error = tsleep(odata, PCATCH, "zydcmd", hz);
+ if (error == EWOULDBLOCK)
+ printf("%s: zyd_read sleep timeout\n", USBDEVNAME(sc->sc_dev));
+ SIMPLEQ_REMOVE(&sc->sc_rqh, &rq, rq, rq);
splx(s);
(void)usbd_free_xfer(xfer);
@@ -1810,7 +1817,7 @@ zyd_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct zyd_softc *sc = (struct zyd_softc *)priv;
struct zyd_cmd *cmd;
- uint32_t len;
+ uint32_t datalen;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
@@ -1854,18 +1861,36 @@ zyd_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
ifp->if_oerrors++; /* too many retries */
} else if (le16toh(cmd->code) == ZYD_NOTIF_IORD) {
+ struct rq *rqp;
+
if (le16toh(*(uint16_t *)cmd->data) == ZYD_CR_INTERRUPT)
return; /* HMAC interrupt */
- if (sc->odata == NULL)
- return; /* unexpected IORD notification */
+ usbd_get_xfer_status(xfer, NULL, NULL, &datalen, NULL);
+ datalen -= sizeof(cmd->code);
+ datalen -= 2; /* XXX: padding? */
- /* copy answer into caller-supplied buffer */
- usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
- bcopy(cmd->data, sc->odata, sc->olen);
+ SIMPLEQ_FOREACH(rqp, &sc->sc_rqh, rq) {
+ int i;
- wakeup(sc); /* wakeup caller */
+ if (rqp->len != datalen)
+ continue;
+ for (i = 0; i < rqp->len; i++) {
+ if (*(((const uint16_t *)rqp->idata) + i) !=
+ (((struct zyd_pair *)cmd->data) + i)->reg)
+ break;
+ }
+ if (i != rqp->len)
+ continue;
+
+ /* copy answer into caller-supplied buffer */
+ bcopy(cmd->data, rqp->odata,
+ sizeof(struct zyd_pair) * rqp->len);
+ wakeup(rqp->odata); /* wakeup caller */
+ return;
+ }
+ return; /* unexpected IORD notification */
} else {
printf("%s: unknown notification %x\n", USBDEVNAME(sc->sc_dev),
le16toh(cmd->code));
diff --git a/sys/dev/usb/if_zydreg.h b/sys/dev/usb/if_zydreg.h
index 9c5d979cfa4..b30c62677f8 100644
--- a/sys/dev/usb/if_zydreg.h
+++ b/sys/dev/usb/if_zydreg.h
@@ -1,5 +1,5 @@
/* $OpenBSD: if_zydreg.h,v 1.19 2006/11/30 19:28:07 damien Exp $ */
-/* $NetBSD: if_zydreg.h,v 1.1 2007/06/09 11:20:55 kiyohara Exp $ */
+/* $NetBSD: if_zydreg.h,v 1.2 2007/06/16 11:18:45 kiyohara Exp $ */
/*-
* Copyright (c) 2006 by Damien Bergamini <damien.bergamini@free.fr>
@@ -1158,6 +1158,13 @@ struct zyd_rf {
int width;
};
+struct rq {
+ const uint16_t *idata;
+ struct zyd_pair *odata;
+ int len;
+ SIMPLEQ_ENTRY(rq) rq;
+};
+
struct zyd_softc {
USBBASEDEVICE sc_dev;
struct ethercom sc_ec;
@@ -1183,8 +1190,7 @@ struct zyd_softc {
struct ieee80211_amrr amrr;
- void *odata;
- int olen;
+ SIMPLEQ_HEAD(rqh, rq) sc_rqh;
uint16_t fwbase;
uint8_t regdomain;