summaryrefslogtreecommitdiff
path: root/sys/dev/usb/ugen.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/ugen.c')
-rw-r--r--sys/dev/usb/ugen.c411
1 files changed, 273 insertions, 138 deletions
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
index 882a3a1328aa..0b950eff6be8 100644
--- a/sys/dev/usb/ugen.c
+++ b/sys/dev/usb/ugen.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ugen.c,v 1.11 1999/01/08 11:58:25 augustss Exp $ */
+/* $NetBSD: ugen.c,v 1.23 1999/09/09 12:26:44 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -43,7 +43,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#include <sys/ioctl.h>
#elif defined(__FreeBSD__)
@@ -54,6 +54,7 @@
#include <sys/fcntl.h>
#include <sys/filio.h>
#endif
+#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/select.h>
@@ -68,7 +69,7 @@
#ifdef UGEN_DEBUG
#define DPRINTF(x) if (ugendebug) logprintf x
#define DPRINTFN(n,x) if (ugendebug>(n)) logprintf x
-int ugendebug = 1;
+int ugendebug = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -79,13 +80,13 @@ struct ugen_endpoint {
usb_endpoint_descriptor_t *edesc;
usbd_interface_handle iface;
int state;
-#define UGEN_OPEN 0x01 /* device is open */
#define UGEN_ASLP 0x02 /* waiting for data */
#define UGEN_SHORT_OK 0x04 /* short xfers are OK */
usbd_pipe_handle pipeh;
struct clist q;
struct selinfo rsel;
void *ibuf;
+ u_int32_t timeout;
};
#define UGEN_CHUNK 128 /* chunk size for read */
@@ -93,23 +94,20 @@ struct ugen_endpoint {
#define UGEN_BBSIZE 1024
struct ugen_softc {
- bdevice sc_dev; /* base device */
- struct usbd_device *sc_udev;
+ USBBASEDEVICE sc_dev; /* base device */
+ usbd_device_handle sc_udev;
+ char sc_is_open[USB_MAX_ENDPOINTS][2];
struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
-#define OUT 0 /* index order is important, from UE_OUT */
-#define IN 1 /* from UE_IN */
+#define OUT 0
+#define IN 1
- int sc_disconnected; /* device is gone */
+ int sc_refcnt;
+ u_char sc_dying;
};
-#if defined(__NetBSD__)
-int ugenopen __P((dev_t, int, int, struct proc *));
-int ugenclose __P((dev_t, int, int, struct proc *p));
-int ugenread __P((dev_t, struct uio *uio, int));
-int ugenwrite __P((dev_t, struct uio *uio, int));
-int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int ugenpoll __P((dev_t, int, struct proc *));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+cdev_decl(ugen);
#elif defined(__FreeBSD__)
d_open_t ugenopen;
d_close_t ugenclose;
@@ -140,11 +138,11 @@ static struct cdevsw ugen_cdevsw = {
void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
usbd_status status));
-void ugen_disco __P((void *));
-
-
-
+int ugen_do_read __P((struct ugen_softc *, int, struct uio *, int));
+int ugen_do_write __P((struct ugen_softc *, int, struct uio *, int));
+int ugen_do_ioctl __P((struct ugen_softc *, int, u_long,
+ caddr_t, int, struct proc *));
int ugen_set_config __P((struct ugen_softc *sc, int configno));
usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
int *lenp));
@@ -153,6 +151,7 @@ int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
#define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
#define UGENENDPOINT(n) (minor(n) & 0xf)
+#define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e)))
USB_DECLARE_DRIVER(ugen);
@@ -183,9 +182,10 @@ USB_ATTACH(ugen)
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: setting configuration %d failed\n",
USBDEVNAME(sc->sc_dev), conf);
- sc->sc_disconnected = 1;
+ sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
+
USB_ATTACH_SUCCESS_RETURN;
}
@@ -201,6 +201,7 @@ ugen_set_config(sc, configno)
u_int8_t niface, nendpt;
int ifaceno, endptno, endpt;
usbd_status r;
+ int dir;
DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
USBDEVNAME(sc->sc_dev), configno, sc));
@@ -226,12 +227,12 @@ ugen_set_config(sc, configno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
- [UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
"(%d,%d), sce=%p\n",
endptno, endpt, UE_GET_ADDR(endpt),
- UE_GET_IN(endpt), sce));
+ UE_GET_DIR(endpt), sce));
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
@@ -240,14 +241,6 @@ ugen_set_config(sc, configno)
return (USBD_NORMAL_COMPLETION);
}
-void
-ugen_disco(p)
- void *p;
-{
- struct ugen_softc *sc = p;
- sc->sc_disconnected = 1;
-}
-
int
ugenopen(dev, flag, mode, p)
dev_t dev;
@@ -263,34 +256,38 @@ ugenopen(dev, flag, mode, p)
usbd_status r;
USB_GET_SC_OPEN(ugen, unit, sc);
- DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
+ DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
flag, mode, unit, endpt));
- if (sc->sc_disconnected)
- return (EIO);
+ if (!sc || sc->sc_dying)
+ return (ENXIO);
if (endpt == USB_CONTROL_ENDPOINT) {
- /*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
- return (EACCES);*/
- sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
- if (sce->state & UGEN_OPEN)
+ sc->sc_is_open[USB_CONTROL_ENDPOINT][IN] = 1;
+ return (0);
+ }
+ /* Make sure there are pipes for all directions. */
+ for (dir = OUT; dir <= IN; dir++) {
+ if (sc->sc_is_open[endpt][dir])
return (EBUSY);
- } else {
- switch (flag & (FWRITE|FREAD)) {
- case FWRITE:
- dir = OUT;
- break;
- case FREAD:
- dir = IN;
- break;
- default:
- return (EACCES);
+
+ if (flag & (dir == OUT ? FWRITE : FREAD)) {
+ sce = &sc->sc_endpoints[endpt][dir];
+ if (sce == 0 || sce->edesc == 0)
+ return (ENXIO);
}
+ }
+
+ /* Actually open the pipes. */
+ /* XXX Should back out properly if it fails. */
+ for (dir = OUT; dir <= IN; dir++) {
+ if (!(flag & (dir == OUT ? FWRITE : FREAD)))
+ continue;
sce = &sc->sc_endpoints[endpt][dir];
+ sce->state = 0;
+ sce->timeout = USBD_NO_TIMEOUT;
DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
sc, endpt, dir, sce));
- if (sce->state & UGEN_OPEN)
- return (EBUSY);
edesc = sce->edesc;
if (!edesc)
return (ENXIO);
@@ -299,12 +296,12 @@ ugenopen(dev, flag, mode, p)
isize = UGETW(edesc->wMaxPacketSize);
if (isize == 0) /* shouldn't happen */
return (EINVAL);
- sce->ibuf = malloc(isize, M_USB, M_WAITOK);
+ sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
endpt, isize));
-#if defined(__NetBSD__)
- if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
- return (ENOMEM);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
+ return (ENOMEM);
#elif defined(__FreeBSD__)
clist_alloc_cblocks(&sce->q, UGEN_IBSIZE, 0);
#endif
@@ -313,15 +310,14 @@ ugenopen(dev, flag, mode, p)
USBD_SHORT_XFER_OK, &sce->pipeh, sce,
sce->ibuf, isize, ugenintr);
if (r != USBD_NORMAL_COMPLETION) {
- free(sce->ibuf, M_USB);
-#if defined(__NetBSD__)
+ free(sce->ibuf, M_USBDEV);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
clfree(&sce->q);
#elif defined(__FreeBSD__)
clist_free_cblocks(&sce->q);
#endif
return (EIO);
}
- usbd_set_disco(sce->pipeh, ugen_disco, sc);
DPRINTFN(5, ("ugenopen: interrupt open done\n"));
break;
case UE_BULK:
@@ -335,8 +331,8 @@ ugenopen(dev, flag, mode, p)
case UE_ISOCHRONOUS:
return (EINVAL);
}
+ sc->sc_is_open[endpt][dir] = 1;
}
- sce->state |= UGEN_OPEN;
return (0);
}
@@ -352,52 +348,58 @@ ugenclose(dev, flag, mode, p)
struct ugen_endpoint *sce;
int dir;
- DPRINTFN(5, ("ugenclose: flag=%d, mode=%d\n", flag, mode));
+ DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
+ flag, mode, UGENUNIT(dev), endpt));
- if (!sc || sc->sc_disconnected)
- return (EIO);
+#ifdef DIAGNOSTIC
+ if (!sc->sc_is_open[endpt][IN] || !sc->sc_is_open[endpt][OUT] ) {
+ printf("ugenclose: not open\n");
+ return (EINVAL);
+ }
+#endif
if (endpt == USB_CONTROL_ENDPOINT) {
DPRINTFN(5, ("ugenclose: close control\n"));
- sc->sc_endpoints[endpt][OUT].state = 0;
+ sc->sc_is_open[USB_CONTROL_ENDPOINT][IN] = 0;
return (0);
}
- flag = FWRITE | FREAD; /* XXX bug if generic open/close */
-
- /* The open modes have been joined, so check for both modes. */
for (dir = OUT; dir <= IN; dir++) {
- if (flag & (dir == OUT ? FWRITE : FREAD)) {
- sce = &sc->sc_endpoints[endpt][dir];
- if (!sce || !sce->pipeh) /* XXX */
- continue; /* XXX */
- DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
- endpt, dir, sce));
- sce->state = 0;
-
- usbd_abort_pipe(sce->pipeh);
- usbd_close_pipe(sce->pipeh);
- sce->pipeh = 0;
-
- if (sce->ibuf) {
- free(sce->ibuf, M_USB);
- sce->ibuf = 0;
- }
+ if (!(flag & (dir == OUT ? FWRITE : FREAD)))
+ continue;
+ sce = &sc->sc_endpoints[endpt][dir];
+ if (!sce || !sce->pipeh)
+ continue;
+ DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
+ endpt, dir, sce));
+
+ usbd_abort_pipe(sce->pipeh);
+ usbd_close_pipe(sce->pipeh);
+ sce->pipeh = 0;
+
+ if (sce->ibuf) {
+ free(sce->ibuf, M_USBDEV);
+ sce->ibuf = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ clfree(&sce->q);
+#elif defined(__FreeBSD__)
+ clist_free_cblocks(&sce->q);
+#endif
}
+ sc->sc_is_open[endpt][dir] = 0;
}
return (0);
}
int
-ugenread(dev, uio, flag)
- dev_t dev;
+ugen_do_read(sc, endpt, uio, flag)
+ struct ugen_softc *sc;
+ int endpt;
struct uio *uio;
int flag;
{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
+ struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
u_int32_t n, tn;
char buf[UGEN_BBSIZE];
usbd_request_handle reqh;
@@ -406,12 +408,12 @@ ugenread(dev, uio, flag)
int error = 0;
u_char buffer[UGEN_CHUNK];
- DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
- if (!sc || sc->sc_disconnected)
+#ifdef __NetBSD__
+ DPRINTFN(5, ("ugenread: %d:%d\n", sc->sc_dev.dv_unit, endpt));
+#endif
+ if (sc->sc_dying)
return (EIO);
- sce = &sc->sc_endpoints[endpt][IN];
-
#ifdef DIAGNOSTIC
if (!sce->edesc) {
printf("ugenread: no edesc\n");
@@ -434,19 +436,19 @@ ugenread(dev, uio, flag)
}
sce->state |= UGEN_ASLP;
DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
- error = tsleep((caddr_t)sce, PZERO | PCATCH,
- "ugenri", 0);
+ error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
+ if (sc->sc_dying)
+ error = EIO;
if (error) {
sce->state &= ~UGEN_ASLP;
- splx(s);
- return (error);
+ break;
}
}
splx(s);
/* Transfer as many chunks as possible. */
- while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
+ while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
n = min(sce->q.c_cc, uio->uio_resid);
if (n > sizeof(buffer))
n = sizeof(buffer);
@@ -462,18 +464,22 @@ ugenread(dev, uio, flag)
}
break;
case UE_BULK:
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(sc->sc_udev);
if (reqh == 0)
return (ENOMEM);
while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
- DPRINTFN(1, ("ugenread: start transfer %d bytes\n", n));
+ DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
tn = n;
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
- USBD_NO_TIMEOUT, buf,
- &tn, "ugenrb");
+ r = usbd_bulk_transfer(
+ reqh, sce->pipeh,
+ sce->state & UGEN_SHORT_OK ?
+ USBD_SHORT_XFER_OK : 0,
+ sce->timeout, buf, &tn, "ugenrb");
if (r != USBD_NORMAL_COMPLETION) {
if (r == USBD_INTERRUPTED)
error = EINTR;
+ else if (r == USBD_TIMEOUT)
+ error = ETIMEDOUT;
else
error = EIO;
break;
@@ -488,30 +494,43 @@ ugenread(dev, uio, flag)
default:
return (ENXIO);
}
-
return (error);
}
int
-ugenwrite(dev, uio, flag)
+ugenread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
USB_GET_SC(ugen, UGENUNIT(dev), sc);
int endpt = UGENENDPOINT(dev);
- struct ugen_endpoint *sce;
- size_t n;
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_read(sc, endpt, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
+ugen_do_write(sc, endpt, uio, flag)
+ struct ugen_softc *sc;
+ int endpt;
+ struct uio *uio;
+ int flag;
+{
+ struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
+ u_int32_t n;
int error = 0;
char buf[UGEN_BBSIZE];
usbd_request_handle reqh;
usbd_status r;
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
- sce = &sc->sc_endpoints[endpt][OUT];
-
#ifdef DIAGNOSTIC
if (!sce->edesc) {
printf("ugenwrite: no edesc\n");
@@ -526,7 +545,7 @@ ugenwrite(dev, uio, flag)
DPRINTF(("ugenwrite\n"));
switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_BULK:
- reqh = usbd_alloc_request();
+ reqh = usbd_alloc_request(sc->sc_udev);
if (reqh == 0)
return (EIO);
while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
@@ -534,9 +553,8 @@ ugenwrite(dev, uio, flag)
if (error)
break;
DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
- r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
- USBD_NO_TIMEOUT, buf,
- &n, "ugenwb");
+ r = usbd_bulk_transfer(reqh, sce->pipeh, 0,
+ sce->timeout, buf, &n,"ugenwb");
if (r != USBD_NORMAL_COMPLETION) {
if (r == USBD_INTERRUPTED)
error = EINTR;
@@ -553,6 +571,94 @@ ugenwrite(dev, uio, flag)
return (error);
}
+int
+ugenwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ USB_GET_SC(ugen, UGENUNIT(dev), sc);
+ int endpt = UGENENDPOINT(dev);
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_write(sc, endpt, uio, flag);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+ugen_activate(self, act)
+ device_ptr_t self;
+ enum devact act;
+{
+ struct ugen_softc *sc = (struct ugen_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ sc->sc_dying = 1;
+ break;
+ }
+ return (0);
+}
+#endif
+
+USB_DETACH(ugen)
+{
+ USB_DETACH_START(ugen, sc);
+ struct ugen_endpoint *sce;
+ int i, dir;
+ int s;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ int maj, mn;
+
+ DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
+#elif defined(__FreeBSD__)
+ DPRINTF(("ugen_detach: sc=%p\n", sc));
+#endif
+
+ sc->sc_dying = 1;
+ /* Abort all pipes. Causes processes waiting for transfer to wake. */
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ for (dir = OUT; dir <= IN; dir++) {
+ sce = &sc->sc_endpoints[i][dir];
+ if (sce && sce->pipeh)
+ usbd_abort_pipe(sce->pipeh);
+ }
+ }
+
+ s = splusb();
+ if (--sc->sc_refcnt >= 0) {
+ /* Wake everyone */
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+ wakeup(&sc->sc_endpoints[i][IN]);
+ /* Wait for processes to go away. */
+ usb_detach_wait(USBDEV(sc->sc_dev));
+ }
+ splx(s);
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == ugenopen)
+ break;
+
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit * USB_MAX_ENDPOINTS;
+ vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
+#elif defined(__FreeBSD__)
+ /* XXX not implemented yet */
+#endif
+
+ return (0);
+}
void
ugenintr(reqh, addr, status)
@@ -562,10 +668,7 @@ ugenintr(reqh, addr, status)
{
struct ugen_endpoint *sce = addr;
/*struct ugen_softc *sc = sce->sc;*/
- usbd_private_handle priv;
- void *buffer;
u_int32_t count;
- usbd_status xstatus;
u_char *ibuf;
if (status == USBD_CANCELLED)
@@ -577,11 +680,11 @@ ugenintr(reqh, addr, status)
return;
}
- (void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);
+ usbd_get_request_status(reqh, 0, 0, &count, 0);
ibuf = sce->ibuf;
DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n",
- reqh, xstatus, count));
+ reqh, status, count));
DPRINTFN(5, (" data = %02x %02x %02x\n",
ibuf[0], ibuf[1], ibuf[2]));
@@ -590,7 +693,7 @@ ugenintr(reqh, addr, status)
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
- wakeup((caddr_t)sce);
+ wakeup(sce);
}
selwakeup(&sce->rsel);
}
@@ -605,6 +708,7 @@ ugen_set_interface(sc, ifaceidx, altno)
usbd_status r;
struct ugen_endpoint *sce;
u_int8_t niface, nendpt, endptno, endpt;
+ int dir;
DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
@@ -623,7 +727,8 @@ ugen_set_interface(sc, ifaceidx, altno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
sce->sc = 0;
sce->edesc = 0;
sce->iface = 0;
@@ -640,7 +745,8 @@ ugen_set_interface(sc, ifaceidx, altno)
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
- sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
+ dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
+ sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
@@ -700,15 +806,14 @@ ugen_get_alt_index(sc, ifaceidx)
}
int
-ugenioctl(dev, cmd, addr, flag, p)
- dev_t dev;
+ugen_do_ioctl(sc, endpt, cmd, addr, flag, p)
+ struct ugen_softc *sc;
+ int endpt;
u_long cmd;
caddr_t addr;
int flag;
struct proc *p;
{
- USB_GET_SC(ugen, UGENUNIT(dev), sc);
- int endpt = UGENENDPOINT(dev);
struct ugen_endpoint *sce;
usbd_status r;
usbd_interface_handle iface;
@@ -723,7 +828,7 @@ ugenioctl(dev, cmd, addr, flag, p)
u_int8_t conf, alt;
DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
switch (cmd) {
@@ -732,10 +837,12 @@ ugenioctl(dev, cmd, addr, flag, p)
return (0);
case USB_SET_SHORT_XFER:
/* This flag only affects read */
+ if (endpt == USB_CONTROL_ENDPOINT)
+ return (EINVAL);
sce = &sc->sc_endpoints[endpt][IN];
#ifdef DIAGNOSTIC
if (!sce->pipeh) {
- printf("ugenioctl: no pipe\n");
+ printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
return (EIO);
}
#endif
@@ -744,6 +851,16 @@ ugenioctl(dev, cmd, addr, flag, p)
else
sce->state &= ~UGEN_SHORT_OK;
return (0);
+ case USB_SET_TIMEOUT:
+ sce = &sc->sc_endpoints[endpt][IN];
+#ifdef DIAGNOSTIC
+ if (!sce->pipeh) {
+ printf("ugenioctl: USB_SET_TIMEOUT, no pipe\n");
+ return (EIO);
+ }
+#endif
+ sce->timeout = *(int *)addr;
+ return (0);
default:
break;
}
@@ -799,9 +916,12 @@ ugenioctl(dev, cmd, addr, flag, p)
if (!cdesc)
return (EINVAL);
idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
- if (!idesc)
+ if (!idesc) {
+ free(cdesc, M_TEMP);
return (EINVAL);
+ }
ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
+ free(cdesc, M_TEMP);
break;
case USB_GET_DEVICE_DESC:
*(usb_device_descriptor_t *)addr =
@@ -872,7 +992,11 @@ ugenioctl(dev, cmd, addr, flag, p)
uio.uio_segflg = UIO_USERSPACE;
uio.uio_rw = UIO_READ;
uio.uio_procp = p;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
error = uiomove((caddr_t)cdesc, len, &uio);
+#elif defined(__FreeBSD__)
+ error = uiomove((void *)cdesc, len, &uio);
+#endif
free(cdesc, M_TEMP);
return (error);
}
@@ -927,7 +1051,7 @@ ugenioctl(dev, cmd, addr, flag, p)
}
r = usbd_do_request_flags(sc->sc_udev, &ur->request,
ptr, ur->flags, &ur->actlen);
- if (r) {
+ if (r != USBD_NORMAL_COMPLETION) {
error = EIO;
goto ret;
}
@@ -954,20 +1078,39 @@ ugenioctl(dev, cmd, addr, flag, p)
}
int
+ugenioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ USB_GET_SC(ugen, UGENUNIT(dev), sc);
+ int endpt = UGENENDPOINT(dev);
+ int error;
+
+ sc->sc_refcnt++;
+ error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
+ if (--sc->sc_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->sc_dev));
+ return (error);
+}
+
+int
ugenpoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
USB_GET_SC(ugen, UGENUNIT(dev), sc);
- /* XXX */
struct ugen_endpoint *sce;
int revents = 0;
int s;
- if (!sc || sc->sc_disconnected)
+ if (sc->sc_dying)
return (EIO);
+ /* XXX always IN */
sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
#ifdef DIAGNOSTIC
if (!sce->edesc) {
@@ -1006,13 +1149,5 @@ ugenpoll(dev, events, p)
}
#if defined(__FreeBSD__)
-static int
-ugen_detach(device_t self)
-{
- DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
-
- return 0;
-}
-
DEV_DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, ugen_cdevsw, usbd_driver_load, 0);
#endif