patch-2.4.10 linux/drivers/usb/hub.c
Next file: linux/drivers/usb/hub.h
Previous file: linux/drivers/usb/hiddev.c
Back to the patch index
Back to the overall index
- Lines: 195
- Date:
Thu Sep 20 14:12:28 2001
- Orig file:
v2.4.9/linux/drivers/usb/hub.c
- Orig date:
Mon Aug 27 12:41:45 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
@@ -39,6 +39,18 @@
static int khubd_pid = 0; /* PID of khubd */
static DECLARE_COMPLETION(khubd_exited);
+#ifdef DEBUG
+static inline char *portspeed (int portstatus)
+{
+ if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+ return "480 Mb/s";
+ else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+#endif
+
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -113,7 +125,7 @@
/* Enable power to the ports */
dbg("enabling power on all ports");
- for (i = 0; i < hub->nports; i++)
+ for (i = 0; i < hub->descriptor->bNbrPorts; i++)
usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER);
/* Wait for power to be enabled */
@@ -128,14 +140,14 @@
unsigned int pipe;
int i, maxp, ret;
- hub->descriptor = kmalloc(HUB_DESCRIPTOR_MAX_SIZE, GFP_KERNEL);
+ hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
- err("Unable to kmalloc %d bytes for hub descriptor", HUB_DESCRIPTOR_MAX_SIZE);
+ err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
return -1;
}
/* Request the entire hub descriptor. */
- ret = usb_get_hub_descriptor(dev, hub->descriptor, HUB_DESCRIPTOR_MAX_SIZE);
+ ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
/* <hub->descriptor> is large enough for a hub with 127 ports;
* the hub can/will return fewer bytes here. */
if (ret < 0) {
@@ -144,10 +156,10 @@
return -1;
}
- le16_to_cpus(&hub->descriptor->wHubCharacteristics);
+ dev->maxchild = hub->descriptor->bNbrPorts;
+ info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");
- hub->nports = dev->maxchild = hub->descriptor->bNbrPorts;
- info("%d port%s detected", hub->nports, (hub->nports == 1) ? "" : "s");
+ le16_to_cpus(&hub->descriptor->wHubCharacteristics);
if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
dbg("part of a compound device");
@@ -180,6 +192,40 @@
break;
}
+ switch (dev->descriptor.bDeviceProtocol) {
+ case 0:
+ break;
+ case 1:
+ dbg("Single TT");
+ break;
+ case 2:
+ dbg("Multiple TT");
+ break;
+ default:
+ dbg("Unrecognized hub protocol %d",
+ dev->descriptor.bDeviceProtocol);
+ break;
+ }
+
+ switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
+ case 0x00:
+ if (dev->descriptor.bDeviceProtocol != 0)
+ dbg("TT requires at most 8 FS bit times");
+ break;
+ case 0x20:
+ dbg("TT requires at most 16 FS bit times");
+ break;
+ case 0x40:
+ dbg("TT requires at most 24 FS bit times");
+ break;
+ case 0x60:
+ dbg("TT requires at most 32 FS bit times");
+ break;
+ }
+
+ dbg("Port indicators are %s supported",
+ (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");
+
dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2);
dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent);
@@ -397,7 +443,7 @@
int i;
/* Disconnect any attached devices */
- for (i = 0; i < hub->nports; i++) {
+ for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
if (dev->children[i])
usb_disconnect(&dev->children[i]);
}
@@ -444,6 +490,7 @@
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500
+/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay)
{
@@ -465,18 +512,25 @@
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
dbg("port %d, portstatus %x, change %x, %s", port + 1,
- portstatus, portchange,
- portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
+ portstatus, portchange, portspeed (portstatus));
+
+ /* Device went away? */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION))
+ return 1;
/* bomb out completely if something weird happened */
- if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
- !(portstatus & USB_PORT_STAT_CONNECTION))
+ if ((portchange & USB_PORT_STAT_C_CONNECTION))
return -1;
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
- dev->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ dev->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ dev->speed = USB_SPEED_LOW;
+ else
+ dev->speed = USB_SPEED_FULL;
return 0;
}
@@ -491,19 +545,21 @@
return -1;
}
+/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay)
{
- int i;
+ int i, status;
/* Reset the port */
for (i = 0; i < HUB_RESET_TRIES; i++) {
usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
- /* return success if the port reset OK */
- if (!usb_hub_port_wait_reset(hub, port, dev, delay)) {
+ /* return on disconnect or reset */
+ status = usb_hub_port_wait_reset(hub, port, dev, delay);
+ if (status != -1) {
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
- return 0;
+ return status;
}
dbg("port %d of hub %d not enabled, trying reset again...",
@@ -539,8 +595,8 @@
portstatus = le16_to_cpu(portsts->wPortStatus);
portchange = le16_to_cpu(portsts->wPortChange);
- dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus,
- portchange, portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
+ dbg("port %d, portstatus %x, change %x, %s",
+ port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -686,7 +742,7 @@
hub->error = 0;
}
- for (i = 0; i < hub->nports; i++) {
+ for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
struct usb_port_status portsts;
unsigned short portstatus, portchange;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)