Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/nick-nhusb]: src/sys/dev/usb More changes from Takahiro HAYASHI
details: https://anonhg.NetBSD.org/src/rev/f8b77bffe415
branches: nick-nhusb
changeset: 804356:f8b77bffe415
user: skrll <skrll%NetBSD.org@localhost>
date: Thu May 28 06:15:47 2015 +0000
description:
More changes from Takahiro HAYASHI
+ Add sc_statuspend that stores ports bitmap of pending interrupts
instead of sc_isxhciroothub hack til someone implements suspend pipe.
While sc_explorepending == 1, uhub_intr shall merge sc_status into
sc_statuspend.
+ Eliminate confusing UPS_SUPER_SPEED flag and introduce
UPS_OTHER_SPEED flag that indicates ud_speed of device is
super speed (or more).
uhub shall set this flag if ud_speed is super speed (or more).
+ Add the macro that checks ud_speed is super speed.
The codes shall use this macro to check ud_speed is super speed.
+ Add speed type conversion functions.
+ Include port link status in port_status if port is super speed.
Various other changes to support SS hubs and devices
diffstat:
sys/dev/usb/uhub.c | 207 ++++++++++++++++++++++++++++++++++++++++++++--------
sys/dev/usb/usb.h | 9 +-
sys/dev/usb/xhci.c | 89 ++++++++++++----------
3 files changed, 228 insertions(+), 77 deletions(-)
diffs (truncated from 597 to 300 lines):
diff -r baaf84247341 -r f8b77bffe415 sys/dev/usb/uhub.c
--- a/sys/dev/usb/uhub.c Wed May 27 07:22:51 2015 +0000
+++ b/sys/dev/usb/uhub.c Thu May 28 06:15:47 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uhub.c,v 1.126.2.11 2015/04/07 06:23:10 skrll Exp $ */
+/* $NetBSD: uhub.c,v 1.126.2.12 2015/05/28 06:15:47 skrll Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
/*
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.11 2015/04/07 06:23:10 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.12 2015/05/28 06:15:47 skrll Exp $");
#include <sys/param.h>
@@ -104,6 +104,7 @@
/* XXX second buffer needed because we can't suspend pipes yet */
uint8_t *sc_statusbuf;
+ uint8_t *sc_statuspend;
uint8_t *sc_status;
size_t sc_statuslen;
int sc_explorepending;
@@ -112,7 +113,8 @@
u_char sc_running;
};
-#define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
+#define UHUB_IS_HIGH_SPEED(sc) \
+ ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
#define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
#define PORTSTAT_ISSET(sc, port) \
@@ -147,6 +149,76 @@
*/
int uhub_ubermatch = 0;
+static usbd_status
+usbd_get_hub_desc(struct usbd_device *dev, usb_hub_descriptor_t *hd, int speed)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ int nports;
+
+ UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+ /* don't issue UDESC_HUB to SS hub, or it would stall */
+ if (dev->ud_depth != 0 && USB_IS_SS(dev->ud_speed)) {
+ usb_hub_ss_descriptor_t hssd;
+ int rmvlen;
+
+ memset(&hssd, 0, sizeof(hssd));
+ req.bmRequestType = UT_READ_CLASS_DEVICE;
+ req.bRequest = UR_GET_DESCRIPTOR;
+ USETW2(req.wValue, UDESC_SS_HUB, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
+ DPRINTFN(1, "getting sshub descriptor", 0, 0, 0, 0);
+ err = usbd_do_request(dev, &req, &hssd);
+ nports = hssd.bNbrPorts;
+ if (dev->ud_depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+ DPRINTF("num of ports %d exceeds maxports %d",
+ nports, UHD_SS_NPORTS_MAX, 0, 0);
+ nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
+ }
+ rmvlen = (nports + 7) / 8;
+ hd->bDescLength = USB_HUB_DESCRIPTOR_SIZE +
+ (rmvlen > 1 ? rmvlen : 1) - 1;
+ memcpy(hd->DeviceRemovable, hssd.DeviceRemovable, rmvlen);
+ hd->bDescriptorType = hssd.bDescriptorType;
+ hd->bNbrPorts = hssd.bNbrPorts;
+ hd->wHubCharacteristics[0] = hssd.wHubCharacteristics[0];
+ hd->wHubCharacteristics[1] = hssd.wHubCharacteristics[1];
+ hd->bPwrOn2PwrGood = hssd.bPwrOn2PwrGood;
+ hd->bHubContrCurrent = hssd.bHubContrCurrent;
+ } else {
+ req.bmRequestType = UT_READ_CLASS_DEVICE;
+ req.bRequest = UR_GET_DESCRIPTOR;
+ USETW2(req.wValue, UDESC_HUB, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
+ DPRINTFN(1, "getting hub descriptor", 0, 0, 0, 0);
+ err = usbd_do_request(dev, &req, hd);
+ nports = hd->bNbrPorts;
+ if (!err && nports > 7) {
+ USETW(req.wLength,
+ USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
+ err = usbd_do_request(dev, &req, hd);
+ }
+ }
+
+ return err;
+}
+
+static usbd_status
+usbd_set_hub_depth(struct usbd_device *dev, int depth)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_CLASS_DEVICE;
+ req.bRequest = UR_SET_HUB_DEPTH;
+ USETW(req.wValue, depth);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ return usbd_do_request(dev, &req, 0);
+}
+
int
uhub_match(device_t parent, cfdata_t match, void *aux)
{
@@ -179,7 +251,6 @@
char *devinfop;
usbd_status err;
struct usbd_hub *hub = NULL;
- usb_device_request_t req;
usb_hub_descriptor_t hubdesc;
int p, port, nports, nremov, pwrdly;
struct usbd_interface *iface;
@@ -219,18 +290,9 @@
}
/* Get hub descriptor. */
- req.bmRequestType = UT_READ_CLASS_DEVICE;
- req.bRequest = UR_GET_DESCRIPTOR;
- USETW2(req.wValue, UDESC_HUB, 0);
- USETW(req.wIndex, 0);
- USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
- DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
- err = usbd_do_request(dev, &req, &hubdesc);
+ memset(&hubdesc, 0, sizeof(hubdesc));
+ err = usbd_get_hub_desc(dev, &hubdesc, dev->ud_speed);
nports = hubdesc.bNbrPorts;
- if (!err && nports > 7) {
- USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
- err = usbd_do_request(dev, &req, &hubdesc);
- }
if (err) {
DPRINTF("getting hub descriptor failed, uhub %d error %d",
device_unit(self), err, 0, 0);
@@ -258,6 +320,16 @@
hub->uh_explore = uhub_explore;
hub->uh_hubdesc = hubdesc;
+ if (USB_IS_SS(dev->ud_speed) && dev->ud_depth != 0) {
+ aprint_debug_dev(self, "setting hub depth %u\n",
+ dev->ud_depth-1);
+ err = usbd_set_hub_depth(dev, dev->ud_depth - 1);
+ if (err) {
+ aprint_error_dev(self, "can't set depth\n");
+ goto bad;
+ }
+ }
+
/* Set up interrupt pipe. */
err = usbd_device2interface_handle(dev, 0, &iface);
if (err) {
@@ -285,6 +357,9 @@
sc->sc_statusbuf = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
if (!sc->sc_statusbuf)
goto bad;
+ sc->sc_statuspend = kmem_zalloc(sc->sc_statuslen, KM_SLEEP);
+ if (!sc->sc_statuspend)
+ goto bad;
sc->sc_status = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
if (!sc->sc_status)
goto bad;
@@ -395,6 +470,8 @@
bad:
if (sc->sc_status)
kmem_free(sc->sc_status, sc->sc_statuslen);
+ if (sc->sc_statuspend)
+ kmem_free(sc->sc_statuspend, sc->sc_statuslen);
if (sc->sc_statusbuf)
kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
if (hub)
@@ -469,6 +546,10 @@
}
status = UGETW(up->up_status.wPortStatus);
change = UGETW(up->up_status.wPortChange);
+ if (USB_IS_SS(dev->ud_speed)) {
+ status |= UPS_OTHER_SPEED;
+ USETW(up->up_status.wPortStatus, status);
+ }
DPRINTF("uhub %d port %d: s/c=%x/%x",
device_unit(sc->sc_dev), port, status, change);
@@ -505,10 +586,26 @@
port);
}
}
+ int is_wrc = 0;
+ if (change & UPS_C_PORT_RESET)
+ usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+ if (change & UPS_C_BH_PORT_RESET) {
+ is_wrc = 1;
+ usbd_clear_port_feature(dev, port,
+ UHF_C_BH_PORT_RESET);
+ }
+ if (change & UPS_C_PORT_LINK_STATE)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_PORT_LINK_STATE);
+ if (change & UPS_C_PORT_CONFIG_ERROR)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_PORT_CONFIG_ERROR);
/* XXX handle overcurrent and resume events! */
- if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
+ /* xHCI sets WRC instead of CSC when port is reset */
+ if (!reconnect && !(change & UPS_C_CONNECT_STATUS) &&
+ !(is_wrc && (status & UPS_CURRENT_CONNECT_STATUS))) {
/* No status change, just do recursive explore. */
if (up->up_dev != NULL && up->up_dev->ud_hub != NULL)
up->up_dev->ud_hub->uh_explore(up->up_dev);
@@ -537,11 +634,15 @@
usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
usbd_clear_port_feature(dev, port,
UHF_C_PORT_CONNECTION);
+ continue;
}
if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
/* Nothing connected, just ignore it. */
DPRINTFN(3, "uhub %d port=%d !CURRENT_CONNECT_STATUS",
device_unit(sc->sc_dev), port, 0, 0);
+ usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
+ usbd_clear_port_feature(dev, port,
+ UHF_C_PORT_CONNECTION);
continue;
}
@@ -549,9 +650,22 @@
DPRINTF("unit %d dev->speed=%u dev->depth=%u",
device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);
- if (!(status & UPS_PORT_POWER))
- aprint_normal_dev(sc->sc_dev,
- "strange, connected port %d has no power\n", port);
+ /*
+ * To check whether port has power,
+ * check UPS_PORT_POWER bit if port speed is HS/FS/LS and
+ * check UPS_PORT_POWER_SS bit if port speed is SS.
+ */
+ if (status & UPS_OTHER_SPEED) {
+ if (!(status & UPS_PORT_POWER_SS))
+ aprint_normal_dev(sc->sc_dev,
+ "strange, connected port %d has no power\n",
+ port);
+ } else {
+ if (!(status & UPS_PORT_POWER))
+ aprint_normal_dev(sc->sc_dev,
+ "strange, connected port %d has no power\n",
+ port);
+ }
/* Wait for maximum device power up time. */
usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
@@ -571,6 +685,10 @@
}
status = UGETW(up->up_status.wPortStatus);
change = UGETW(up->up_status.wPortChange);
+ if (USB_IS_SS(dev->ud_speed)) {
+ status |= UPS_OTHER_SPEED;
+ USETW(up->up_status.wPortStatus, status);
+ }
DPRINTF("hub %d port %d after reset: s/c=%x/%x",
device_unit(sc->sc_dev), port, status, change);
@@ -590,14 +708,15 @@
#endif
continue;
}
+ /* port reset may cause Warm Reset Change, drop it. */
+ if (change & UPS_C_BH_PORT_RESET)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_BH_PORT_RESET);
/* Figure out device speed */
-#if 0
- if (status & UPS_SUPER_SPEED)
+ if (status & UPS_OTHER_SPEED) {
speed = USB_SPEED_SUPER;
- else
-#endif
- if (status & UPS_HIGH_SPEED)
+ } else if (status & UPS_HIGH_SPEED)
speed = USB_SPEED_HIGH;
else if (status & UPS_LOW_SPEED)
speed = USB_SPEED_LOW;
@@ -637,6 +756,15 @@
if (!sc->sc_isehciroothub)
memset(sc->sc_status, 0, sc->sc_statuslen);
sc->sc_explorepending = 0;
+ for (int i = 0; i < sc->sc_statuslen; i++) {
+ if (sc->sc_statuspend[i] != 0) {
+ memcpy(sc->sc_status, sc->sc_statuspend,
+ sc->sc_statuslen);
+ memset(sc->sc_statuspend, 0, sc->sc_statuslen);
Home |
Main Index |
Thread Index |
Old Index