diff options
-rw-r--r-- | sys/dev/usb/ehci.c | 8 | ||||
-rw-r--r-- | sys/dev/usb/ohci.c | 5 | ||||
-rw-r--r-- | sys/dev/usb/uhci.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 3 | ||||
-rw-r--r-- | sys/dev/usb/usb_quirks.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/usb_quirks.h | 4 | ||||
-rw-r--r-- | sys/dev/usb/usb_subr.c | 52 | ||||
-rw-r--r-- | sys/dev/usb/usbdivar.h | 4 |
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, |