summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2006-08-18 02:54:12 +0000
committerJason Wright <jason@cvs.openbsd.org>2006-08-18 02:54:12 +0000
commit5b6abf1c1a48d2d8259c2ce49d894e29d5d94efb (patch)
treeff8a1fbd332fb7ae18a644d9d34249380317d72f
parent9a29069b7777b249a7ae8ab30d6009b355b369bc (diff)
support for ucycom:
- teach ucom that not all i/o is done via bulk pipes - teach uhidev that i/o interrupt pipes are distinct
-rw-r--r--sys/dev/usb/ucom.c200
-rw-r--r--sys/dev/usb/ucomvar.h3
-rw-r--r--sys/dev/usb/uhidev.c197
-rw-r--r--sys/dev/usb/uhidev.h13
4 files changed, 295 insertions, 118 deletions
diff --git a/sys/dev/usb/ucom.c b/sys/dev/usb/ucom.c
index e9823e206f6..58f4cbccedc 100644
--- a/sys/dev/usb/ucom.c
+++ b/sys/dev/usb/ucom.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ucom.c,v 1.30 2006/06/23 06:27:11 miod Exp $ */
+/* $OpenBSD: ucom.c,v 1.31 2006/08/18 02:54:11 jason Exp $ */
/* $NetBSD: ucom.c,v 1.49 2003/01/01 00:10:25 thorpej Exp $ */
/*
@@ -58,6 +58,7 @@
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
+#include <dev/usb/uhidev.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usb_quirks.h>
@@ -87,6 +88,7 @@ struct ucom_softc {
USBBASEDEVICE sc_dev; /* base device */
usbd_device_handle sc_udev; /* USB device */
+ struct uhidev_softc *sc_uhidev; /* hid device (if deeper) */
usbd_interface_handle sc_iface; /* data interface */
@@ -105,6 +107,9 @@ struct ucom_softc {
u_int sc_opkthdrlen; /* header length of
* output packet */
+ usbd_pipe_handle sc_ipipe; /* hid interrupt input pipe */
+ usbd_pipe_handle sc_opipe; /* hid interrupt pipe */
+
struct ucom_methods *sc_methods;
void *sc_parent;
int sc_portno;
@@ -178,6 +183,7 @@ USB_ATTACH(ucom)
sc->sc_iface = uca->iface;
sc->sc_bulkout_no = uca->bulkout;
sc->sc_bulkin_no = uca->bulkin;
+ sc->sc_uhidev = uca->uhidev;
sc->sc_ibufsize = uca->ibufsize;
sc->sc_ibufsizepad = uca->ibufsizepad;
sc->sc_obufsize = uca->obufsize;
@@ -310,6 +316,70 @@ ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
if (sc->sc_open++ == 0) {
s = splusb();
+ DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
+ sc->sc_bulkin_no, sc->sc_bulkout_no));
+ DPRINTF(("ucomopen: hid %p pipes in=%p out=%p\n",
+ sc->sc_uhidev, sc->sc_ipipe, sc->sc_opipe));
+
+ if (sc->sc_bulkin_no != -1) {
+
+ /* Open the bulk pipes */
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
+ &sc->sc_bulkin_pipe);
+ if (err) {
+ DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
+ usbd_errstr(err)));
+ error = EIO;
+ goto fail_0;
+ }
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
+ USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
+ if (err) {
+ DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
+ USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
+ usbd_errstr(err)));
+ error = EIO;
+ goto fail_1;
+ }
+
+ /* Allocate a request and an input buffer and start reading. */
+ sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_ixfer == NULL) {
+ error = ENOMEM;
+ goto fail_2;
+ }
+
+ sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
+ sc->sc_ibufsizepad);
+ if (sc->sc_ibuf == NULL) {
+ error = ENOMEM;
+ goto fail_2;
+ }
+
+ sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_oxfer == NULL) {
+ error = ENOMEM;
+ goto fail_3;
+ }
+ } else {
+ /*
+ * input/output pipes and xfers already allocated
+ * as is the input buffer.
+ */
+ sc->sc_ipipe = sc->sc_uhidev->sc_ipipe;
+ sc->sc_ixfer = sc->sc_uhidev->sc_ixfer;
+ sc->sc_opipe = sc->sc_uhidev->sc_opipe;
+ sc->sc_oxfer = sc->sc_uhidev->sc_oxfer;
+ }
+
+ sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
+ sc->sc_obufsize + sc->sc_opkthdrlen);
+ if (sc->sc_obuf == NULL) {
+ error = ENOMEM;
+ goto fail_4;
+ }
+
if (sc->sc_methods->ucom_open != NULL) {
error = sc->sc_methods->ucom_open(sc->sc_parent,
sc->sc_portno);
@@ -323,57 +393,6 @@ ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
ucom_status_change(sc);
- DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
- sc->sc_bulkin_no, sc->sc_bulkout_no));
-
- /* Open the bulk pipes */
- err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
- &sc->sc_bulkin_pipe);
- if (err) {
- DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
- USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
- usbd_errstr(err)));
- error = EIO;
- goto fail_0;
- }
- err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
- USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
- if (err) {
- DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
- USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
- usbd_errstr(err)));
- error = EIO;
- goto fail_1;
- }
-
- /* Allocate a request and an input buffer and start reading. */
- sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
- if (sc->sc_ixfer == NULL) {
- error = ENOMEM;
- goto fail_2;
- }
-
- sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
- sc->sc_ibufsizepad);
- if (sc->sc_ibuf == NULL) {
- error = ENOMEM;
- goto fail_3;
- }
-
- sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
- if (sc->sc_oxfer == NULL) {
- error = ENOMEM;
- goto fail_3;
- }
-
- sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
- sc->sc_obufsize +
- sc->sc_opkthdrlen);
- if (sc->sc_obuf == NULL) {
- error = ENOMEM;
- goto fail_4;
- }
-
ucomstartread(sc);
splx(s);
@@ -484,7 +503,8 @@ ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
return (0);
fail_4:
- usbd_free_xfer(sc->sc_oxfer);
+ if (sc->sc_uhidev == NULL)
+ usbd_free_xfer(sc->sc_oxfer);
sc->sc_oxfer = NULL;
fail_3:
usbd_free_xfer(sc->sc_ixfer);
@@ -517,10 +537,10 @@ ucomclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
struct tty *tp = sc->sc_tty;
int s;
- DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
if (!ISSET(tp->t_state, TS_ISOPEN))
return (0);
+ DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
ucom_lock(sc);
(*LINESW(tp, l_close))(tp, flag);
@@ -944,9 +964,21 @@ ucomstart(struct tty *tp)
memcpy(sc->sc_obuf, data, cnt);
DPRINTFN(4,("ucomstart: %d chars\n", cnt));
- usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
- (usbd_private_handle)sc, sc->sc_obuf, cnt,
- USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
+#ifdef DIAGNOSTIC
+ if (sc->sc_oxfer == NULL) {
+ printf("ucomstart: null oxfer\n");
+ goto out;
+ }
+#endif
+ if (sc->sc_bulkout_pipe != NULL) {
+ usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
+ (usbd_private_handle)sc, sc->sc_obuf, cnt,
+ USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
+ } else {
+ usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe,
+ (usbd_private_handle)sc, sc->sc_obuf, cnt,
+ USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
+ }
/* What can we do on error? */
err = usbd_transfer(sc->sc_oxfer);
#ifdef DIAGNOSTIC
@@ -986,20 +1018,23 @@ ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
u_int32_t cc;
int s;
- DPRINTFN(5,("ucomwritecb: status=%d\n", status));
+ DPRINTFN(5,("ucomwritecb: %p %p status=%d\n", xfer, p, status));
if (status == USBD_CANCELLED || sc->sc_dying)
goto error;
- if (status) {
- DPRINTF(("ucomwritecb: status=%d\n", status));
- usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
- /* XXX we should restart after some delay. */
- goto error;
+ if (sc->sc_bulkin_pipe != NULL) {
+ if (status) {
+ usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
+ /* XXX we should restart after some delay. */
+ goto error;
+ }
+ usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
+ } else {
+ usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
+ // XXX above gives me wrong cc, no?
}
- usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
-
DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
/* convert from USB bytes to tty bytes */
cc -= sc->sc_opkthdrlen;
@@ -1026,16 +1061,26 @@ ucomstartread(struct ucom_softc *sc)
usbd_status err;
DPRINTFN(5,("ucomstartread: start\n"));
- usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
+#ifdef DIAGNOSTIC
+ if (sc->sc_ixfer == NULL) {
+ DPRINTF(("ucomstartread: null ixfer\n"));
+ return (USBD_INVAL);
+ }
+#endif
+
+ if (sc->sc_bulkin_pipe != NULL) {
+ usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
(usbd_private_handle)sc,
sc->sc_ibuf, sc->sc_ibufsize,
USBD_SHORT_XFER_OK | USBD_NO_COPY,
USBD_NO_TIMEOUT, ucomreadcb);
- err = usbd_transfer(sc->sc_ixfer);
- if (err != USBD_IN_PROGRESS) {
- DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
- return (err);
+ err = usbd_transfer(sc->sc_ixfer);
+ if (err != USBD_IN_PROGRESS) {
+ DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
+ return (err);
+ }
}
+
return (USBD_NORMAL_COMPLETION);
}
@@ -1064,9 +1109,11 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
}
if (status) {
- usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
- /* XXX we should restart after some delay. */
- return;
+ if (sc->sc_bulkin_pipe != NULL) {
+ usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
+ /* XXX we should restart after some delay. */
+ return;
+ }
}
usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
@@ -1113,11 +1160,14 @@ ucom_cleanup(struct ucom_softc *sc)
sc->sc_bulkout_pipe = NULL;
}
if (sc->sc_ixfer != NULL) {
- usbd_free_xfer(sc->sc_ixfer);
+ if (sc->sc_uhidev == NULL)
+ usbd_free_xfer(sc->sc_ixfer);
sc->sc_ixfer = NULL;
}
if (sc->sc_oxfer != NULL) {
- usbd_free_xfer(sc->sc_oxfer);
+ usbd_free_buffer(sc->sc_oxfer);
+ if (sc->sc_uhidev == NULL)
+ usbd_free_xfer(sc->sc_oxfer);
sc->sc_oxfer = NULL;
}
}
diff --git a/sys/dev/usb/ucomvar.h b/sys/dev/usb/ucomvar.h
index 033d7359e7b..8ec54457157 100644
--- a/sys/dev/usb/ucomvar.h
+++ b/sys/dev/usb/ucomvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ucomvar.h,v 1.13 2006/03/27 08:19:39 dlg Exp $ */
+/* $OpenBSD: ucomvar.h,v 1.14 2006/08/18 02:54:11 jason Exp $ */
/* $NetBSD: ucomvar.h,v 1.10 2001/12/31 12:15:21 augustss Exp $ */
/*
@@ -89,6 +89,7 @@ struct ucom_attach_args {
int portno;
int bulkin;
int bulkout;
+ struct uhidev_softc *uhidev;
u_int ibufsize;
u_int ibufsizepad;
u_int obufsize;
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index 81f2c59ec8f..ec830547b03 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhidev.c,v 1.16 2006/06/23 06:27:11 miod Exp $ */
+/* $OpenBSD: uhidev.c,v 1.17 2006/08/18 02:54:11 jason Exp $ */
/* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -126,6 +126,7 @@ USB_ATTACH(uhidev)
struct uhidev *dev;
int size, nrepid, repid, repsz;
int repsizes[256];
+ int i;
void *desc;
const void *descptr;
usbd_status err;
@@ -150,32 +151,48 @@ USB_ATTACH(uhidev)
(void)usbd_set_protocol(iface, 1);
#endif
- ed = usbd_interface2endpoint_descriptor(iface, 0);
- if (ed == NULL) {
- printf("%s: could not read endpoint descriptor\n",
- USBDEVNAME(sc->sc_dev));
- sc->sc_dying = 1;
- USB_ATTACH_ERROR_RETURN;
+ sc->sc_iep_addr = sc->sc_oep_addr = -1;
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(iface, i);
+ if (ed == NULL) {
+ printf("%s: could not read endpoint descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
+ "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
+ " bInterval=%d\n",
+ ed->bLength, ed->bDescriptorType,
+ ed->bEndpointAddress & UE_ADDR,
+ UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
+ ed->bmAttributes & UE_XFERTYPE,
+ UGETW(ed->wMaxPacketSize), ed->bInterval));
+
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
+ sc->sc_iep_addr = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+ (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
+ sc->sc_oep_addr = ed->bEndpointAddress;
+ } else {
+ printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
+ sc->sc_dying = 1;
+ USB_ATTACH_ERROR_RETURN;
+ }
}
- DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
- "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
- " bInterval=%d\n",
- ed->bLength, ed->bDescriptorType,
- ed->bEndpointAddress & UE_ADDR,
- UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
- ed->bmAttributes & UE_XFERTYPE,
- UGETW(ed->wMaxPacketSize), ed->bInterval));
-
- if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
- (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
- printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
+ /*
+ * Check that we found an input interrupt endpoint. The output interrupt
+ * endpoint is optional
+ */
+ if (sc->sc_iep_addr == -1) {
+ printf("%s: no input interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
- sc->sc_ep_addr = ed->bEndpointAddress;
-
/* XXX need to extend this */
descptr = NULL;
if (uaa->vendor == USB_VENDOR_WACOM) {
@@ -361,8 +378,8 @@ USB_DETACH(uhidev)
DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
sc->sc_dying = 1;
- if (sc->sc_intrpipe != NULL)
- usbd_abort_pipe(sc->sc_intrpipe);
+ if (sc->sc_ipipe != NULL)
+ usbd_abort_pipe(sc->sc_ipipe);
if (sc->sc_repdesc != NULL)
free(sc->sc_repdesc, M_USBDEV);
@@ -410,7 +427,7 @@ uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
if (status != USBD_NORMAL_COMPLETION) {
DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev),
status));
- usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
+ usbd_clear_endpoint_stall_async(sc->sc_ipipe);
return;
}
@@ -448,6 +465,7 @@ uhidev_open(struct uhidev *scd)
{
struct uhidev_softc *sc = scd->sc_parent;
usbd_status err;
+ int error;
DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
scd->sc_state, sc->sc_refcnt));
@@ -463,22 +481,86 @@ uhidev_open(struct uhidev *scd)
sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
- /* Set up interrupt pipe. */
+ /* Set up input interrupt pipe. */
DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
- sc->sc_ep_addr));
- err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
- USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf,
+ sc->sc_iep_addr));
+
+ err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
+ USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
- if (err) {
+ if (err != USBD_NORMAL_COMPLETION) {
DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
- "error=%d\n",err));
- free(sc->sc_ibuf, M_USBDEV);
- scd->sc_state &= ~UHIDEV_OPEN;
- sc->sc_refcnt = 0;
- sc->sc_intrpipe = NULL;
- return (EIO);
+ "error=%d\n", err));
+ error = EIO;
+ goto out1;
+ }
+
+ DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe));
+
+ sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_ixfer == NULL) {
+ DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
+ error = ENOMEM;
+ goto out1; // xxxx
}
+
+ /*
+ * Set up output interrupt pipe if an output interrupt endpoint
+ * exists.
+ */
+ if (sc->sc_oep_addr != -1) {
+ DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
+
+ err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
+ 0, &sc->sc_opipe);
+
+ if (err != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("uhidev_open: usbd_open_pipe failed, "
+ "error=%d\n", err));
+ error = EIO;
+ goto out2;
+ }
+ DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
+
+ sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_oxfer == NULL) {
+ DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
+ error = ENOMEM;
+ goto out3;
+ }
+
+ sc->sc_owxfer = usbd_alloc_xfer(sc->sc_udev);
+ if (sc->sc_owxfer == NULL) {
+ DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
+ error = ENOMEM;
+ goto out3;
+ }
+ }
+
return (0);
+
+out3:
+ /* Abort output pipe */
+ usbd_close_pipe(sc->sc_opipe);
+out2:
+ /* Abort input pipe */
+ usbd_close_pipe(sc->sc_ipipe);
+out1:
+ DPRINTF(("uhidev_open: failed in someway"));
+ free(sc->sc_ibuf, M_USBDEV);
+ scd->sc_state &= ~UHIDEV_OPEN;
+ sc->sc_refcnt = 0;
+ sc->sc_ipipe = NULL;
+ sc->sc_opipe = NULL;
+ if (sc->sc_oxfer != NULL) {
+ usbd_free_xfer(sc->sc_oxfer);
+ sc->sc_oxfer = NULL;
+ }
+ if (sc->sc_owxfer != NULL) {
+ usbd_free_xfer(sc->sc_owxfer);
+ sc->sc_owxfer = NULL;
+ }
+ return (error);
}
void
@@ -493,11 +575,23 @@ uhidev_close(struct uhidev *scd)
return;
DPRINTF(("uhidev_close: close pipe\n"));
+ if (sc->sc_oxfer != NULL)
+ usbd_free_xfer(sc->sc_oxfer);
+
+ if (sc->sc_owxfer != NULL)
+ usbd_free_xfer(sc->sc_owxfer);
+
/* Disable interrupts. */
- if (sc->sc_intrpipe != NULL) {
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
- sc->sc_intrpipe = NULL;
+ if (sc->sc_opipe != NULL) {
+ usbd_abort_pipe(sc->sc_opipe);
+ usbd_close_pipe(sc->sc_opipe);
+ sc->sc_opipe = NULL;
+ }
+
+ if (sc->sc_ipipe != NULL) {
+ usbd_abort_pipe(sc->sc_ipipe);
+ usbd_close_pipe(sc->sc_ipipe);
+ sc->sc_ipipe = NULL;
}
if (sc->sc_ibuf != NULL) {
@@ -550,3 +644,28 @@ uhidev_get_report(struct uhidev *scd, int type, void *data, int len)
return usbd_get_report(scd->sc_parent->sc_iface, type,
scd->sc_report_id, data, len);
}
+
+usbd_status
+uhidev_write(struct uhidev_softc *sc, void *data, int len)
+{
+
+ DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
+
+ if (sc->sc_opipe == NULL)
+ return USBD_INVAL;
+
+#ifdef UHIDEV_DEBUG
+ if (uhidevdebug > 50) {
+
+ u_int32_t i;
+ u_int8_t *d = data;
+
+ DPRINTF(("uhidev_write: data ="));
+ for (i = 0; i < len; i++)
+ DPRINTF((" %02x", d[i]));
+ DPRINTF(("\n"));
+ }
+#endif
+ return usbd_intr_transfer(sc->sc_owxfer, sc->sc_opipe, 0,
+ USBD_NO_TIMEOUT, data, &len, "uhidevwi");
+}
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index dd9190c1f62..ce37bd8a26c 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhidev.h,v 1.5 2006/03/07 04:41:19 krw Exp $ */
+/* $OpenBSD: uhidev.h,v 1.6 2006/08/18 02:54:11 jason Exp $ */
/* $NetBSD: uhidev.h,v 1.3 2002/10/08 09:56:17 dan Exp $ */
/*
@@ -51,12 +51,18 @@ struct uhidev_softc {
USBBASEDEVICE sc_dev; /* base device */
usbd_device_handle sc_udev;
usbd_interface_handle sc_iface; /* interface */
- usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
- int sc_ep_addr;
+ usbd_pipe_handle sc_ipipe; /* input interrupt pipe */
+ usbd_xfer_handle sc_ixfer; /* read request */
+ int sc_iep_addr;
u_char *sc_ibuf;
u_int sc_isize;
+ usbd_pipe_handle sc_opipe; /* output interrupt pipe */
+ usbd_xfer_handle sc_oxfer; /* write request */
+ usbd_xfer_handle sc_owxfer; /* internal write request */
+ int sc_oep_addr;
+
void *sc_repdesc;
int sc_repdesc_size;
@@ -91,3 +97,4 @@ void uhidev_close(struct uhidev *);
usbd_status uhidev_set_report(struct uhidev *scd, int type, void *data,int len);
void uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len);
usbd_status uhidev_get_report(struct uhidev *scd, int type, void *data,int len);
+usbd_status uhidev_write(struct uhidev_softc *, void *, int);