Greg:
This patch implements the Windows scheme for USB device initialization.
It also incorporates the change recently posted by David to scrub the
endpoint state following a SET-ADDRESS. Other noteworthy changes:
There is a #undef near the start of the source file which can
be changed to #define to enable use of the old initialization
scheme. If the symbol is not defined then most of the old code
will be optimized away by the compiler.
hub_set_address() returns 0 immediately if the device is already
in the USB_STATE_ADDRESS state.
On the first attempt to read the device descriptor the code
uses a short 1-second timeout. This ought to help prevent
full-speed devices with an 8- or 16-byte maxpacket from
slowing the procedure down by NAKing the unexpectedly early
status stage of the transfer.
For debugging, the ep0 maxpacket value is printed. It might
be a good idea to validate it rather than just believing the
device -- although I haven't heard of any device providing
an incorrect value other than 0.
This should get plenty of testing. Folks on linux-usb-users have already
shown that a preliminary version of the patch allows Sony camcorders to
work properly, which they don't with the current code.
Alan Stern
Signed-off-by: Alan Stern [EMAIL PROTECTED]
= drivers/usb/core/hub.c 1.204 vs edited =
--- 1.204/drivers/usb/core/hub.c2004-09-20 10:53:16 -04:00
+++ edited/drivers/usb/core/hub.c 2004-10-13 16:27:02 -04:00
@@ -8,6 +8,15 @@
*
*/
+/* As of 2.6.10 we use a new USB device initialization scheme which closely
+ * resembles the way Windows works. Hopefully it will be compatible with a
+ * wider range of devices than the old scheme. However some previously-
+ * working devices may start giving rise to device not accepting address
+ * errors; if that happens the user can try using the old scheme in addition
+ * to the new one by changing the following #undef to #define.
+ */
+#undef USE_OLD_DEVICE_INIT_SCHEME
+
#include linux/config.h
#ifdef CONFIG_USB_DEBUG
#define DEBUG
@@ -1265,7 +1274,14 @@
#define PORT_RESET_TRIES 5
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
+
+#ifdef USE_OLD_DEVICE_INIT_SCHEME
+#define SET_CONFIG_TRIES 4
+#define use_new_scheme(i) ((i) 2)
+#else
#define SET_CONFIG_TRIES 2
+#define use_new_scheme(i) 1
+#endif
#define HUB_ROOT_RESET_TIME50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
@@ -1983,20 +1999,30 @@
return portstatus;
}
+#define usb_sndaddr0pipe() (PIPE_CONTROL 30)
+#define usb_rcvaddr0pipe() ((PIPE_CONTROL 30) | USB_DIR_IN)
+
static int hub_set_address(struct usb_device *udev)
{
int retval;
if (udev-devnum == 0)
return -EINVAL;
- if (udev-state != USB_STATE_DEFAULT
- udev-state != USB_STATE_ADDRESS)
+ if (udev-state == USB_STATE_ADDRESS)
+ return 0;
+ if (udev-state != USB_STATE_DEFAULT)
return -EINVAL;
- retval = usb_control_msg(udev, (PIPE_CONTROL 30) /* Address 0 */,
+ retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, udev-devnum, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
- if (retval == 0)
+ if (retval == 0) {
+ int m = udev-epmaxpacketin[0];
+
usb_set_device_state(udev, USB_STATE_ADDRESS);
+ usb_disable_endpoint(udev, 0 + USB_DIR_IN);
+ usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
+ udev-epmaxpacketin[0] = udev-epmaxpacketout[0] = m;
+ }
return retval;
}
@@ -2010,7 +2036,8 @@
* pointers, it's not necessary to lock the device.
*/
static int
-hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
+hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port,
+ int retry_counter)
{
static DECLARE_MUTEX(usb_address0_sem);
@@ -2049,6 +2076,7 @@
dev_dbg(udev-dev, device reset changed speed!\n);
goto fail;
}
+ oldspeed = udev-speed;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
@@ -2058,22 +2086,22 @@
i = 64;
break;
case USB_SPEED_FULL:/* 8, 16, 32, or 64 */
- /* to determine the ep0 maxpacket size, read the first 8
-* bytes from the device descriptor to get bMaxPacketSize0;
-* then correct our initial (small) guess.
+ /* to determine the ep0 maxpacket size, try to read
+* the device descriptor to get bMaxPacketSize0 and
+* then correct our initial guess.
*/
- // FALLTHROUGH
+