ChangeSet 1.1188, 2003/05/20 12:10:28-07:00, david-b@pacbell.net

[PATCH] USB: disable usb device endpoints in more places

This patch touches the most significant places in usbcore
that need to respond to configuration change events:

  - set_interface changes altsettings; affects endpoints
    in both new and old settings (but not other endpoints).

  - set_configuration; affects every endpoint

The endpoints get disabled, flushing hardware state
reliably.  This resolves two FIXMEs here, part of one
in OHCI (ed_get) and all of one in EHCI (qh_append_tds).

Not many drivers currently use these code paths, but
now they should start to work properly.


diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Tue May 20 17:24:49 2003
+++ b/drivers/usb/core/message.c	Tue May 20 17:24:49 2003
@@ -795,6 +795,7 @@
 	struct usb_interface *iface;
 	struct usb_host_interface *iface_as;
 	int i, ret;
+	void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
 
 	iface = usb_ifnum_to_if(dev, interface);
 	if (!iface) {
@@ -832,9 +833,11 @@
 		u8	ep = iface_as->endpoint [i].desc.bEndpointAddress;
 		int	out = !(ep & USB_DIR_IN);
 
+		/* clear out hcd state, then usbcore state */
+		if (disable)
+			disable (dev, ep);
 		ep &= USB_ENDPOINT_NUMBER_MASK;
 		(out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0;
-		// FIXME want hcd hook here, "no such endpoint"
 	}
 	iface->act_altsetting = alternate;
 
@@ -898,6 +901,7 @@
 {
 	int i, ret;
 	struct usb_host_config *cp = NULL;
+	void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
 	
 	for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
 		if (dev->config[i].desc.bConfigurationValue == configuration) {
@@ -911,11 +915,15 @@
 	}
 
 	/* if it's already configured, clear out old state first. */
-	if (dev->state != USB_STATE_ADDRESS) {
-		/* FIXME unbind drivers from all "old" interfaces.
-		 * handshake with hcd to reset cached hc endpoint state.
-		 */
+	if (dev->state != USB_STATE_ADDRESS && disable) {
+		for (i = 0; i < 15; i++) {
+			disable (dev, i);
+			disable (dev, USB_DIR_IN | i);
+		}
 	}
+	dev->toggle[0] = dev->toggle[1] = 0;
+	dev->halted[0] = dev->halted[1] = 0;
+	dev->state = USB_STATE_ADDRESS;
 
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -923,15 +931,9 @@
 		return ret;
 	if (configuration)
 		dev->state = USB_STATE_CONFIGURED;
-	else
-		dev->state = USB_STATE_ADDRESS;
 	dev->actconfig = cp;
 
 	/* reset more hc/hcd endpoint state */
-	dev->toggle[0] = 0;
-	dev->toggle[1] = 0;
-	dev->halted[0] = 0;
-	dev->halted[1] = 0;
 	usb_set_maxpacket(dev);
 
 	return 0;
