summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYojiro Uo <yuo@cvs.openbsd.org>2008-06-29 10:04:16 +0000
committerYojiro Uo <yuo@cvs.openbsd.org>2008-06-29 10:04:16 +0000
commit8d7845fd770d4f2e89eaf7c6acd6ee8711a4bf3a (patch)
treeae1cbf278151c1a5341cab824075deafb24efe01
parent99e04e378e33075d748641da5140863b7b7f982d (diff)
add usb2.0 to usb1.1(ohci/uchi) handover request to usb subsystem.
add new quirk entry for uvideo which is required isoc transfer. Some usb2.0 devices use isochronous transfer but current usb subsystem does not support isoc transfer in ehci(usb2.0) bus. This patch introduce new psuedo usb hub request UHF_PORT_DISOWN_TO_1_1 to handover the device to ehci to usb1.1 bus(ohci or uhci). ok mglocker@ deraadt@ fgsch@
-rw-r--r--sys/dev/usb/ehci.c8
-rw-r--r--sys/dev/usb/ohci.c5
-rw-r--r--sys/dev/usb/uhci.c6
-rw-r--r--sys/dev/usb/usb.h3
-rw-r--r--sys/dev/usb/usb_quirks.c4
-rw-r--r--sys/dev/usb/usb_quirks.h4
-rw-r--r--sys/dev/usb/usb_subr.c52
-rw-r--r--sys/dev/usb/usbdivar.h4
8 files changed, 77 insertions, 9 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 360797439b0..da641102b1d 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.83 2008/06/26 05:42:18 ray Exp $ */
+/* $OpenBSD: ehci.c,v 1.84 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -1897,6 +1897,12 @@ ehci_root_ctrl_start(usbd_xfer_handle xfer)
case UHF_PORT_SUSPEND:
EOWRITE4(sc, port, v | EHCI_PS_SUSP);
break;
+ case UHF_PORT_DISOWN_TO_1_1:
+ /* enter to Port Reset State */
+ v &= ~EHCI_PS_PE;
+ EOWRITE4(sc, port, v | EHCI_PS_PR);
+ ehci_disown(sc, index, 0);
+ break;
case UHF_PORT_RESET:
DPRINTFN(5,("ehci_root_ctrl_start: reset port %d\n",
index));
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 41b93638092..6f99c172624 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ohci.c,v 1.86 2008/06/26 05:42:18 ray Exp $ */
+/* $OpenBSD: ohci.c,v 1.87 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
@@ -2659,6 +2659,9 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
"%d\n", index));
OWRITE4(sc, port, UPS_PORT_POWER);
break;
+ case UHF_PORT_DISOWN_TO_1_1:
+ /* accept, but do nothing */
+ break;
default:
err = USBD_IOERROR;
goto ret;
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 0565ef0059b..586eedbc6f5 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhci.c,v 1.67 2008/06/26 05:42:18 ray Exp $ */
+/* $OpenBSD: uhci.c,v 1.68 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
@@ -3379,6 +3379,10 @@ uhci_root_ctrl_start(usbd_xfer_handle xfer)
/* Pretend we turned on power */
err = USBD_NORMAL_COMPLETION;
goto ret;
+ case UHF_PORT_DISOWN_TO_1_1:
+ /* accept, but do nothing */
+ err = USBD_NORMAL_COMPLETION;
+ goto ret;
case UHF_C_PORT_CONNECTION:
case UHF_C_PORT_ENABLE:
case UHF_C_PORT_OVER_CURRENT:
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index 8f7d01b3972..04a04173686 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb.h,v 1.31 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usb.h,v 1.32 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: usb.h,v 1.69 2002/09/22 23:20:50 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */
@@ -285,6 +285,7 @@ typedef struct {
#define UHF_C_PORT_RESET 20
#define UHF_PORT_TEST 21
#define UHF_PORT_INDICATOR 22
+#define UHF_PORT_DISOWN_TO_1_1 30
typedef struct {
uByte bDescLength;
diff --git a/sys/dev/usb/usb_quirks.c b/sys/dev/usb/usb_quirks.c
index 866c86ecf88..f2c4a248cae 100644
--- a/sys/dev/usb/usb_quirks.c
+++ b/sys/dev/usb/usb_quirks.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_quirks.c,v 1.42 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usb_quirks.c,v 1.43 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: usb_quirks.c,v 1.45 2003/05/10 17:47:14 hamajima Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.30 2003/01/02 04:15:55 imp Exp $ */
@@ -158,7 +158,7 @@ const struct usbd_dev_quirk_entry {
u_int8_t bDeviceProtocol;
struct usbd_quirks quirks;
} usb_dev_quirks[] = {
- /* currently this table is empty */
+ { UDCLASS_VIDEO, bANY, bANY, { UQ_EHCI_NEEDTO_DISOWN }},
{ 0, 0, 0, { 0 } }
};
diff --git a/sys/dev/usb/usb_quirks.h b/sys/dev/usb/usb_quirks.h
index 93dbfab9005..ef398007e04 100644
--- a/sys/dev/usb/usb_quirks.h
+++ b/sys/dev/usb/usb_quirks.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_quirks.h,v 1.12 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usb_quirks.h,v 1.13 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: usb_quirks.h,v 1.20 2001/04/15 09:38:01 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_quirks.h,v 1.9 1999/11/12 23:31:03 n_hibma Exp $ */
@@ -68,6 +68,8 @@ struct usbd_quirks {
#define UQ_MS_BAD_CLASS 0x00008000
/* mouse sends an unknown leading byte. */
#define UQ_MS_LEADING_BYTE 0x00010000
+ /* need to attach as 1.1 device if it is 2.0 */
+#define UQ_EHCI_NEEDTO_DISOWN 0x00020000
};
extern const struct usbd_quirks usbd_no_quirk;
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 2d6ac2d77fd..0b682d87a09 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_subr.c,v 1.68 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.69 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
@@ -352,6 +352,42 @@ usbd_delay_ms(usbd_device_handle dev, u_int ms)
}
usbd_status
+usbd_port_disown_to_1_1(usbd_device_handle dev, int port, usb_port_status_t *ps)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ int n;
+
+ req.bmRequestType = UT_WRITE_CLASS_OTHER;
+ req.bRequest = UR_SET_FEATURE;
+ USETW(req.wValue, UHF_PORT_DISOWN_TO_1_1);
+ USETW(req.wIndex, port);
+ USETW(req.wLength, 0);
+ err = usbd_do_request(dev, &req, 0);
+ DPRINTF(("usbd_disown_to_1_1: port %d disown request done, error=%s\n",
+ port, usbd_errstr(err)));
+ if (err)
+ return (err);
+ n = 10;
+ do {
+ /* Wait for device to recover from reset. */
+ usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
+ err = usbd_get_port_status(dev, port, ps);
+ if (err) {
+ DPRINTF(("%s: get status failed %d\n", __func__, err));
+ return (err);
+ }
+ /* If the device disappeared, just give up. */
+ if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
+ return (USBD_NORMAL_COMPLETION);
+ } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
+ if (n == 0)
+ return (USBD_TIMEOUT);
+
+ return (err);
+}
+
+usbd_status
usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
{
usb_device_request_t req;
@@ -1127,6 +1163,20 @@ usbd_new_device(struct device *parent, usbd_bus_handle bus, int depth,
return (err);
}
+ /* send disown request to handover 2.0 to 1.1. */
+ if (dev->quirks->uq_flags & UQ_EHCI_NEEDTO_DISOWN) {
+
+ /* only effective when the target device is on ehci */
+ if (dev->bus->usbrev == USBREV_2_0) {
+ DPRINTF(("%s: disown request issues to dev:%p on usb2.0 bus\n",
+ __func__, dev));
+ (void) usbd_port_disown_to_1_1(dev->myhub, port, &ps);
+ /* reset_port required to finish disown request */
+ (void) usbd_reset_port(dev->myhub, port, &ps);
+ return (USBD_NORMAL_COMPLETION);
+ }
+ }
+
/* Assume 100mA bus powered for now. Changed when configured. */
dev->power = USB_MIN_POWER;
dev->self_powered = 0;
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 721b7592480..feed6655134 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.33 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.34 2008/06/29 10:04:15 yuo Exp $ */
/* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -231,6 +231,8 @@ void usbd_dump_pipe(usbd_pipe_handle pipe);
/* Routines from usb_subr.c */
int usbctlprint(void *, const char *);
void usb_delay_ms(usbd_bus_handle, u_int);
+usbd_status usbd_port_disown_to_1_1(usbd_device_handle dev,
+ int port, usb_port_status_t *ps);
usbd_status usbd_reset_port(usbd_device_handle dev,
int port, usb_port_status_t *ps);
usbd_status usbd_setup_pipe(usbd_device_handle dev,