patch-2.3.35 linux/drivers/usb/hub.c

Next file: linux/drivers/usb/inits.h
Previous file: linux/drivers/usb/hp_scanner.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.34/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
@@ -4,6 +4,8 @@
  * (C) Copyright 1999 Linus Torvalds
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Gregory P. Smith
+ *
+ * $Id: hub.c,v 1.15 1999/12/27 15:17:45 acher Exp $
  */
 
 #include <linux/kernel.h>
@@ -45,6 +47,12 @@
 		USB_DT_HUB << 8, 0, data, size, HZ);
 }
 
+static int usb_clear_hub_feature(struct usb_device *dev,  int feature)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0 , NULL, 0, HZ);
+}
+
 static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
 {
 	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -190,7 +198,6 @@
 	printk(KERN_INFO "hub: enabling power on all ports\n");
 	for (i = 0; i < hub->nports; i++)
 		usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
-
 	return 0;
 }
 
@@ -305,7 +312,9 @@
 	struct usb_device *usb;
 	struct usb_port_status portsts;
 	unsigned short portstatus, portchange;
+	int tries;
 
+	wait_ms(100);
 	/* Check status */
 	if (usb_get_port_status(hub, port + 1, &portsts)<0) {
 		printk(KERN_ERR "get_port_status failed\n");
@@ -314,7 +323,8 @@
 
 	portstatus = le16_to_cpu(portsts.wPortStatus);
 	portchange = le16_to_cpu(portsts.wPortChange);
-	printk("hub.c: portstatus %x, change %x\n",portstatus,portchange);
+	printk("hub.c: portstatus %x, change %x, %s\n",portstatus,portchange,
+	(portstatus&(1<<USB_PORT_FEAT_LOWSPEED)?"Low Speed":"High Speed"));
 	/* If it's not in CONNECT and ENABLE state, we're done */
 	if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
 	    (!(portstatus & USB_PORT_STAT_ENABLE))) {
@@ -324,10 +334,37 @@
 		return;
 	}
 	wait_ms(400);	
+
 	/* Reset the port */
-	usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
-	wait_ms(100);	
+
+#define MAX_TRIES 5
+	
+	for(tries=0;tries<MAX_TRIES;tries++) {
+		
+		usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+		wait_ms(200);	
+		
+		if (usb_get_port_status(hub, port + 1, &portsts)<0) {
+			printk(KERN_ERR "get_port_status failed\n");
+			return;
+		}
+		portstatus = le16_to_cpu(portsts.wPortStatus);
+		portchange = le16_to_cpu(portsts.wPortChange);
+		printk("hub.c: portstatus %x, change %x, %s\n",portstatus,portchange,
+		(portstatus&(1<<USB_PORT_FEAT_LOWSPEED)?"Low Speed":"High Speed"));
+
+		if ((portstatus&(1<<USB_PORT_FEAT_ENABLE))) 
+			break;
+
+		wait_ms(200);
+	}
+
+	if (tries==MAX_TRIES) {
+		printk("hub.c: Can not enable port %i after %i retries, disabling port\n",port+1,MAX_TRIES);
+		return;
+	}
 	/* Allocate a new device struct for it */
+
 	usb = usb_alloc_dev(hub, hub->bus);
 	if (!usb) {
 		printk(KERN_ERR "couldn't allocate usb_device\n");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)