bk://kernel.bkbits.net/gregkh/linux/usb-2.6 stern@rowland.harvard.edu|ChangeSet|20040326223904|07802 stern diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c --- a/drivers/isdn/hisax/hfc_usb.c Sun Mar 28 13:17:10 2004 +++ b/drivers/isdn/hisax/hfc_usb.c Sun Mar 28 13:17:10 2004 @@ -262,7 +262,7 @@ hfc->ctrl_urb->transfer_buffer_length = 0; hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg; hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val; - err = usb_submit_urb(hfc->ctrl_urb, GFP_KERNEL); /* start transfer */ + err = usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */ printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err); } } /* ctrl_start_transfer */ @@ -754,7 +754,7 @@ } } - errcode = usb_submit_urb(urb, GFP_KERNEL); + errcode = usb_submit_urb(urb, GFP_ATOMIC); if(errcode < 0) { printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); @@ -821,7 +821,7 @@ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context); - errcode = usb_submit_urb(urb, GFP_KERNEL); + errcode = usb_submit_urb(urb, GFP_ATOMIC); if(errcode < 0) { printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); @@ -1345,7 +1345,7 @@ /*************************************************/ /* function called to probe a new plugged device */ /*************************************************/ -static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev= interface_to_usbdev(intf); hfcusb_data *context; diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c --- a/drivers/isdn/hisax/st5481_b.c Sun Mar 28 13:17:10 2004 +++ b/drivers/isdn/hisax/st5481_b.c Sun Mar 28 13:17:10 2004 @@ -119,7 +119,7 @@ DBG_ISO_PACKET(0x200,urb); - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_NOIO); } /* @@ -171,8 +171,8 @@ buf_nr = get_buf_nr(b_out->urb, urb); test_and_clear_bit(buf_nr, &b_out->busy); - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); if (b_out->busy == 0) { st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c --- a/drivers/isdn/hisax/st5481_d.c Sun Mar 28 13:17:10 2004 +++ b/drivers/isdn/hisax/st5481_d.c Sun Mar 28 13:17:10 2004 @@ -381,8 +381,8 @@ buf_nr = get_buf_nr(d_out->urb, urb); test_and_clear_bit(buf_nr, &d_out->busy); - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); if (d_out->busy == 0) { st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); @@ -649,7 +649,7 @@ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); } -static int __devinit st5481_setup_d_out(struct st5481_adapter *adapter) +static int st5481_setup_d_out(struct st5481_adapter *adapter) { struct usb_device *dev = adapter->usb_dev; struct usb_host_interface *altsetting; @@ -682,7 +682,7 @@ st5481_release_isocpipes(d_out->urb); } -int __devinit st5481_setup_d(struct st5481_adapter *adapter) +int st5481_setup_d(struct st5481_adapter *adapter) { int retval; diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Sun Mar 28 13:17:10 2004 +++ b/drivers/isdn/hisax/st5481_init.c Sun Mar 28 13:17:10 2004 @@ -58,8 +58,8 @@ * This function will be called when the adapter is plugged * into the USB bus. */ -static int __devinit probe_st5481(struct usb_interface *intf, - const struct usb_device_id *id) +static int probe_st5481(struct usb_interface *intf, + const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct st5481_adapter *adapter; diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c Sun Mar 28 13:17:10 2004 +++ b/drivers/isdn/hisax/st5481_usb.c Sun Mar 28 13:17:10 2004 @@ -48,7 +48,7 @@ // Prepare the URB urb->dev = adapter->usb_dev; - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_ATOMIC); } /* @@ -129,8 +129,8 @@ struct st5481_ctrl *ctrl = &adapter->ctrl; struct ctrl_msg *ctrl_msg; - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); } else { DBG(1,"urb killed"); @@ -239,7 +239,7 @@ * initialization */ -int __devinit st5481_setup_usb(struct st5481_adapter *adapter) +int st5481_setup_usb(struct st5481_adapter *adapter) { struct usb_device *dev = adapter->usb_dev; struct st5481_ctrl *ctrl = &adapter->ctrl; @@ -341,7 +341,7 @@ /* * Initialize the adapter. */ -void __devinit st5481_start(struct st5481_adapter *adapter) +void st5481_start(struct st5481_adapter *adapter) { static const u8 init_cmd_table[]={ SET_DEFAULT,0, @@ -381,7 +381,7 @@ /* * Reset the adapter to default values. */ -void __devexit st5481_stop(struct st5481_adapter *adapter) +void st5481_stop(struct st5481_adapter *adapter) { DBG(8,""); @@ -392,7 +392,7 @@ * isochronous USB helpers */ -static void __devinit +static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf, int num_packets, int packet_size, usb_complete_t complete, @@ -417,7 +417,7 @@ } } -int __devinit +int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, unsigned int pipe, int num_packets, int packet_size, int buf_size, @@ -481,8 +481,8 @@ struct sk_buff *skb; int len, count, status; - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); } else { DBG(1,"urb killed"); @@ -529,10 +529,10 @@ urb->dev = in->adapter->usb_dev; urb->actual_length = 0; - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_ATOMIC); } -int __devinit st5481_setup_in(struct st5481_in *in) +int st5481_setup_in(struct st5481_in *in) { struct usb_device *dev = in->adapter->usb_dev; int retval; diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/Makefile Sun Mar 28 13:17:10 2004 @@ -55,8 +55,11 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_AUERSWALD) += misc/ +obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ +obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_LCD) += misc/ +obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_SPEEDTOUCH) += misc/ diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/config.c Sun Mar 28 13:17:10 2004 @@ -1,28 +1,62 @@ +#include + +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#endif + #include #include #include #include +#include #include #define USB_MAXALTSETTING 128 /* Hard limit */ #define USB_MAXENDPOINTS 30 /* Hard limit */ -/* these maximums are arbitrary */ -#define USB_MAXCONFIG 8 -#define USB_MAXINTERFACES 32 +#define USB_MAXCONFIG 8 /* Arbitrary limit */ + -static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size) +static int find_next_descriptor(unsigned char *buffer, int size, + int dt1, int dt2, int *num_skipped) +{ + struct usb_descriptor_header *h; + int n = 0; + unsigned char *buffer0 = buffer; + + /* Find the next descriptor of type dt1 or dt2 */ + while (size >= sizeof(struct usb_descriptor_header)) { + h = (struct usb_descriptor_header *) buffer; + if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) + break; + buffer += h->bLength; + size -= h->bLength; + ++n; + } + + /* Store the number of descriptors skipped and return the + * number of bytes skipped */ + if (num_skipped) + *num_skipped = n; + return buffer - buffer0; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, + int asnum, struct usb_host_endpoint *endpoint, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_descriptor_header *header; - unsigned char *begin; - int numskipped; + int n, i; header = (struct usb_descriptor_header *)buffer; if (header->bDescriptorType != USB_DT_ENDPOINT) { - warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X", - header->bDescriptorType, USB_DT_ENDPOINT); + dev_err(ddev, "config %d interface %d altsetting %d has an " + "unexpected descriptor of type 0x%X, " + "expecting endpoint type 0x%X\n", + cfgno, inum, asnum, + header->bDescriptorType, USB_DT_ENDPOINT); return -EINVAL; } @@ -31,13 +65,17 @@ else if (header->bLength >= USB_DT_ENDPOINT_SIZE) memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE); else { - warn("invalid endpoint descriptor"); + dev_err(ddev, "config %d interface %d altsetting %d has an " + "invalid endpoint descriptor of length %d\n", + cfgno, inum, asnum, header->bLength); return -EINVAL; } - if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) { - warn("invalid endpoint address 0x%X", - endpoint->desc.bEndpointAddress); + i = endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; + if (i >= 16 || i == 0) { + dev_err(ddev, "config %d interface %d altsetting %d has an " + "invalid endpoint with address 0x%X\n", + cfgno, inum, asnum, endpoint->desc.bEndpointAddress); return -EINVAL; } @@ -46,30 +84,16 @@ buffer += header->bLength; size -= header->bLength; - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); - endpoint->extra = begin; - endpoint->extralen = buffer - begin; - } - - return buffer - buffer0; + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the next endpoint or interface descriptor */ + endpoint->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + endpoint->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific endpoint " + "descriptors\n", n); + return buffer - buffer0 + i; } static void usb_free_intf(struct usb_interface *intf) @@ -78,253 +102,235 @@ if (intf->altsetting) { for (j = 0; j < intf->num_altsetting; j++) { - struct usb_host_interface *as = &intf->altsetting[j]; + struct usb_host_interface *alt = &intf->altsetting[j]; - kfree(as->endpoint); + kfree(alt->endpoint); } kfree(intf->altsetting); } kfree(intf); } -static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, int size) +static int usb_parse_interface(struct device *ddev, int cfgno, + struct usb_host_config *config, unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_interface_descriptor *d; int inum, asnum; struct usb_interface *interface; - struct usb_host_interface *ifp; - int len, numskipped; - struct usb_descriptor_header *header; - unsigned char *begin; - int i, retval; + struct usb_host_interface *alt; + int i, n; + int len, retval; d = (struct usb_interface_descriptor *) buffer; + buffer += d->bLength; + size -= d->bLength; + if (d->bDescriptorType != USB_DT_INTERFACE) { - warn("unexpected descriptor 0x%X, expecting interface, 0x%X", - d->bDescriptorType, USB_DT_INTERFACE); + dev_err(ddev, "config %d has an unexpected descriptor of type " + "0x%X, expecting interface type 0x%X\n", + cfgno, d->bDescriptorType, USB_DT_INTERFACE); return -EINVAL; } inum = d->bInterfaceNumber; - if (inum >= config->desc.bNumInterfaces) { - - /* Skip to the next interface descriptor */ - buffer += d->bLength; - size -= d->bLength; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *) buffer; - - if (header->bDescriptorType == USB_DT_INTERFACE) - break; - buffer += header->bLength; - size -= header->bLength; - } - return buffer - buffer0; - } + if (inum >= config->desc.bNumInterfaces) + goto skip_to_next_interface_descriptor; interface = config->interface[inum]; asnum = d->bAlternateSetting; if (asnum >= interface->num_altsetting) { - warn("invalid alternate setting %d for interface %d", - asnum, inum); + dev_err(ddev, "config %d interface %d has an invalid " + "alternate setting number: %d but max is %d\n", + cfgno, inum, asnum, interface->num_altsetting - 1); return -EINVAL; } - ifp = &interface->altsetting[asnum]; - if (ifp->desc.bLength) { - warn("duplicate descriptor for interface %d altsetting %d", - inum, asnum); + alt = &interface->altsetting[asnum]; + if (alt->desc.bLength) { + dev_err(ddev, "Duplicate descriptor for config %d " + "interface %d altsetting %d\n", cfgno, inum, asnum); return -EINVAL; } - memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); - - buffer += d->bLength; - size -= d->bLength; - - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific interface descriptors", numskipped); - ifp->extra = begin; - ifp->extralen = buffer - begin; - } + memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); - if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { - warn("too many endpoints for interface %d altsetting %d", - inum, asnum); + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the first endpoint or interface descriptor */ + alt->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + alt->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific " + "interface descriptors\n", n); + buffer += i; + size -= i; + + if (alt->desc.bNumEndpoints > USB_MAXENDPOINTS) { + dev_err(ddev, "too many endpoints for config %d interface %d " + "altsetting %d: %d, maximum allowed: %d\n", + cfgno, inum, asnum, alt->desc.bNumEndpoints, + USB_MAXENDPOINTS); return -EINVAL; } - len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint); - ifp->endpoint = kmalloc(len, GFP_KERNEL); - if (!ifp->endpoint) { - err("out of memory"); + len = alt->desc.bNumEndpoints * sizeof(struct usb_host_endpoint); + alt->endpoint = kmalloc(len, GFP_KERNEL); + if (!alt->endpoint) return -ENOMEM; - } - memset(ifp->endpoint, 0, len); + memset(alt->endpoint, 0, len); - for (i = 0; i < ifp->desc.bNumEndpoints; i++) { + for (i = 0; i < alt->desc.bNumEndpoints; i++) { if (size < USB_DT_ENDPOINT_SIZE) { - warn("ran out of descriptors while parsing endpoints"); + dev_err(ddev, "too few endpoint descriptors for " + "config %d interface %d altsetting %d\n", + cfgno, inum, asnum); return -EINVAL; } - retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, + alt->endpoint + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } - return buffer - buffer0; + +skip_to_next_interface_descriptor: + i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, + USB_DT_INTERFACE, NULL); + return buffer - buffer0 + i; } -int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size) +int usb_parse_configuration(struct device *ddev, int cfgidx, + struct usb_host_config *config, unsigned char *buffer, int size) { + int cfgno; int nintf, nintf_orig; - int i, j; + int i, j, n; struct usb_interface *interface; - char *buffer2; + unsigned char *buffer2; int size2; struct usb_descriptor_header *header; - int numskipped, len; - char *begin; - int retval; + int len, retval; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE) { - warn("invalid configuration descriptor"); + dev_err(ddev, "invalid descriptor for config index %d: " + "type = 0x%X, length = %d\n", cfgidx, + config->desc.bDescriptorType, config->desc.bLength); return -EINVAL; } config->desc.wTotalLength = size; + cfgno = config->desc.bConfigurationValue; + + buffer += config->desc.bLength; + size -= config->desc.bLength; nintf = nintf_orig = config->desc.bNumInterfaces; if (nintf > USB_MAXINTERFACES) { - warn("too many interfaces (%d max %d)", - nintf, USB_MAXINTERFACES); + dev_warn(ddev, "config %d has too many interfaces: %d, " + "using maximum allowed: %d\n", + cfgno, nintf, USB_MAXINTERFACES); config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES; } for (i = 0; i < nintf; ++i) { interface = config->interface[i] = kmalloc(sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i", interface, i); - if (!interface) { - err("out of memory"); + if (!interface) return -ENOMEM; - } memset(interface, 0, sizeof(struct usb_interface)); } /* Go through the descriptors, checking their length and counting the * number of altsettings for each interface */ - buffer2 = buffer; - size2 = size; - j = 0; - while (size2 >= sizeof(struct usb_descriptor_header)) { + for ((buffer2 = buffer, size2 = size); + size2 >= sizeof(struct usb_descriptor_header); + (buffer2 += header->bLength, size2 -= header->bLength)) { + header = (struct usb_descriptor_header *) buffer2; if ((header->bLength > size2) || (header->bLength < 2)) { - warn("invalid descriptor of length %d", header->bLength); + dev_err(ddev, "config %d has an invalid descriptor " + "of length %d\n", cfgno, header->bLength); return -EINVAL; } if (header->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *d; - if (header->bLength < USB_DT_INTERFACE_SIZE) { - warn("invalid interface descriptor"); + d = (struct usb_interface_descriptor *) header; + if (d->bLength < USB_DT_INTERFACE_SIZE) { + dev_err(ddev, "config %d has an invalid " + "interface descriptor of length %d\n", + cfgno, d->bLength); return -EINVAL; } - d = (struct usb_interface_descriptor *) header; + i = d->bInterfaceNumber; if (i >= nintf_orig) { - warn("invalid interface number (%d/%d)", - i, nintf_orig); + dev_err(ddev, "config %d has an invalid " + "interface number: %d but max is %d\n", + cfgno, i, nintf_orig - 1); return -EINVAL; } if (i < nintf) ++config->interface[i]->num_altsetting; - } else if ((header->bDescriptorType == USB_DT_DEVICE || - header->bDescriptorType == USB_DT_CONFIG) && j) { - warn("unexpected descriptor type 0x%X", header->bDescriptorType); + } else if (header->bDescriptorType == USB_DT_DEVICE || + header->bDescriptorType == USB_DT_CONFIG) { + dev_err(ddev, "config %d contains an unexpected " + "descriptor of type 0x%X\n", + cfgno, header->bDescriptorType); return -EINVAL; } - j = 1; - buffer2 += header->bLength; - size2 -= header->bLength; - } + } /* for ((buffer2 = buffer, size2 = size); ...) */ /* Allocate the altsetting arrays */ - for (i = 0; i < config->desc.bNumInterfaces; ++i) { + for (i = 0; i < nintf; ++i) { interface = config->interface[i]; if (interface->num_altsetting > USB_MAXALTSETTING) { - warn("too many alternate settings for interface %d (%d max %d)\n", - i, interface->num_altsetting, USB_MAXALTSETTING); + dev_err(ddev, "too many alternate settings for " + "config %d interface %d: %d, " + "maximum allowed: %d\n", + cfgno, i, interface->num_altsetting, + USB_MAXALTSETTING); return -EINVAL; } if (interface->num_altsetting == 0) { - warn("no alternate settings for interface %d", i); + dev_err(ddev, "config %d has no interface number " + "%d\n", cfgno, i); return -EINVAL; } - len = sizeof(*interface->altsetting) * interface->num_altsetting; + len = sizeof(*interface->altsetting) * + interface->num_altsetting; interface->altsetting = kmalloc(len, GFP_KERNEL); - if (!interface->altsetting) { - err("couldn't kmalloc interface->altsetting"); + if (!interface->altsetting) return -ENOMEM; - } memset(interface->altsetting, 0, len); } - buffer += config->desc.bLength; - size -= config->desc.bLength; - - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific configuration descriptors", numskipped); - config->extra = begin; - config->extralen = buffer - begin; - } + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the first interface descriptor */ + config->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, + USB_DT_INTERFACE, &n); + config->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific " + "configuration descriptors\n", n); + buffer += i; + size -= i; /* Parse all the interface/altsetting descriptors */ while (size >= sizeof(struct usb_descriptor_header)) { - retval = usb_parse_interface(config, buffer, size); + retval = usb_parse_interface(ddev, cfgno, config, + buffer, size); if (retval < 0) return retval; @@ -337,7 +343,8 @@ interface = config->interface[i]; for (j = 0; j < interface->num_altsetting; ++j) { if (!interface->altsetting[j].desc.bLength) { - warn("missing altsetting %d for interface %d", j, i); + dev_err(ddev, "config %d interface %d has no " + "altsetting %d\n", cfgno, i, j); return -EINVAL; } } @@ -380,81 +387,77 @@ // (used by real hubs and virtual root hubs) int usb_get_configuration(struct usb_device *dev) { + struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; if (ncfg > USB_MAXCONFIG) { - warn("too many configurations (%d max %d)", - ncfg, USB_MAXCONFIG); + dev_warn(ddev, "too many configurations: %d, " + "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG; } if (ncfg < 1) { - warn("no configurations"); + dev_err(ddev, "no configurations\n"); return -EINVAL; } length = ncfg * sizeof(struct usb_host_config); dev->config = kmalloc(length, GFP_KERNEL); - if (!dev->config) { - err("out of memory"); - return -ENOMEM; - } + if (!dev->config) + goto err2; memset(dev->config, 0, length); length = ncfg * sizeof(char *); dev->rawdescriptors = kmalloc(length, GFP_KERNEL); - if (!dev->rawdescriptors) { - err("out of memory"); - return -ENOMEM; - } + if (!dev->rawdescriptors) + goto err2; memset(dev->rawdescriptors, 0, length); buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - err("unable to allocate memory for configuration descriptors"); - return -ENOMEM; - } + if (!buffer) + goto err2; desc = (struct usb_config_descriptor *)buffer; for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab the first 8 bytes so we know how long the whole */ - /* configuration is */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); - if (result < 8) { - if (result < 0) - err("unable to get descriptor"); - else { - warn("config descriptor too short (expected %i, got %i)", 8, result); - result = -EINVAL; - } + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, + buffer, 8); + if (result < 0) { + dev_err(ddev, "unable to read config index %d " + "descriptor\n", cfgno); + goto err; + } else if (result < 8) { + dev_err(ddev, "config index %d descriptor too short " + "(expected %i, got %i)\n", cfgno, 8, result); + result = -EINVAL; goto err; } + length = max((int) le16_to_cpu(desc->wTotalLength), + USB_DT_CONFIG_SIZE); - /* Get the full buffer */ - length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE); - + /* Now that we know the length, get the whole thing */ bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) { - err("unable to allocate memory for configuration descriptors"); result = -ENOMEM; goto err; } - - /* Now that we know the length, get the whole thing */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, + bigbuffer, length); if (result < 0) { - err("couldn't get all of config descriptors"); + dev_err(ddev, "unable to read config index %d " + "descriptor\n", cfgno); kfree(bigbuffer); goto err; } - if (result < length) { - err("config descriptor too short (expected %i, got %i)", length, result); + dev_err(ddev, "config index %d descriptor too short " + "(expected %i, got %i)\n", cfgno, length, result); result = -EINVAL; kfree(bigbuffer); goto err; @@ -462,20 +465,23 @@ dev->rawdescriptors[cfgno] = bigbuffer; - result = usb_parse_configuration(&dev->config[cfgno], bigbuffer, length); + result = usb_parse_configuration(&dev->dev, cfgno, + &dev->config[cfgno], bigbuffer, length); if (result > 0) - dbg("descriptor data left"); + dev_dbg(ddev, "config index %d descriptor has %d " + "excess byte(s)\n", cfgno, result); else if (result < 0) { ++cfgno; goto err; } } + result = 0; - kfree(buffer); - return 0; err: kfree(buffer); dev->descriptor.bNumConfigurations = cfgno; +err2: + if (result == -ENOMEM) + dev_err(ddev, "out of memory\n"); return result; } - diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/devio.c Sun Mar 28 13:17:10 2004 @@ -124,14 +124,25 @@ unsigned int length = le16_to_cpu(config->wTotalLength); if (*ppos < pos + length) { + + /* The descriptor may claim to be longer than it + * really is. Here is the actual allocated length. */ + unsigned alloclen = + ps->dev->config[i].desc.wTotalLength; + len = length - (*ppos - pos); if (len > nbytes) len = nbytes; - if (copy_to_user(buf, - ps->dev->rawdescriptors[i] + (*ppos - pos), len)) { - ret = -EFAULT; - goto err; + /* Simply don't write (skip over) unallocated parts */ + if (alloclen > (*ppos - pos)) { + alloclen -= (*ppos - pos); + if (copy_to_user(buf, + ps->dev->rawdescriptors[i] + (*ppos - pos), + min(len, alloclen))) { + ret = -EFAULT; + goto err; + } } *ppos += len; diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/hcd-pci.c Sun Mar 28 13:17:10 2004 @@ -80,7 +80,8 @@ return -ENODEV; if (!dev->irq) { - err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", + dev_err (&dev->dev, + "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); return -ENODEV; } @@ -90,16 +91,17 @@ resource = pci_resource_start (dev, 0); len = pci_resource_len (dev, 0); if (!request_mem_region (resource, len, driver->description)) { - dbg ("controller already in use"); + dev_dbg (&dev->dev, "controller already in use\n"); return -EBUSY; } base = ioremap_nocache (resource, len); if (base == NULL) { - dbg ("error mapping memory"); + dev_dbg (&dev->dev, "error mapping memory\n"); retval = -EFAULT; clean_1: release_mem_region (resource, len); - err ("init %s fail, %d", pci_name(dev), retval); + dev_err (&dev->dev, "init %s fail, %d\n", + pci_name(dev), retval); return retval; } @@ -116,7 +118,7 @@ break; } if (region == PCI_ROM_RESOURCE) { - dbg ("no i/o regions available"); + dev_dbg (&dev->dev, "no i/o regions available\n"); return -EBUSY; } base = (void *) resource; @@ -127,7 +129,7 @@ hcd = driver->hcd_alloc (); if (hcd == NULL){ - dbg ("hcd alloc fail"); + dev_dbg (&dev->dev, "hcd alloc fail\n"); retval = -ENOMEM; clean_2: if (driver->flags & HCD_MEMORY) { @@ -135,7 +137,8 @@ goto clean_1; } else { release_region (resource, len); - err ("init %s fail, %d", pci_name(dev), retval); + dev_err (&dev->dev, "init %s fail, %d\n", + pci_name(dev), retval); return retval; } } @@ -193,13 +196,16 @@ hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = (void *) hcd; hcd->self.release = &hcd_pci_release; + init_timer (&hcd->rh_timer); INIT_LIST_HEAD (&hcd->dev_list); usb_register_bus (&hcd->self); - if ((retval = driver->start (hcd)) < 0) + if ((retval = driver->start (hcd)) < 0) { + dev_err (hcd->self.controller, "init error %d\n", retval); usb_hcd_pci_remove (dev); + } return retval; } diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/hcd.c Sun Mar 28 13:17:10 2004 @@ -42,6 +42,8 @@ #include #include + +#include "usb.h" #include "hcd.h" @@ -416,9 +418,14 @@ default: /* non-generic request */ - urb->status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - ubuf, wLength); + if (HCD_IS_SUSPENDED (hcd->state)) + urb->status = -EAGAIN; + else if (!HCD_IS_RUNNING (hcd->state)) + urb->status = -ENODEV; + else + urb->status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + ubuf, wLength); break; error: /* "protocol stall" on error */ @@ -678,8 +685,10 @@ if (busnum < USB_MAXBUS) { set_bit (busnum, busmap.busmap); bus->busnum = busnum; - } else - warn ("too many buses"); + } else { + printk (KERN_ERR "%s: too many buses\n", usbcore_name); + return -E2BIG; + } snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); bus->class_dev.class = &usb_host_class; @@ -804,7 +813,7 @@ tmp = HS_USECS_ISO (bytecount); return tmp; default: - dbg ("bogus device speed!"); + pr_debug ("%s: bogus device speed!\n", usbcore_name); return -1; } } diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/hcd.h Sun Mar 28 13:17:10 2004 @@ -275,10 +275,6 @@ #define EndpointOutRequest \ ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) -/* table 9.6 standard features */ -#define DEVICE_REMOTE_WAKEUP 1 -#define ENDPOINT_HALT 0 - /* class requests from the USB 2.0 hub spec, table 11-15 */ /* GetBusState and SetHubDescriptor are optional, omitted */ #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/hub.c Sun Mar 28 13:17:10 2004 @@ -212,8 +212,7 @@ spin_lock_irqsave (&hub->tt.lock, flags); if (status) - err ("usb-%s-%s clear tt %d (%04x) error %d", - dev->bus->bus_name, dev->devpath, + dev_err (&dev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); kfree (clear); } @@ -244,8 +243,7 @@ * there can be many TTs per hub). even if they're uncommon. */ if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { - err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s", - dev->bus->bus_name, tt->hub->devpath); + dev_err (&dev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return; } @@ -596,7 +594,7 @@ hub = kmalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { - err("couldn't kmalloc hub struct"); + dev_dbg (hubdev(dev), "couldn't kmalloc hub struct\n"); return -ENOMEM; } @@ -700,7 +698,7 @@ } } - err("cannot disconnect hub %s", dev->devpath); + dev_err(&dev->dev, "cannot disconnect hub!\n"); } static int hub_port_status(struct usb_device *dev, int port, @@ -1145,7 +1143,7 @@ refrigerator(PF_IOTHREAD); } while (!signal_pending(current)); - dbg("hub_thread exiting"); + pr_debug ("%s: khubd exiting\n", usbcore_name); complete_and_exit(&khubd_exited, 0); } @@ -1176,7 +1174,8 @@ pid_t pid; if (usb_register(&hub_driver) < 0) { - err("Unable to register USB hub driver"); + printk(KERN_ERR "%s: can't register hub driver\n", + usbcore_name); return -1; } @@ -1189,7 +1188,7 @@ /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); - err("failed to start hub_thread"); + printk(KERN_ERR "%s: can't start khubd\n", usbcore_name); return -1; } diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/message.c Sun Mar 28 13:17:10 2004 @@ -722,7 +722,8 @@ * this request for iso endpoints, which can't halt! */ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); /* don't un-halt or force to DATA0 except on success */ @@ -928,7 +929,8 @@ iface = usb_ifnum_to_if(dev, interface); if (!iface) { - warn("selecting invalid interface %d", interface); + dev_dbg(&dev->dev, "selecting invalid interface %d\n", + interface); return -EINVAL; } @@ -946,8 +948,9 @@ * request if the interface only has one alternate setting. */ if (ret == -EPIPE && iface->num_altsetting == 1) { - dbg("manual set_interface for dev %d, iface %d, alt %d", - dev->devnum, interface, alternate); + dev_dbg(&dev->dev, + "manual set_interface for iface %d, alt %d\n", + interface, alternate); manual = 1; } else if (ret < 0) return ret; @@ -1226,18 +1229,20 @@ if (!dev->have_langid) { err = usb_get_string(dev, 0, 0, tbuf, 4); if (err < 0) { - err("error getting string descriptor 0 (error=%d)", err); + dev_err (&dev->dev, + "string descriptor 0 read error: %d\n", + err); goto errout; } else if (err < 4 || tbuf[0] < 4) { - err("string descriptor 0 too short"); + dev_err (&dev->dev, "string descriptor 0 too short\n"); err = -EINVAL; goto errout; } else { dev->have_langid = -1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ - dbg("USB device number %d default language ID 0x%x", - dev->devnum, dev->string_langid); + dev_dbg (&dev->dev, "default language 0x%04x\n", + dev->string_langid); } } diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/usb.c Sun Mar 28 13:17:10 2004 @@ -58,6 +58,8 @@ extern void usb_host_cleanup(void); +const char *usbcore_name = "usbcore"; + int nousb; /* Disable USB when built into kernel image */ /* Not honored on modular build */ @@ -158,11 +160,12 @@ retval = driver_register(&new_driver->driver); if (!retval) { - info("registered new driver %s", new_driver->name); + pr_info("%s: registered new driver %s\n", + usbcore_name, new_driver->name); usbfs_update_special(); } else { - err("problem %d when registering driver %s", - retval, new_driver->name); + printk(KERN_ERR "%s: error %d registering driver %s\n", + usbcore_name, retval, new_driver->name); } return retval; @@ -181,7 +184,7 @@ */ void usb_deregister(struct usb_driver *driver) { - info("deregistering driver %s", driver->name); + pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); driver_unregister (&driver->driver); @@ -587,11 +590,12 @@ int i = 0; int length = 0; - dbg ("%s", __FUNCTION__); - if (!dev) return -ENODEV; + /* driver is often null here; dev_dbg() would oops */ + pr_debug ("usb %s: hotplug\n", dev->bus_id); + /* Must check driver_data here, as on remove driver is always NULL */ if ((dev->driver == &usb_generic_driver) || (dev->driver_data == &usb_generic_driver_data)) @@ -601,11 +605,11 @@ usb_dev = interface_to_usbdev (intf); if (usb_dev->devnum < 0) { - dbg ("device already deleted ??"); + pr_debug ("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; } if (!usb_dev->bus) { - dbg ("bus already removed?"); + pr_debug ("usb %s: bus removed?\n", dev->bus_id); return -ENODEV; } @@ -827,14 +831,14 @@ struct usb_device *ret_dev = NULL; int child; - dbg("looking at vendor %d, product %d", + dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n", dev->descriptor.idVendor, dev->descriptor.idProduct); /* see if this device matches */ if ((dev->descriptor.idVendor == vendor_id) && (dev->descriptor.idProduct == product_id)) { - dbg ("found the device!"); + dev_dbg (&dev->dev, "matched this device!\n"); ret_dev = usb_get_dev(dev); goto exit; } @@ -909,7 +913,8 @@ * extra field of the interface and endpoint descriptor structs. */ -int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) +int __usb_get_extra_descriptor(char *buffer, unsigned size, + unsigned char type, void **ptr) { struct usb_descriptor_header *header; @@ -917,7 +922,11 @@ header = (struct usb_descriptor_header *)buffer; if (header->bLength < 2) { - err("invalid descriptor length of %d", header->bLength); + printk(KERN_ERR + "%s: bogus descriptor, type %d length %d\n", + usbcore_name, + header->bDescriptorType, + header->bLength); return -1; } @@ -1568,7 +1577,7 @@ static int __init usb_init(void) { if (nousb) { - info("USB support disabled\n"); + pr_info ("%s: USB support disabled\n", usbcore_name); return 0; } diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h --- a/drivers/usb/core/usb.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/core/usb.h Sun Mar 28 13:17:10 2004 @@ -17,3 +17,6 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); + +/* for labeling diagnostics */ +extern const char *usbcore_name; diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/Kconfig Sun Mar 28 13:17:10 2004 @@ -71,8 +71,8 @@ default USB_GADGET config USB_GADGET_PXA2XX - boolean "PXA 2xx or IXP 42x" - depends on ARCH_PXA || ARCH_IXP425 + boolean "PXA 2xx or IXP 4xx" + depends on ARCH_PXA || ARCH_IXP4XX help Intel's PXA 2xx series XScale ARM-5TE processors include an integrated full speed USB 1.1 device controller. The @@ -132,6 +132,34 @@ config USB_SA1100 tristate depends on USB_GADGET_SA1100 + default USB_GADGET + +config USB_GADGET_DUMMY_HCD + boolean "Dummy HCD (DEVELOPMENT)" + depends on USB && EXPERIMENTAL + select USB_GADGET_DUALSPEED + help + This host controller driver emulates USB, looping all data transfer + requests back to a USB "gadget driver" in the same host. The host + side is the master; the gadget side is the slave. Gadget drivers + can be high, full, or low speed; and they have access to endpoints + like those from NET2280, PXA2xx, or SA1100 hardware. + + This may help in some stages of creating a driver to embed in a + Linux device, since it lets you debug several parts of the gadget + driver without its hardware or drivers being involved. + + Since such a gadget side driver needs to interoperate with a host + side Linux-USB device driver, this may help to debug both sides + of a USB protocol stack. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "dummy_hcd" and force all + gadget drivers to also be dynamically linked. + +config USB_DUMMY_HCD + tristate + depends on USB_GADGET_DUMMY_HCD default USB_GADGET endchoice diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/Makefile Sun Mar 28 13:17:10 2004 @@ -1,6 +1,7 @@ # # USB peripheral controller drivers # +obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o @@ -8,10 +9,10 @@ # # USB gadget drivers # -g_zero-objs := zero.o usbstring.o config.o -g_ether-objs := ether.o usbstring.o config.o +g_zero-objs := zero.o usbstring.o config.o epautoconf.o +g_ether-objs := ether.o usbstring.o config.o epautoconf.o g_serial-objs := serial.o usbstring.o -gadgetfs-objs := inode.o usbstring.o +gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o obj-$(CONFIG_USB_ZERO) += g_zero.o diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/dummy_hcd.c Sun Mar 28 13:17:10 2004 @@ -0,0 +1,1677 @@ +/* + * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver. + * + * Maintainer: Alan Stern + * + * Copyright (C) 2003 David Brownell + * Copyright (C) 2003, 2004 Alan Stern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * This exposes a device side "USB gadget" API, driven by requests to a + * Linux-USB host controller driver. USB traffic is simulated; there's + * no need for USB hardware. Use this with two other drivers: + * + * - Gadget driver, responding to requests (slave); + * - Host-side device driver, as already familiar in Linux. + * + * Having this all in one kernel can help some stages of development, + * bypassing some hardware (and driver) issues. UML could help too. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +#include "../core/hcd.h" + + +#define DRIVER_DESC "USB Host+Gadget Emulator" +#define DRIVER_VERSION "14 Mar 2004" + +static const char driver_name [] = "dummy_hcd"; +static const char driver_desc [] = "USB Host+Gadget Emulator"; + +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("GPL"); + +/*-------------------------------------------------------------------------*/ + +/* gadget side driver data structres */ +struct dummy_ep { + struct list_head queue; + unsigned long last_io; /* jiffies timestamp */ + struct usb_gadget *gadget; + const struct usb_endpoint_descriptor *desc; + struct usb_ep ep; + unsigned halted : 1; + unsigned already_seen : 1; + unsigned setup_stage : 1; +}; + +struct dummy_request { + struct list_head queue; /* ep's requests */ + struct usb_request req; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * Every device has ep0 for control requests, plus up to 30 more endpoints, + * in one of two types: + * + * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint + * number can be changed. Names like "ep-a" are used for this type. + * + * - Fixed Function: in other cases. some characteristics may be mutable; + * that'd be hardware-specific. Names like "ep12out-bulk" are used. + * + * Gadget drivers are responsible for not setting up conflicting endpoint + * configurations, illegal or unsupported packet lengths, and so on. + */ + +static const char ep0name [] = "ep0"; + +static const char *const ep_name [] = { + ep0name, /* everyone has ep0 */ + + /* act like a net2280: high speed, six configurable endpoints */ + "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", + + /* or like pxa250: fifteen fixed function endpoints */ + "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", + "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", + "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", + "ep15in-int", + + /* or like sa1100: two fixed function endpoints */ + "ep1out-bulk", "ep2in-bulk", +}; +#define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) + +#define FIFO_SIZE 64 + +struct dummy { + spinlock_t lock; + + /* + * SLAVE/GADGET side support + */ + struct dummy_ep ep [DUMMY_ENDPOINTS]; + int address; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct dummy_request fifo_req; + u8 fifo_buf [FIFO_SIZE]; + + struct hcd_dev *hdev; + + /* + * MASTER/HOST side support + */ + struct usb_hcd hcd; + struct platform_device pdev; + struct timer_list timer; + u32 port_status; + int started; + struct completion released; +}; + +static struct dummy *the_controller; + +static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) +{ + return container_of (ep->gadget, struct dummy, gadget); +} + +static inline struct dummy *gadget_dev_to_dummy (struct device *dev) +{ + return container_of (dev, struct dummy, gadget.dev); +} + +/* + * This "hardware" may look a bit odd in diagnostics since it's got both + * host and device sides; and it binds different drivers to each side. + */ +#define hardware (&the_controller->pdev.dev) + +/*-------------------------------------------------------------------------*/ + +static struct device_driver dummy_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, +}; + +/*-------------------------------------------------------------------------*/ + +/* SLAVE/GADGET SIDE DRIVER + * + * This only tracks gadget state. All the work is done when the host + * side tries some (emulated) i/o operation. Real device controller + * drivers would do real i/o using dma, fifos, irqs, timers, etc. + */ + +#define is_enabled() \ + (the_controller->port_status & USB_PORT_STAT_ENABLE) + +static int +dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct dummy *dum; + struct dummy_ep *ep; + unsigned max; + int retval; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT) + if (!the_controller->driver || !is_enabled ()) + return -ESHUTDOWN; + max = desc->wMaxPacketSize & 0x3ff; + + /* drivers must not request bad settings, since lower levels + * (hardware or its drivers) may not check. some endpoints + * can't do iso, many have maxpacket limitations, etc. + * + * since this "hardware" driver is here to help debugging, we + * have some extra sanity checks. (there could be more though, + * especially for "ep9out" style fixed function ones.) + */ + dum = container_of (ep->gadget, struct dummy, gadget); + retval = -EINVAL; + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: + if (strstr (ep->ep.name, "-iso") + || strstr (ep->ep.name, "-int")) { + goto done; + } + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max == 512) + break; + /* conserve return statements */ + default: + switch (max) { + case 8: case 16: case 32: case 64: + /* we'll fake any legal size */ + break; + default: + case USB_SPEED_LOW: + goto done; + } + } + break; + case USB_ENDPOINT_XFER_INT: + if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ + goto done; + /* real hardware might not handle all packet sizes */ + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + /* save a return statement */ + case USB_SPEED_FULL: + if (max <= 64) + break; + /* save a return statement */ + default: + if (max <= 8) + break; + goto done; + } + break; + case USB_ENDPOINT_XFER_ISOC: + if (strstr (ep->ep.name, "-bulk") + || strstr (ep->ep.name, "-int")) + goto done; + /* real hardware might not handle all packet sizes */ + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + /* save a return statement */ + case USB_SPEED_FULL: + if (max <= 1023) + break; + /* save a return statement */ + default: + goto done; + } + break; + default: + /* few chips support control except on ep0 */ + goto done; + } + + _ep->maxpacket = max; + ep->desc = desc; + + dev_dbg (hardware, "enabled %s (ep%d%s-%s) maxpacket %d\n", + _ep->name, + desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + ({ char *val; + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; + case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; + case USB_ENDPOINT_XFER_INT: val = "intr"; break; + default: val = "ctrl"; break; + }; val; }), + max); + + /* at this point real hardware should be NAKing transfers + * to that endpoint, until a buffer is queued to it. + */ + retval = 0; +done: + return retval; +} + +/* called with spinlock held */ +static void nuke (struct dummy *dum, struct dummy_ep *ep) +{ + while (!list_empty (&ep->queue)) { + struct dummy_request *req; + + req = list_entry (ep->queue.next, struct dummy_request, queue); + list_del_init (&req->queue); + req->req.status = -ESHUTDOWN; + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + } +} + +static int dummy_disable (struct usb_ep *_ep) +{ + struct dummy_ep *ep; + struct dummy *dum; + unsigned long flags; + int retval; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || !ep->desc || _ep->name == ep0name) + return -EINVAL; + dum = ep_to_dummy (ep); + + spin_lock_irqsave (&dum->lock, flags); + ep->desc = 0; + retval = 0; + nuke (dum, ep); + spin_unlock_irqrestore (&dum->lock, flags); + + dev_dbg (hardware, "disabled %s\n", _ep->name); + return retval; +} + +static struct usb_request * +dummy_alloc_request (struct usb_ep *_ep, int mem_flags) +{ + struct dummy_ep *ep; + struct dummy_request *req; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep) + return 0; + + req = kmalloc (sizeof *req, mem_flags); + if (!req) + return 0; + memset (req, 0, sizeof *req); + INIT_LIST_HEAD (&req->queue); + return &req->req; +} + +static void +dummy_free_request (struct usb_ep *_ep, struct usb_request *_req) +{ + struct dummy_ep *ep; + struct dummy_request *req; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) + return; + + req = container_of (_req, struct dummy_request, req); + WARN_ON (!list_empty (&req->queue)); + kfree (req); +} + +static void * +dummy_alloc_buffer ( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + int mem_flags +) { + char *retval; + + if (!the_controller->driver) + return 0; + retval = kmalloc (bytes, mem_flags); + *dma = (dma_addr_t) retval; + return retval; +} + +static void +dummy_free_buffer ( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) { + if (bytes) + kfree (buf); +} + +static void +fifo_complete (struct usb_ep *ep, struct usb_request *req) +{ +#if 0 + dev_dbg (hardware, "fifo_complete: %d\n", req->status); +#endif +} + +static int +dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) +{ + struct dummy_ep *ep; + struct dummy_request *req; + struct dummy *dum; + unsigned long flags; + + req = container_of (_req, struct dummy_request, req); + if (!_req || !list_empty (&req->queue) || !_req->complete) + return -EINVAL; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || (!ep->desc && _ep->name != ep0name)) + return -EINVAL; + + if (!the_controller->driver || !is_enabled ()) + return -ESHUTDOWN; + + dum = container_of (ep->gadget, struct dummy, gadget); + +#if 0 + dev_dbg (hardware, "ep %p queue req %p to %s, len %d buf %p\n", + ep, _req, _ep->name, _req->length, _req->buf); +#endif + + _req->status = -EINPROGRESS; + _req->actual = 0; + spin_lock_irqsave (&dum->lock, flags); + + /* implement an emulated single-request FIFO */ + if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && + list_empty (&dum->fifo_req.queue) && + list_empty (&ep->queue) && + _req->length <= FIFO_SIZE) { + req = &dum->fifo_req; + req->req = *_req; + req->req.buf = dum->fifo_buf; + memcpy (dum->fifo_buf, _req->buf, _req->length); + req->req.context = dum; + req->req.complete = fifo_complete; + + spin_unlock (&dum->lock); + _req->actual = _req->length; + _req->status = 0; + _req->complete (_ep, _req); + spin_lock (&dum->lock); + } + list_add_tail (&req->queue, &ep->queue); + spin_unlock_irqrestore (&dum->lock, flags); + + /* real hardware would likely enable transfers here, in case + * it'd been left NAKing. + */ + return 0; +} + +static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) +{ + struct dummy_ep *ep; + struct dummy *dum; + int retval = -EINVAL; + unsigned long flags; + struct dummy_request *req = 0; + + if (!the_controller->driver) + return -ESHUTDOWN; + + if (!_ep || !_req) + return retval; + ep = container_of (_ep, struct dummy_ep, ep); + dum = container_of (ep->gadget, struct dummy, gadget); + + spin_lock_irqsave (&dum->lock, flags); + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) { + list_del_init (&req->queue); + _req->status = -ECONNRESET; + retval = 0; + break; + } + } + spin_unlock_irqrestore (&dum->lock, flags); + + if (retval == 0) { + dev_dbg (hardware, "dequeued req %p from %s, len %d buf %p\n", + req, _ep->name, _req->length, _req->buf); + + _req->complete (_ep, _req); + } + return retval; +} + +static int +dummy_set_halt (struct usb_ep *_ep, int value) +{ + struct dummy_ep *ep; + + if (!_ep) + return -EINVAL; + if (!the_controller->driver) + return -ESHUTDOWN; + ep = container_of (_ep, struct dummy_ep, ep); + if (!value) + ep->halted = 0; + else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && + !list_empty (&ep->queue)) + return -EAGAIN; + else + ep->halted = 1; + /* FIXME clear emulated data toggle too */ + return 0; +} + +static const struct usb_ep_ops dummy_ep_ops = { + .enable = dummy_enable, + .disable = dummy_disable, + + .alloc_request = dummy_alloc_request, + .free_request = dummy_free_request, + + .alloc_buffer = dummy_alloc_buffer, + .free_buffer = dummy_free_buffer, + /* map, unmap, ... eventually hook the "generic" dma calls */ + + .queue = dummy_queue, + .dequeue = dummy_dequeue, + + .set_halt = dummy_set_halt, +}; + +/*-------------------------------------------------------------------------*/ + +/* there are both host and device side versions of this call ... */ +static int dummy_g_get_frame (struct usb_gadget *_gadget) +{ + struct timeval tv; + + do_gettimeofday (&tv); + return tv.tv_usec / 1000; +} + +static const struct usb_gadget_ops dummy_ops = { + .get_frame = dummy_g_get_frame, +}; + +/*-------------------------------------------------------------------------*/ + +/* "function" sysfs attribute */ +static ssize_t +show_function (struct device *_dev, char *buf) +{ + struct dummy *dum = the_controller; + + if (!dum->driver->function + || strlen (dum->driver->function) > PAGE_SIZE) + return 0; + return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); +} +DEVICE_ATTR (function, S_IRUGO, show_function, NULL); + +/*-------------------------------------------------------------------------*/ + +/* + * Driver registration/unregistration. + * + * This is basically hardware-specific; there's usually only one real USB + * device (not host) controller since that's how USB devices are intended + * to work. So most implementations of these api calls will rely on the + * fact that only one driver will ever bind to the hardware. But curious + * hardware can be built with discrete components, so the gadget API doesn't + * require that assumption. + * + * For this emulator, it might be convenient to create a usb slave device + * for each driver that registers: just add to a big root hub. + */ + +static void +dummy_udc_release (struct device *dev) +{ + struct dummy *dum = gadget_dev_to_dummy (dev); + + complete (&dum->released); +} + +static void +dummy_hc_release (struct device *dev) +{ + struct dummy *dum = dev_get_drvdata (dev); + + complete (&dum->released); +} + +static int +dummy_register_udc (struct dummy *dum) +{ + int rc; + + strcpy (dum->gadget.dev.bus_id, "udc"); + dum->gadget.dev.parent = &dum->pdev.dev; + dum->gadget.dev.release = dummy_udc_release; + + rc = device_register (&dum->gadget.dev); + if (rc == 0) + device_create_file (&dum->gadget.dev, &dev_attr_function); + return rc; +} + +static void +dummy_unregister_udc (struct dummy *dum) +{ + device_remove_file (&dum->gadget.dev, &dev_attr_function); + init_completion (&dum->released); + device_unregister (&dum->gadget.dev); + wait_for_completion (&dum->released); +} + +int +usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + struct dummy *dum = the_controller; + int retval, i; + + if (!dum) + return -EINVAL; + if (dum->driver) + return -EBUSY; + if (!driver->bind || !driver->unbind || !driver->setup + || driver->speed == USB_SPEED_UNKNOWN) + return -EINVAL; + + /* + * SLAVE side init ... the layer above hardware, which + * can't enumerate without help from the driver we're binding. + */ + dum->gadget.name = driver_name; + dum->gadget.ops = &dummy_ops; + dum->gadget.is_dualspeed = 1; + + INIT_LIST_HEAD (&dum->gadget.ep_list); + for (i = 0; i < DUMMY_ENDPOINTS; i++) { + struct dummy_ep *ep = &dum->ep [i]; + + if (!ep_name [i]) + break; + ep->ep.name = ep_name [i]; + ep->ep.ops = &dummy_ep_ops; + list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list); + ep->halted = ep->already_seen = ep->setup_stage = 0; + ep->ep.maxpacket = ~0; + ep->last_io = jiffies; + ep->gadget = &dum->gadget; + ep->desc = 0; + INIT_LIST_HEAD (&ep->queue); + } + + dum->gadget.ep0 = &dum->ep [0].ep; + dum->ep [0].ep.maxpacket = 64; + list_del_init (&dum->ep [0].ep.ep_list); + INIT_LIST_HEAD(&dum->fifo_req.queue); + + dum->driver = driver; + dum->gadget.dev.driver = &driver->driver; + dev_dbg (hardware, "binding gadget driver '%s'\n", driver->driver.name); + if ((retval = driver->bind (&dum->gadget)) != 0) { + dum->driver = 0; + dum->gadget.dev.driver = 0; + return retval; + } + + // FIXME: Check these calls for errors and re-order + driver->driver.bus = dum->pdev.dev.bus; + driver_register (&driver->driver); + + device_bind_driver (&dum->gadget.dev); + + /* khubd will enumerate this in a while */ + dum->port_status |= USB_PORT_STAT_CONNECTION + | (1 << USB_PORT_FEAT_C_CONNECTION); + return 0; +} +EXPORT_SYMBOL (usb_gadget_register_driver); + +/* caller must hold lock */ +static void +stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) +{ + struct dummy_ep *ep; + + /* prevent any more requests */ + dum->hdev = 0; + dum->address = 0; + + /* this might not succeed ... */ + del_timer (&dum->timer); + + /* nuke any pending requests first, so driver i/o is quiesced */ + list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) + nuke (dum, ep); + + /* driver now does any non-usb quiescing necessary */ + if (driver) { + spin_unlock (&dum->lock); + driver->disconnect (&dum->gadget); + spin_lock (&dum->lock); + } +} + +int +usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + struct dummy *dum = the_controller; + unsigned long flags; + + if (!dum) + return -ENODEV; + if (!driver || driver != dum->driver) + return -EINVAL; + + dev_dbg (hardware, "unregister gadget driver '%s'\n", + driver->driver.name); + + spin_lock_irqsave (&dum->lock, flags); + stop_activity (dum, driver); + dum->port_status &= ~USB_PORT_STAT_CONNECTION; + dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); + spin_unlock_irqrestore (&dum->lock, flags); + + driver->unbind (&dum->gadget); + dum->driver = 0; + + device_release_driver (&dum->gadget.dev); + + driver_unregister (&driver->driver); + + del_timer_sync (&dum->timer); + return 0; +} +EXPORT_SYMBOL (usb_gadget_unregister_driver); + +#undef is_enabled + +int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) +{ + return -ENOSYS; +} +EXPORT_SYMBOL (net2280_set_fifo_mode); + +/*-------------------------------------------------------------------------*/ + +/* MASTER/HOST SIDE DRIVER + * + * this uses the hcd framework to hook up to host side drivers. + * its root hub will only have one device, otherwise it acts like + * a normal host controller. + * + * when urbs are queued, they're just stuck on a list that we + * scan in a timer callback. that callback connects writes from + * the host with reads from the device, and so on, based on the + * usb 2.0 rules. + */ + +static int dummy_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct dummy *dum; + unsigned long flags; + + /* patch to usb_sg_init() is in 2.5.60 */ + BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length); + + dum = container_of (hcd, struct dummy, hcd); + spin_lock_irqsave (&dum->lock, flags); + + if (!dum->hdev) + dum->hdev = urb->dev->hcpriv; + urb->hcpriv = dum; + if (usb_pipetype (urb->pipe) == PIPE_CONTROL) + urb->error_count = 1; /* mark as a new urb */ + + /* kick the scheduler, it'll do the rest */ + if (!timer_pending (&dum->timer)) + mod_timer (&dum->timer, jiffies + 1); + + spin_unlock_irqrestore (&dum->lock, flags); + return 0; +} + +static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + /* giveback happens automatically in timer callback */ + return 0; +} + +static void maybe_set_status (struct urb *urb, int status) +{ + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock (&urb->lock); +} + +/* transfer up to a frame's worth; caller must own lock */ +static int +transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +{ + struct dummy_request *req; + +top: + /* if there's no request queued, the device is NAKing; return */ + list_for_each_entry (req, &ep->queue, queue) { + unsigned host_len, dev_len, len; + int is_short, to_host; + int rescan = 0; + + /* 1..N packets of ep->ep.maxpacket each ... the last one + * may be short (including zero length). + * + * writer can send a zlp explicitly (length 0) or implicitly + * (length mod maxpacket zero, and 'zero' flag); they always + * terminate reads. + */ + host_len = urb->transfer_buffer_length - urb->actual_length; + dev_len = req->req.length - req->req.actual; + len = min (host_len, dev_len); + + /* FIXME update emulated data toggle too */ + + to_host = usb_pipein (urb->pipe); + if (unlikely (len == 0)) + is_short = 1; + else { + char *ubuf, *rbuf; + + /* not enough bandwidth left? */ + if (limit < ep->ep.maxpacket && limit < len) + break; + len = min (len, (unsigned) limit); + if (len == 0) + break; + + /* use an extra pass for the final short packet */ + if (len > ep->ep.maxpacket) { + rescan = 1; + len -= (len % ep->ep.maxpacket); + } + is_short = (len % ep->ep.maxpacket) != 0; + + /* else transfer packet(s) */ + ubuf = urb->transfer_buffer + urb->actual_length; + rbuf = req->req.buf + req->req.actual; + if (to_host) + memcpy (ubuf, rbuf, len); + else + memcpy (rbuf, ubuf, len); + ep->last_io = jiffies; + + limit -= len; + urb->actual_length += len; + req->req.actual += len; + } + + /* short packets terminate, maybe with overflow/underflow. + * it's only really an error to write too much. + * + * partially filling a buffer optionally blocks queue advances + * (so completion handlers can clean up the queue) but we don't + * need to emulate such data-in-flight. so we only show part + * of the URB_SHORT_NOT_OK effect: completion status. + */ + if (is_short) { + if (host_len == dev_len) { + req->req.status = 0; + maybe_set_status (urb, 0); + } else if (to_host) { + req->req.status = 0; + if (dev_len > host_len) + maybe_set_status (urb, -EOVERFLOW); + else + maybe_set_status (urb, + (urb->transfer_flags + & URB_SHORT_NOT_OK) + ? -EREMOTEIO : 0); + } else if (!to_host) { + maybe_set_status (urb, 0); + if (host_len > dev_len) + req->req.status = -EOVERFLOW; + else + req->req.status = 0; + } + + /* many requests terminate without a short packet */ + } else { + if (req->req.length == req->req.actual + && !req->req.zero) + req->req.status = 0; + if (urb->transfer_buffer_length == urb->actual_length + && !(urb->transfer_flags + & URB_ZERO_PACKET)) { + maybe_set_status (urb, 0); + } + } + + /* device side completion --> continuable */ + if (req->req.status != -EINPROGRESS) { + list_del_init (&req->queue); + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + + /* requests might have been unlinked... */ + rescan = 1; + } + + /* host side completion --> terminate */ + if (urb->status != -EINPROGRESS) + break; + + /* rescan to continue with any other queued i/o */ + if (rescan) + goto top; + } + return limit; +} + +static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) +{ + int limit = ep->ep.maxpacket; + + if (dum->gadget.speed == USB_SPEED_HIGH) { + int tmp; + + /* high bandwidth mode */ + tmp = ep->desc->wMaxPacketSize; + tmp = le16_to_cpu (tmp); + tmp = (tmp >> 11) & 0x03; + tmp *= 8 /* applies to entire frame */; + limit += limit * tmp; + } + return limit; +} + +static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) +{ + int i; + + if ((address & ~USB_DIR_IN) == 0) + return &dum->ep [0]; + for (i = 1; i < DUMMY_ENDPOINTS; i++) { + struct dummy_ep *ep = &dum->ep [i]; + + if (!ep->desc) + continue; + if (ep->desc->bEndpointAddress == address) + return ep; + } + return NULL; +} + +#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) +#define Dev_InRequest (Dev_Request | USB_DIR_IN) +#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define Intf_InRequest (Intf_Request | USB_DIR_IN) +#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) +#define Ep_InRequest (Ep_Request | USB_DIR_IN) + +/* drive both sides of the transfers; looks like irq handlers to + * both drivers except the callbacks aren't in_irq(). + */ +static void dummy_timer (unsigned long _dum) +{ + struct dummy *dum = (struct dummy *) _dum; + struct hcd_dev *hdev = dum->hdev; + struct list_head *entry, *tmp; + unsigned long flags; + int limit, total; + int i; + + if (!hdev) { + dev_err (hardware, "timer fired with device gone?\n"); + return; + } + + /* simplistic model for one frame's bandwidth */ + switch (dum->gadget.speed) { + case USB_SPEED_LOW: + total = 8/*bytes*/ * 12/*packets*/; + break; + case USB_SPEED_FULL: + total = 64/*bytes*/ * 19/*packets*/; + break; + case USB_SPEED_HIGH: + total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; + break; + default: + dev_err (hardware, "bogus device speed\n"); + return; + } + + /* FIXME if HZ != 1000 this will probably misbehave ... */ + + /* look at each urb queued by the host side driver */ + spin_lock_irqsave (&dum->lock, flags); + for (i = 0; i < DUMMY_ENDPOINTS; i++) { + if (!ep_name [i]) + break; + dum->ep [i].already_seen = 0; + } + +restart: + list_for_each_safe (entry, tmp, &hdev->urb_list) { + struct urb *urb; + struct dummy_request *req; + u8 address; + struct dummy_ep *ep = 0; + int type; + + urb = list_entry (entry, struct urb, urb_list); + if (urb->status != -EINPROGRESS) { + /* likely it was just unlinked */ + goto return_urb; + } + type = usb_pipetype (urb->pipe); + + /* used up this frame's non-periodic bandwidth? + * FIXME there's infinite bandwidth for control and + * periodic transfers ... unrealistic. + */ + if (total <= 0 && type == PIPE_BULK) + continue; + + /* find the gadget's ep for this request (if configured) */ + address = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) + address |= USB_DIR_IN; + ep = find_endpoint(dum, address); + if (!ep) { + /* set_configuration() disagreement */ + dev_err (hardware, + "no ep configured for urb %p\n", + urb); + maybe_set_status (urb, -ETIMEDOUT); + goto return_urb; + } + + if (ep->already_seen) + continue; + ep->already_seen = 1; + if (ep == &dum->ep [0] && urb->error_count) { + ep->setup_stage = 1; /* a new urb */ + urb->error_count = 0; + } + if (ep->halted && !ep->setup_stage) { + /* NOTE: must not be iso! */ + dev_dbg (hardware, "ep %s halted, urb %p\n", + ep->ep.name, urb); + maybe_set_status (urb, -EPIPE); + goto return_urb; + } + /* FIXME make sure both ends agree on maxpacket */ + + /* handle control requests */ + if (ep == &dum->ep [0] && ep->setup_stage) { + struct usb_ctrlrequest setup; + int value = 1; + struct dummy_ep *ep2; + + setup = *(struct usb_ctrlrequest*) urb->setup_packet; + le16_to_cpus (&setup.wIndex); + le16_to_cpus (&setup.wValue); + le16_to_cpus (&setup.wLength); + if (setup.wLength != urb->transfer_buffer_length) { + maybe_set_status (urb, -EOVERFLOW); + goto return_urb; + } + + /* paranoia, in case of stale queued data */ + list_for_each_entry (req, &ep->queue, queue) { + list_del_init (&req->queue); + req->req.status = -EOVERFLOW; + dev_dbg (hardware, "stale req = %p\n", req); + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + ep->already_seen = 0; + goto restart; + } + + /* gadget driver never sees set_address or operations + * on standard feature flags. some hardware doesn't + * even expose them. + */ + ep->last_io = jiffies; + ep->setup_stage = 0; + ep->halted = 0; + switch (setup.bRequest) { + case USB_REQ_SET_ADDRESS: + if (setup.bRequestType != Dev_Request) + break; + if (dum->address != 0) { + maybe_set_status (urb, -ETIMEDOUT); + urb->actual_length = 0; + goto return_urb; + } + dum->address = setup.wValue; + maybe_set_status (urb, 0); + dev_dbg (hardware, "set_address = %d\n", + setup.wValue); + value = 0; + break; + case USB_REQ_SET_FEATURE: + if (setup.bRequestType == Dev_Request) { + // remote wakeup, and (hs) test mode + value = -EOPNOTSUPP; + } else if (setup.bRequestType == Ep_Request) { + // endpoint halt + ep2 = find_endpoint (dum, + setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + ep2->halted = 1; + value = 0; + maybe_set_status (urb, 0); + } + break; + case USB_REQ_CLEAR_FEATURE: + if (setup.bRequestType == Dev_Request) { + // remote wakeup + value = 0; + maybe_set_status (urb, 0); + } else if (setup.bRequestType == Ep_Request) { + // endpoint halt + ep2 = find_endpoint (dum, + setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + ep2->halted = 0; + value = 0; + maybe_set_status (urb, 0); + } + break; + case USB_REQ_GET_STATUS: + if (setup.bRequestType == Dev_InRequest + || setup.bRequestType + == Intf_InRequest + || setup.bRequestType + == Ep_InRequest + ) { + char *buf; + + // device: remote wakeup, selfpowered + // interface: nothing + // endpoint: halt + buf = (char *)urb->transfer_buffer; + if (urb->transfer_buffer_length > 0) { + if (setup.bRequestType == + Ep_InRequest) { + ep2 = find_endpoint (dum, setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + buf [0] = ep2->halted; + } else + buf [0] = 0; + } + if (urb->transfer_buffer_length > 1) + buf [1] = 0; + urb->actual_length = min (2, + urb->transfer_buffer_length); + value = 0; + maybe_set_status (urb, 0); + } + break; + } + + /* gadget driver handles all other requests. block + * until setup() returns; no reentrancy issues etc. + */ + if (value > 0) { + spin_unlock (&dum->lock); + value = dum->driver->setup (&dum->gadget, + &setup); + spin_lock (&dum->lock); + + if (value >= 0) { + /* no delays (max 64KB data stage) */ + limit = 64*1024; + goto treat_control_like_bulk; + } + /* error, see below */ + } + + if (value < 0) { + if (value != -EOPNOTSUPP) + dev_dbg (hardware, + "setup --> %d\n", + value); + maybe_set_status (urb, -EPIPE); + urb->actual_length = 0; + } + + goto return_urb; + } + + /* non-control requests */ + limit = total; + switch (usb_pipetype (urb->pipe)) { + case PIPE_ISOCHRONOUS: + /* FIXME is it urb->interval since the last xfer? + * use urb->iso_frame_desc[i]. + * complete whether or not ep has requests queued. + * report random errors, to debug drivers. + */ + limit = max (limit, periodic_bytes (dum, ep)); + maybe_set_status (urb, -ENOSYS); + break; + + case PIPE_INTERRUPT: + /* FIXME is it urb->interval since the last xfer? + * this almost certainly polls too fast. + */ + limit = max (limit, periodic_bytes (dum, ep)); + /* FALLTHROUGH */ + + // case PIPE_BULK: case PIPE_CONTROL: + default: + treat_control_like_bulk: + ep->last_io = jiffies; + total = transfer (dum, urb, ep, limit); + break; + } + + /* incomplete transfer? */ + if (urb->status == -EINPROGRESS) + continue; + +return_urb: + urb->hcpriv = 0; + if (ep) + ep->already_seen = ep->setup_stage = 0; + + spin_unlock (&dum->lock); + usb_hcd_giveback_urb (&dum->hcd, urb, 0); + spin_lock (&dum->lock); + + goto restart; + } + + /* want a 1 msec delay here */ + if (!list_empty (&hdev->urb_list)) + mod_timer (&dum->timer, jiffies + 1); + + spin_unlock_irqrestore (&dum->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +#define PORT_C_MASK \ + ((1 << USB_PORT_FEAT_C_CONNECTION) \ + | (1 << USB_PORT_FEAT_C_ENABLE) \ + | (1 << USB_PORT_FEAT_C_SUSPEND) \ + | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ + | (1 << USB_PORT_FEAT_C_RESET)) + +static int dummy_hub_status (struct usb_hcd *hcd, char *buf) +{ + struct dummy *dum; + unsigned long flags; + int retval; + + dum = container_of (hcd, struct dummy, hcd); + + spin_lock_irqsave (&dum->lock, flags); + if (!(dum->port_status & PORT_C_MASK)) + retval = 0; + else { + *buf = (1 << 1); + dev_dbg (hardware, "port status 0x%08x has changes\n", + dum->port_status); + retval = 1; + } + spin_unlock_irqrestore (&dum->lock, flags); + return retval; +} + +static inline void +hub_descriptor (struct usb_hub_descriptor *desc) +{ + memset (desc, 0, sizeof *desc); + desc->bDescriptorType = 0x29; + desc->bDescLength = 9; + desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); + desc->bNbrPorts = 1; + desc->bitmap [0] = 0xff; + desc->bitmap [1] = 0xff; +} + +static int dummy_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct dummy *dum; + int retval = 0; + unsigned long flags; + + dum = container_of (hcd, struct dummy, hcd); + spin_lock_irqsave (&dum->lock, flags); + switch (typeReq) { + case ClearHubFeature: + break; + case ClearPortFeature: + // FIXME won't some of these need special handling? + dum->port_status &= ~(1 << wValue); + break; + case GetHubDescriptor: + hub_descriptor ((struct usb_hub_descriptor *) buf); + break; + case GetHubStatus: + *(u32 *) buf = __constant_cpu_to_le32 (0); + break; + case GetPortStatus: + if (wIndex != 1) + retval = -EPIPE; + ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); + ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + break; + case SetHubFeature: + retval = -EPIPE; + break; + case SetPortFeature: + if (wValue == USB_PORT_FEAT_RESET) { + /* if it's already running, disconnect first */ + if (dum->port_status & USB_PORT_STAT_ENABLE) { + dum->port_status &= ~(USB_PORT_STAT_ENABLE + | USB_PORT_STAT_LOW_SPEED + | USB_PORT_STAT_HIGH_SPEED); + if (dum->driver) { + dev_dbg (hardware, "disconnect\n"); + stop_activity (dum, dum->driver); + } + + /* FIXME test that code path! */ + } else + dum->port_status |= + (1 << USB_PORT_FEAT_C_ENABLE); + + dum->port_status |= USB_PORT_STAT_ENABLE | + (1 << USB_PORT_FEAT_C_RESET); + if (dum->driver) { + + /* give it the best speed we agree on */ + dum->gadget.speed = dum->driver->speed; + dum->gadget.ep0->maxpacket = 64; + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + dum->port_status |= + USB_PORT_STAT_HIGH_SPEED; + break; + case USB_SPEED_LOW: + dum->gadget.ep0->maxpacket = 8; + dum->port_status |= + USB_PORT_STAT_LOW_SPEED; + break; + default: + dum->gadget.speed = USB_SPEED_FULL; + break; + } + } + } else + dum->port_status |= (1 << wValue); + break; + + default: + dev_dbg (hardware, + "hub control req%04x v%04x i%04x l%d\n", + typeReq, wValue, wIndex, wLength); + + /* "protocol stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore (&dum->lock, flags); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +static struct usb_hcd *dummy_alloc (void) +{ + struct dummy *dum; + + dum = kmalloc (sizeof *dum, SLAB_KERNEL); + if (dum == NULL) + return 0; + memset (dum, 0, sizeof *dum); + return &dum->hcd; +} + +static void dummy_free (struct usb_hcd *hcd) +{ + struct dummy *dum; + + dum = container_of (hcd, struct dummy, hcd); + WARN_ON (dum->driver != 0); + kfree (dum); +} + +/*-------------------------------------------------------------------------*/ + +static inline ssize_t +show_urb (char *buf, size_t size, struct urb *urb) +{ + int ep = usb_pipeendpoint (urb->pipe); + + return snprintf (buf, size, + "urb/%p %s ep%d%s%s len %d/%d\n", + urb, + ({ char *s; + switch (urb->dev->speed) { + case USB_SPEED_LOW: s = "ls"; break; + case USB_SPEED_FULL: s = "fs"; break; + case USB_SPEED_HIGH: s = "hs"; break; + default: s = "?"; break; + }; s; }), + ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", + ({ char *s; \ + switch (usb_pipetype (urb->pipe)) { \ + case PIPE_CONTROL: s = ""; break; \ + case PIPE_BULK: s = "-bulk"; break; \ + case PIPE_INTERRUPT: s = "-int"; break; \ + default: s = "-iso"; break; \ + }; s;}), + urb->actual_length, urb->transfer_buffer_length); +} + +static ssize_t +show_urbs (struct device *dev, char *buf) +{ + struct dummy *dum = dev_get_drvdata(dev); + struct urb *urb; + size_t size = 0; + unsigned long flags; + + spin_lock_irqsave (&dum->lock, flags); + if (dum->hdev) { + list_for_each_entry (urb, &dum->hdev->urb_list, urb_list) { + size_t temp; + + temp = show_urb (buf, PAGE_SIZE - size, urb); + buf += temp; + size += temp; + } + } + spin_unlock_irqrestore (&dum->lock, flags); + + return size; +} +static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); + + +static const struct hc_driver dummy_hcd; + +static int dummy_start (struct usb_hcd *hcd) +{ + struct dummy *dum; + struct usb_bus *bus; + struct usb_device *root; + int retval; + + dum = container_of (hcd, struct dummy, hcd); + + /* + * MASTER side init ... we emulate a root hub that'll only ever + * talk to one device (the slave side). Also appears in sysfs, + * just like more familiar pci-based HCDs. + */ + spin_lock_init (&dum->lock); + + retval = driver_register (&dummy_driver); + if (retval < 0) + return retval; + + dum->pdev.name = "hc"; + dum->pdev.dev.driver = &dummy_driver; + dev_set_drvdata(&dum->pdev.dev, dum); + dum->pdev.dev.release = dummy_hc_release; + retval = platform_device_register (&dum->pdev); + if (retval < 0) { + driver_unregister (&dummy_driver); + return retval; + } + dev_info (&dum->pdev.dev, "%s, driver " DRIVER_VERSION "\n", + driver_desc); + + hcd->self.controller = &dum->pdev.dev; + + /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ + device_create_file (hcd->self.controller, &dev_attr_urbs); + + init_timer (&dum->timer); + dum->timer.function = dummy_timer; + dum->timer.data = (unsigned long) dum; + + /* root hub will appear as another device */ + dum->hcd.driver = (struct hc_driver *) &dummy_hcd; + dum->hcd.description = dummy_hcd.description; + dum->hcd.product_desc = "Dummy host controller"; + + bus = hcd_to_bus (&dum->hcd); + bus->bus_name = dum->pdev.dev.bus_id; + usb_bus_init (bus); + bus->op = &usb_hcd_operations; + bus->hcpriv = &dum->hcd; + + /* FIXME don't require the pci-based buffer/alloc impls; + * the "generic dma" implementation still requires them, + * it's not very generic yet. + */ + if ((retval = hcd_buffer_create (&dum->hcd)) != 0) { +clean0: + init_completion (&dum->released); + platform_device_unregister (&dum->pdev); + wait_for_completion (&dum->released); + driver_unregister (&dummy_driver); + return retval; + } + + INIT_LIST_HEAD (&hcd->dev_list); + usb_register_bus (bus); + + bus->root_hub = root = usb_alloc_dev (0, bus, 0); + if (!root) { + retval = -ENOMEM; +clean1: + hcd_buffer_destroy (&dum->hcd); + usb_deregister_bus (bus); + goto clean0; + } + + /* root hub enters addressed state... */ + dum->hcd.state = USB_STATE_RUNNING; + root->speed = USB_SPEED_HIGH; + + /* ...then configured, so khubd sees us. */ + if ((retval = hcd_register_root (&dum->hcd)) != 0) { + bus->root_hub = 0; + usb_put_dev (root); +clean2: + dum->hcd.state = USB_STATE_QUIESCING; + goto clean1; + } + + dum->started = 1; + + if ((retval = dummy_register_udc (dum)) != 0) { + dum->started = 0; + usb_disconnect (&bus->root_hub); + goto clean2; + } + return 0; +} + +static void dummy_stop (struct usb_hcd *hcd) +{ + struct dummy *dum; + struct usb_bus *bus; + + dum = container_of (hcd, struct dummy, hcd); + if (!dum->started) + return; + dum->started = 0; + + usb_gadget_unregister_driver (dum->driver); + dummy_unregister_udc (dum); + + bus = hcd_to_bus (&dum->hcd); + hcd->state = USB_STATE_QUIESCING; + dev_dbg (hardware, "remove root hub\n"); + usb_disconnect (&bus->root_hub); + + hcd_buffer_destroy (&dum->hcd); + usb_deregister_bus (bus); + + dev_info (hardware, "stopped\n"); + + device_remove_file (hcd->self.controller, &dev_attr_urbs); + init_completion (&dum->released); + platform_device_unregister (&dum->pdev); + wait_for_completion (&dum->released); + + driver_unregister (&dummy_driver); +} + +/*-------------------------------------------------------------------------*/ + +static int dummy_h_get_frame (struct usb_hcd *hcd) +{ + return dummy_g_get_frame (0); +} + +static const struct hc_driver dummy_hcd = { + .description = (char *) driver_name, + .flags = HCD_USB2, + + .start = dummy_start, + .stop = dummy_stop, + + .hcd_alloc = dummy_alloc, + .hcd_free = dummy_free, + + .urb_enqueue = dummy_urb_enqueue, + .urb_dequeue = dummy_urb_dequeue, + + .get_frame_number = dummy_h_get_frame, + + .hub_status_data = dummy_hub_status, + .hub_control = dummy_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init init (void) +{ + struct usb_hcd *hcd; + int value; + + if (usb_disabled ()) + return -ENODEV; + if ((hcd = dummy_alloc ()) == 0) + return -ENOMEM; + + the_controller = container_of (hcd, struct dummy, hcd); + value = dummy_start (hcd); + + if (value != 0) { + dummy_free (hcd); + the_controller = 0; + } + return value; +} +module_init (init); + +static void __exit cleanup (void) +{ + dummy_stop (&the_controller->hcd); + dummy_free (&the_controller->hcd); + the_controller = 0; +} +module_exit (cleanup); + diff -Nru a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/epautoconf.c Sun Mar 28 13:17:10 2004 @@ -0,0 +1,301 @@ +/* + * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers + * + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "gadget_chips.h" + + +/* we must assign addresses for configurable endpoints (like net2280) */ +static __initdata unsigned epnum; + +// #define MANY_ENDPOINTS +#ifdef MANY_ENDPOINTS +/* more than 15 configurable endpoints */ +static __initdata unsigned in_epnum; +#endif + + +/* + * This should work with endpoints from controller drivers sharing the + * same endpoint naming convention. By example: + * + * - ep1, ep2, ... address is fixed, not direction or type + * - ep1in, ep2out, ... address and direction are fixed, not type + * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction + * - ep1in-bulk, ep2out-iso, ... all three are fixed + * - ep-* ... no functionality restrictions + * + * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. + * Less common restrictions are implied by gadget_is_*(). + */ +static int __init +ep_matches ( + struct usb_gadget *gadget, + struct usb_ep *ep, + struct usb_endpoint_descriptor *desc +) +{ + u8 type; + const char *tmp; + u16 max; + + /* endpoint already claimed? */ + if (0 != ep->driver_data) + return 0; + + /* only support ep0 for portable CONTROL traffic */ + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (USB_ENDPOINT_XFER_CONTROL == type) + return 0; + + /* some other naming convention */ + if ('e' != ep->name[0]) + return 0; + + /* type-restriction: "-iso", "-bulk", or "-int". + * direction-restriction: "in", "out". + */ + if ('-' != ep->name[2]) { + tmp = strrchr (ep->name, '-'); + if (tmp) { + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if ('s' == tmp[2]) // == "-iso" + return 0; + /* for now, avoid PXA "interrupt-in"; + * it's documented as never using DATA1. + */ + if (gadget_is_pxa (gadget)) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if ('b' != tmp[1]) // != "-bulk" + return 0; + break; + case USB_ENDPOINT_XFER_ISOC: + if ('s' != tmp[2]) // != "-iso" + return 0; + } + } else { + tmp = ep->name + strlen (ep->name); + } + + /* direction-restriction: "..in-..", "out-.." */ + tmp--; + if (!isdigit (*tmp)) { + if (desc->bEndpointAddress & USB_DIR_IN) { + if ('n' != *tmp) + return 0; + } else { + if ('t' != *tmp) + return 0; + } + } + } + + /* endpoint maxpacket size is an input parameter, except for bulk + * where it's an output parameter representing the full speed limit. + * the usb spec fixes high speed bulk maxpacket at 512 bytes. + */ + max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize); + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* INT: limit 64 bytes full speed, 1024 high speed */ + if (!gadget->is_dualspeed && max > 64) + return 0; + /* FALLTHROUGH */ + + case USB_ENDPOINT_XFER_ISOC: + /* ISO: limit 1023 bytes full speed, 1024 high speed */ + if (ep->maxpacket < max) + return 0; + if (!gadget->is_dualspeed && max > 1023) + return 0; + + /* BOTH: "high bandwidth" works only at high speed */ + if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) { + if (!gadget->is_dualspeed) + return 0; + /* configure your hardware with enough buffering!! */ + } + break; + } + + /* MATCH!! */ + + /* report address */ + if (isdigit (ep->name [2])) { + u8 num = simple_strtol (&ep->name [2], NULL, 10); + desc->bEndpointAddress |= num; +#ifdef MANY_ENDPOINTS + } else if (desc->bEndpointAddress & USB_DIR_IN) { + if (++in_epnum > 15) + return 0; + desc->bEndpointAddress = USB_DIR_IN | in_epnum; +#endif + } else { + if (++epnum > 15) + return 0; + desc->bEndpointAddress |= epnum; + } + + /* report (variable) full speed bulk maxpacket */ + if (USB_ENDPOINT_XFER_BULK == type) + desc->wMaxPacketSize = cpu_to_le16 ( + min ((unsigned)64, ep->maxpacket)); + return 1; +} + +static struct usb_ep * __init +find_ep (struct usb_gadget *gadget, const char *name) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (0 == strcmp (ep->name, name)) + return ep; + } + return 0; +} + +/** + * usb_ep_autoconfig - choose an endpoint matching the descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on success. + * + * By choosing an endpoint to use with the specified descriptor, this + * routine simplifies writing gadget drivers that work with multiple + * USB device controllers. The endpoint would be passed later to + * usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration on your + * hardware. This code may not make the best choices about how to use the + * USB controller, and it can't know all the restrictions that may apply. + * Some combinations of driver and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed. To prevent + * the endpoint from being returned by a later autoconfig call, claim it + * by assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep * __init usb_ep_autoconfig ( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc +) +{ + struct usb_ep *ep; + u8 type; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* First, apply chip-specific "best usage" knowledge. + * This might make a good usb_gadget_ops hook ... + */ + if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = find_ep (gadget, "ep-e"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + ep = find_ep (gadget, "ep-f"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + + } else if (gadget_is_goku (gadget)) { + if (USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough */ + ep = find_ep (gadget, "ep3-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } else if (USB_ENDPOINT_XFER_BULK == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + ep = find_ep (gadget, "ep2-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } + + } else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough; maybe 8 byte fifo is too */ + ep = find_ep (gadget, "ep3in-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + + } else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) { + ep = find_ep (gadget, "ep1-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } + + /* Second, look at endpoints until an unclaimed one looks usable */ + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (ep_matches (gadget, ep, desc)) + return ep; + } + + /* Fail */ + return 0; +} + +/** + * usb_ep_autoconfig_reset - reset endpoint autoconfig state + * @gadget: device for which autoconfig state will be reset + * + * Use this for devices where one configuration may need to assign + * endpoint resources very differently from the next one. It clears + * state such as ep->driver_data and the record of assigned endpoints + * used by usb_ep_autoconfig(). + */ +void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + ep->driver_data = 0; + } +#ifdef MANY_ENDPOINTS + in_epnum = 0; +#endif + epnum = 0; +} + diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/ether.c Sun Mar 28 13:17:10 2004 @@ -55,6 +55,8 @@ #include #include +#include "gadget_chips.h" + /*-------------------------------------------------------------------------*/ /* @@ -62,26 +64,29 @@ * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look - * different for control features. And Microsoft pushes their own approach - * (RNDIS) instead of the standard. + * different for control features. This driver strongly prefers to use + * this USB-IF standard as its open-systems interoperability solution; + * most host side USB stacks (except from Microsoft) support it. * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but * link-level setup only requires activating the configuration. + * Linux supports it, but other host operating systems may not. + * + * A third option is also in use. Rather than CDC Ethernet, or something + * simpler, Microsoft pushes their own approach: RNDIS. The published + * RNDIS specs are ambiguous and appear to be incomplete, and are also + * needlessly complex. */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Bastille Day 2003" +#define DRIVER_VERSION "St Patrick's Day 2004" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; -#define MIN_PACKET sizeof(struct ethhdr) -#define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */ #define RX_EXTRA 20 /* guard against rx overflows */ -/* FIXME allow high speed jumbograms */ - /*-------------------------------------------------------------------------*/ struct eth_dev { @@ -100,214 +105,74 @@ atomic_t tx_qlen; struct work_struct work; + unsigned zlp:1; + unsigned cdc:1; unsigned long todo; #define WORK_RX_MEMORY 0 }; -/*-------------------------------------------------------------------------*/ - -/* Thanks to NetChip Technologies for donating this product ID. +/* This version autoconfigures as much as possible at run-time. * - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. + * It also ASSUMES a self-powered device, without remote wakeup, + * although remote wakeup support would make sense. */ -#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ -#define DRIVER_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; +static const char *EP_STATUS_NAME; /*-------------------------------------------------------------------------*/ -/* - * hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP - * - * hw_optimize(gadget) ... for any hardware tweaks we want to kick in - * before we enable our endpoints - * - * add other defines for other portability issues, like hardware that - * for some reason doesn't handle full speed bulk maxpacket of 64. - */ - -#define DEV_CONFIG_VALUE 3 /* some hardware cares */ - -/* #undef on hardware that can't implement CDC */ -#define DEV_CONFIG_CDC - -/* undef on bus-powered hardware, and #define MAX_USB_POWER */ -#define SELFPOWER - -/* - * NetChip 2280, PCI based. - * - * use DMA with fat fifos for all data traffic, PIO for the status channel - * where its 64 byte maxpacket ceiling is no issue. +/* Thanks to NetChip Technologies for donating this product ID. * - * performance note: only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f) - * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help. + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define DEFAULT_QLEN 4 /* has dma chaining */ -#define DRIVER_VERSION_NUM 0x0101 -static const char EP_OUT_NAME [] = "ep-a"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep-b"; -#define EP_IN_NUM 2 -static const char EP_STATUS_NAME [] = "ep-f"; -#define EP_STATUS_NUM 3 -/* supports remote wakeup, but this driver doesn't */ - -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); - -static inline void hw_optimize (struct usb_gadget *gadget) -{ - /* we can have bigger ep-a/ep-b fifos (2KB each, 4 USB packets - * for highspeed bulk) because we're not using ep-c/ep-d. - */ - net2280_set_fifo_mode (gadget, 1); -} -#endif +#define CDC_VENDOR_NUM 0x0525 /* NetChip */ +#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ -/* - * PXA-2xx UDC: widely used in second gen Linux-capable ARM PDAs - * and other products. - * - * multiple interfaces (or altsettings) aren't usable. so this hardware - * can't implement CDC, which needs both capabilities. +/* For hardware that can't talk CDC, we use the same vendor ID that + * ARM Linux has used for ethernet-over-usb, both with sa1100 and + * with pxa250. We're protocol-compatible, if the host-side drivers + * use the endpoint descriptors. bcdDevice (version) is nonzero, so + * drivers that need to hard-wire endpoint numbers have a hook. */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#undef DEV_CONFIG_CDC -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0103 -static const char EP_OUT_NAME [] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep1in-bulk"; -#define EP_IN_NUM 1 -/* supports remote wakeup, but this driver doesn't */ +#define SIMPLE_VENDOR_NUM 0x049f +#define SIMPLE_PRODUCT_NUM 0x505a -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * can't have a notification endpoint, since there are only the two - * bulk-capable ones. the CDC spec allows that. - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define DRIVER_VERSION_NUM 0x0105 -static const char EP_OUT_NAME [] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -// EP_STATUS_NUM is undefined -/* doesn't support remote wakeup? */ +/*-------------------------------------------------------------------------*/ -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif +#define DEV_CONFIG_VALUE 1 /* some hardware cares */ -/* - * Toshiba TC86C001 ("Goku-S") UDC +/* Include CDC code/data only if we could run on CDC-capable hardware. * - * This has three semi-configurable full speed bulk/interrupt endpoints. + * FIXME this driver should know how to choose between CDC and non-CDC + * configurations as it initializes, and while handling SET_CONFIGURATION + * and SET_INTERFACE requests. It doesn't yet. */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0106 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -static const char EP_STATUS_NAME [] = "ep3-bulk"; -#define EP_STATUS_NUM 3 -/* doesn't support remote wakeup */ -#define hw_optimize(g) do {} while (0) +#ifdef CONFIG_USB_GADGET_NET2280 +#define DEV_CONFIG_CDC #endif -/* - * SuperH UDC: UDC built-in to some Renesas SH processors. - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - * - * Only one configuration and interface is supported. So this hardware - * can't implement CDC. - */ -#ifdef CONFIG_USB_GADGET_SUPERH -#undef DEV_CONFIG_CDC -#define CHIP "superh" -#define DRIVER_VERSION_NUM 0x0107 -static const char EP_OUT_NAME[] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME[] = "ep2in-bulk"; -#define EP_IN_NUM 2 - -#define hw_optimize(g) do {} while (0) +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +// #define DEV_CONFIG_CDC #endif -/*-------------------------------------------------------------------------*/ - -#ifndef CHIP -# error Configure some USB peripheral controller driver! +#ifdef CONFIG_USB_GADGET_GOKU +#define DEV_CONFIG_CDC #endif -/* We normally expect hardware that can talk CDC. That involves - * using multiple interfaces and altsettings, and maybe a status - * interrupt. Driver binding to be done according to USB-IF class, - * though you can use different VENDOR and PRODUCT numbers if you - * want (and they're officially assigned). - * - * For hardware that can't talk CDC, we use the same vendor ID that - * ARM Linux has used for ethernet-over-usb, both with sa1100 and - * with pxa250. We're protocol-compatible, if the host-side drivers - * use the endpoint descriptors. DRIVER_VERSION_NUM is nonzero, so - * drivers that need to hard-wire endpoint numbers have a hook. - */ -#ifdef DEV_CONFIG_CDC -#define DEV_CONFIG_CLASS USB_CLASS_COMM -#else -#define DEV_CONFIG_CLASS USB_CLASS_VENDOR_SPEC -#undef EP_STATUS_NUM -#undef DRIVER_VENDOR_NUM -#undef DRIVER_PRODUCT_NUM -#define DRIVER_VENDOR_NUM 0x049f -#define DRIVER_PRODUCT_NUM 0x505a -#endif /* CONFIG_CDC_ETHER */ - -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef MAX_USB_POWER -#ifdef SELFPOWER -/* some hosts are confused by 0mA */ -#define MAX_USB_POWER 2 /* mA */ -#else -/* bus powered */ -#error Define your bus power consumption! +#ifdef CONFIG_USB_GADGET_MQ11XX +#define DEV_CONFIG_CDC #endif -#endif /* MAX_USB_POWER */ -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ +#ifdef CONFIG_USB_GADGET_OMAP +#define DEV_CONFIG_CDC #endif /*-------------------------------------------------------------------------*/ -#ifndef DEFAULT_QLEN #define DEFAULT_QLEN 2 /* double buffering by default */ -#endif #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -320,7 +185,7 @@ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) /* also defer IRQs on highspeed TX */ -#define TX_DELAY DEFAULT_QLEN +#define TX_DELAY qmult #else /* full speed (low speed doesn't do bulk) */ #define qlen(gadget) DEFAULT_QLEN @@ -386,13 +251,12 @@ .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = DEV_CONFIG_CLASS, + .bDeviceClass = USB_CLASS_COMM, .bDeviceSubClass = 0, .bDeviceProtocol = 0, - .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), - .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), + .idVendor = __constant_cpu_to_le16 (CDC_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (CDC_PRODUCT_NUM), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .bNumConfigurations = 1, @@ -404,39 +268,32 @@ .bDescriptorType = USB_DT_CONFIG, /* compute wTotalLength on the fly */ -#ifdef DEV_CONFIG_CDC .bNumInterfaces = 2, -#else - .bNumInterfaces = 1, -#endif .bConfigurationValue = DEV_CONFIG_VALUE, .iConfiguration = STRING_PRODUCT, - .bmAttributes = USB_CONFIG_ATT_ONE | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, }; #ifdef DEV_CONFIG_CDC /* * Compared to the "minimalist" non-CDC model, the CDC model adds - * three class descriptors, two interface descrioptors, and a status + * three class descriptors, two interface descriptors, optional status * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. */ /* master comm interface optionally has a status notification endpoint */ -static const struct usb_interface_descriptor +static struct usb_interface_descriptor control_intf = { .bLength = sizeof control_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, -#ifdef EP_STATUS_NUM + /* status endpoint is optional; this may be patched later */ .bNumEndpoints = 1, -#else - .bNumEndpoints = 0, -#endif .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = 6, /* ethernet control model */ .bInterfaceProtocol = 0, @@ -501,13 +358,11 @@ /* this descriptor actually adds value, surprise! */ .iMACAddress = STRING_ETHADDR, .bmEthernetStatistics = __constant_cpu_to_le32 (0), /* no statistics */ - .wMaxSegmentSize = __constant_cpu_to_le16 (MAX_PACKET + ETH_HLEN), + .wMaxSegmentSize = __constant_cpu_to_le16 (ETH_FRAME_LEN), .wNumberMCFilters = __constant_cpu_to_le16 (0), .bNumberPowerFilters = 0, }; -#ifdef EP_STATUS_NUM - /* include the status endpoint if we can, even though it's optional. * * some drivers (like current Linux cdc-ether!) "need" it to exist even @@ -518,17 +373,16 @@ #define LOG2_STATUS_INTERVAL_MSEC 6 #define STATUS_BYTECOUNT 16 /* 8 byte header + data */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, }; -#endif /* the default data interface has no endpoints ... */ @@ -585,24 +439,22 @@ #endif /* DEV_CONFIG_CDC */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; static const struct usb_descriptor_header *fs_function [] = { @@ -612,9 +464,8 @@ (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, -#ifdef EP_STATUS_NUM + /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &fs_status_desc, -#endif (struct usb_descriptor_header *) &data_nop_intf, #endif /* DEV_CONFIG_CDC */ /* minimalist core */ @@ -631,39 +482,34 @@ * descriptors, unless they only run at full speed. */ -#ifdef EP_STATUS_NUM -static const struct usb_endpoint_descriptor +#ifdef DEV_CONFIG_CDC +static struct usb_endpoint_descriptor hs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), .bInterval = LOG2_STATUS_INTERVAL_MSEC + 3, }; -#endif +#endif /* DEV_CONFIG_CDC */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), - .bInterval = 1, }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), - .bInterval = 1, }; static struct usb_qualifier_descriptor @@ -672,7 +518,7 @@ .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = DEV_CONFIG_CLASS, + .bDeviceClass = USB_CLASS_COMM, .bNumConfigurations = 1, }; @@ -684,9 +530,8 @@ (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, -#ifdef EP_STATUS_NUM + /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &hs_status_desc, -#endif (struct usb_descriptor_header *) &data_nop_intf, #endif /* DEV_CONFIG_CDC */ /* minimalist core */ @@ -711,6 +556,8 @@ /* descriptors that are built on-demand */ +static char manufacturer [40]; + #ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; @@ -718,7 +565,7 @@ /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE "/" CHIP, }, + { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, driver_desc, }, #ifdef DEV_CONFIG_CDC { STRING_ETHADDR, ethaddr, }, @@ -780,6 +627,9 @@ /* With CDC, the host isn't allowed to use these two data * endpoints in the default altsetting for the interface. * so we don't activate them yet. + * + * RNDIS is the same, but activation is a side effect of + * an RPC setting a packet filter (no SET_INTERFACE). */ /* one endpoint writes data back IN to the host */ @@ -799,9 +649,9 @@ continue; } -#ifdef EP_STATUS_NUM /* optional status/notification endpoint */ - else if (strcmp (ep->name, EP_STATUS_NAME) == 0) { + else if (EP_STATUS_NAME && + strcmp (ep->name, EP_STATUS_NAME) == 0) { d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); result = usb_ep_enable (ep, d); if (result == 0) { @@ -811,7 +661,6 @@ continue; } } -#endif #else /* !CONFIG_CDC_ETHER */ @@ -918,12 +767,10 @@ dev->out_ep = 0; } -#ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); dev->status_ep = 0; } -#endif dev->config = 0; } @@ -939,20 +786,20 @@ if (number == dev->config) return 0; -#ifdef CONFIG_USB_GADGET_SA1100 - if (dev->config && atomic_read (&dev->tx_qlen) != 0) { + if (gadget_is_sa1100 (gadget) + && dev->config + && atomic_read (&dev->tx_qlen) != 0) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } -#endif eth_reset_config (dev); - hw_optimize (gadget); switch (number) { case DEV_CONFIG_VALUE: result = set_ether_config (dev, gfp_flags); break; + // OR: RNDIS_CONFIG_VALUE ... default: result = -EINVAL; /* FALL THROUGH */ @@ -982,7 +829,7 @@ /*-------------------------------------------------------------------------*/ -#ifdef EP_STATUS_NUM +#ifdef DEV_CONFIG_CDC /* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */ #define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */ @@ -1175,17 +1022,6 @@ value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); break; -#ifdef CONFIG_USB_GADGET_PXA2XX - /* PXA UDC prevents us from using SET_INTERFACE in normal ways. - * And it hides GET_CONFIGURATION and GET_INTERFACE too. - */ - case USB_REQ_SET_INTERFACE: - spin_lock (&dev->lock); - value = eth_set_config (dev, DEV_CONFIG_VALUE, GFP_ATOMIC); - spin_unlock (&dev->lock); - break; - -#else /* hardware that that stays out of our way */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; @@ -1198,17 +1034,28 @@ || !dev->config || ctrl->wIndex > 1) break; + if (!dev->cdc && ctrl->wIndex != 0) + break; spin_lock (&dev->lock); + + /* PXA hardware partially handles SET_INTERFACE; + * we need to kluge around that interference. + */ + if (gadget_is_pxa (gadget)) { + value = eth_set_config (dev, DEV_CONFIG_VALUE, + GFP_ATOMIC); + goto done_set_intf; + } + +#ifdef DEV_CONFIG_CDC switch (ctrl->wIndex) { case 0: /* control/master intf */ if (ctrl->wValue != 0) break; -#ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); } -#endif value = 0; break; case 1: /* data intf */ @@ -1225,9 +1072,8 @@ usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); netif_carrier_on (dev->net); -#ifdef EP_STATUS_NUM - issue_start_status (dev); -#endif + if (dev->status_ep) + issue_start_status (dev); if (netif_running (dev->net)) { spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); @@ -1240,6 +1086,14 @@ value = 0; break; } +#else + /* FIXME this is wrong, as is the assumption that + * all non-PXA hardware talks real CDC ... + */ + dev_warn (&gadget->dev, "set_interface ignored!\n"); +#endif /* DEV_CONFIG_CDC */ + +done_set_intf: spin_unlock (&dev->lock); break; case USB_REQ_GET_INTERFACE: @@ -1247,6 +1101,8 @@ || !dev->config || ctrl->wIndex > 1) break; + if (!dev->cdc && ctrl->wIndex != 0) + break; /* if carrier is on, data interface is active. */ *(u8 *)req->buf = @@ -1255,7 +1111,6 @@ : 0, value = min (ctrl->wLength, (u16) 1); break; -#endif #ifdef DEV_CONFIG_CDC case CDC_SET_ETHERNET_PACKET_FILTER: @@ -1263,8 +1118,10 @@ * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) + || !dev->cdc || ctrl->wLength != 0 || ctrl->wIndex > 1) + break; DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue); /* NOTE: table 62 has 5 filter bits to reduce traffic, * and we "must" support multicast and promiscuous. @@ -1321,7 +1178,7 @@ { struct eth_dev *dev = (struct eth_dev *) net->priv; - if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET) + if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN) return -ERANGE; /* no zero-length packet read wanted after mtu-sized packets */ if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0) @@ -1351,7 +1208,8 @@ info.cmd = ETHTOOL_GDRVINFO; strlcpy (info.driver, shortname, sizeof info.driver); strlcpy (info.version, DRIVER_VERSION, sizeof info.version); - strlcpy (info.fw_version, CHIP, sizeof info.fw_version); + strlcpy (info.fw_version, dev->gadget->name, + sizeof info.fw_version); strlcpy (info.bus_info, dev->gadget->dev.bus_id, sizeof info.bus_info); if (copy_to_user (useraddr, &info, sizeof (info))) @@ -1439,8 +1297,7 @@ /* normal completion */ case 0: skb_put (skb, req->actual); - if (MIN_PACKET > skb->len - || skb->len > (MAX_PACKET + ETH_HLEN)) { + if (ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { dev->stats.rx_errors++; dev->stats.rx_length_errors++; DEBUG (dev, "rx length %d\n", skb->len); @@ -1642,16 +1499,14 @@ req->context = skb; req->complete = tx_complete; -#ifdef CONFIG_USB_GADGET_SA1100 - /* don't demand zlp (req->zero) support from all hardware */ - if ((length % dev->in_ep->maxpacket) == 0) - length++; -#else /* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. + * and some hardware doesn't like to write zlps. */ req->zero = 1; -#endif + if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0) + length++; + req->length = length; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1727,10 +1582,10 @@ usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); } -#ifdef EP_STATUS_NUM - usb_ep_disable (dev->status_ep); - usb_ep_enable (dev->status_ep, dev->status); -#endif + if (dev->status_ep) { + usb_ep_disable (dev->status_ep); + usb_ep_enable (dev->status_ep, dev->status); + } } return 0; @@ -1762,31 +1617,123 @@ set_gadget_data (gadget, 0); } -static int +static int __init eth_bind (struct usb_gadget *gadget) { struct eth_dev *dev; struct net_device *net; + u8 cdc = 1, zlp = 1; + struct usb_ep *ep; int status = -ENOMEM; -#ifdef DEV_CONFIG_CDC - u8 node_id [ETH_ALEN]; - /* just one upstream link at a time */ - if (ethaddr [0] != 0) + /* Because most host side USB stacks handle CDC Ethernet, that + * standard protocol is _strongly_ preferred for interop purposes. + * (By everyone except Microsoft.) + */ + if (gadget_is_net2280 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); + } else if (gadget_is_dummy (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0202); + } else if (gadget_is_pxa (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203); + /* pxa doesn't support altsettings */ + cdc = 0; + } else if (gadget_is_sh(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204); + /* sh doesn't support multiple interfaces or configs */ + cdc = 0; + } else if (gadget_is_sa1100 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205); + /* hardware can't write zlps */ + zlp = 0; + /* sa1100 CAN do CDC, without status endpoint ... we use + * non-CDC to be compatible with ARM Linux-2.4 "usb-eth". + */ + cdc = 0; + } else if (gadget_is_goku (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206); + } else if (gadget_is_mq11xx (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); + } else if (gadget_is_omap (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else { + /* can't assume CDC works. don't want to default to + * anything less functional on CDC-capable hardware, + * so we fail in this case. + */ + dev_err (&gadget->dev, + "controller '%s' not recognized\n", + gadget->name); + return -ENODEV; + } + +#ifndef DEV_CONFIG_CDC + /* in case someone doesn't add their hardware correctly */ + if (cdc) { + dev_err (&gadget->dev, + "CDC Ethernet support for '%s' is missing\n", + gadget->name); return -ENODEV; + } #endif - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + /* all we really need is bulk IN/OUT */ + usb_ep_autoconfig_reset (gadget); + ep = usb_ep_autoconfig (gadget, &fs_source_desc); + if (!ep) { +autoconf_fail: + dev_err (&gadget->dev, + "can't autoconfigure on %s\n", + gadget->name); + return -ENODEV; + } + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim */ + +#ifdef DEV_CONFIG_CDC + /* CDC Ethernet control interface doesn't require a status endpoint. + * Since some hosts expect one, try to allocate one anyway. + */ + if (cdc) { + ep = usb_ep_autoconfig (gadget, &fs_status_desc); + if (ep) { + EP_STATUS_NAME = ep->name; + ep->driver_data = ep; /* claim */ + } else { + control_intf.bNumEndpoints = 0; + /* FIXME remove endpoint from descriptor list */ + } + } else +#endif + eth_config.bNumInterfaces = 1; + #ifdef CONFIG_USB_GADGET_DUALSPEED + if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; +#ifdef DEV_CONFIG_CDC + if (EP_STATUS_NAME) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif -#ifdef SELFPOWERED - eth_config.bmAttributes |= USB_CONFIG_ATT_SELFPOWERED; - usb_gadget_set_selfpowered (gadget); #endif + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + usb_gadget_set_selfpowered (gadget); + net = alloc_etherdev (sizeof *dev); if (!net) return status; @@ -1800,6 +1747,12 @@ dev->net = net; SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); + dev->cdc = cdc; + dev->zlp = zlp; + + /* FIXME make these addresses configurable with module params. + * also the manufacturer and product strings. + */ /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. @@ -1812,12 +1765,16 @@ /* ... another address for the host, on the other end of the * link, gets exported through CDC (see CDC spec table 41) */ - get_random_bytes (node_id, sizeof node_id); - node_id [0] &= 0xfe; // clear multicast bit - node_id [0] |= 0x02; // set local assignment bit (IEEE802) - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - node_id [0], node_id [1], node_id [2], - node_id [3], node_id [4], node_id [5]); + if (cdc) { + u8 node_id [ETH_ALEN]; + + get_random_bytes (node_id, sizeof node_id); + node_id [0] &= 0xfe; // clear multicast bit + node_id [0] |= 0x02; // set local assignment bit (IEEE802) + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + node_id [0], node_id [1], node_id [2], + node_id [3], node_id [4], node_id [5]); + } #endif net->change_mtu = eth_change_mtu; @@ -1857,11 +1814,33 @@ status = register_netdev (dev->net); if (status == 0) { - INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", - driver_desc); + INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); + INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME, + EP_STATUS_NAME ? " STATUS " : "", + EP_STATUS_NAME ? EP_STATUS_NAME : "" + ); + INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + net->dev_addr [0], net->dev_addr [1], + net->dev_addr [2], net->dev_addr [3], + net->dev_addr [4], net->dev_addr [5]); + + if (!cdc) { + device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; + device_desc.idVendor = + __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM); + } #ifdef DEV_CONFIG_CDC - INFO (dev, "CDC host enet %s\n", ethaddr); + else + INFO (dev, "CDC host enet %s\n", ethaddr); #endif + + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE "/%s", + gadget->name); + return status; } dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status); diff -Nru a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h --- a/drivers/usb/gadget/gadget_chips.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/gadget_chips.h Sun Mar 28 13:17:10 2004 @@ -14,6 +14,12 @@ #define gadget_is_net2280(g) 0 #endif +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) +#else +#define gadget_is_dummy(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_PXA #define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) #else diff -Nru a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c --- a/drivers/usb/gadget/goku_udc.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/goku_udc.c Sun Mar 28 13:17:10 2004 @@ -1562,8 +1562,7 @@ if (dev->ep[tmp].is_in) goto stall; } - /* endpoint halt */ - if (ctrl.wValue != 0) + if (ctrl.wValue != USB_ENDPOINT_HALT) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/net2280.c Sun Mar 28 13:17:10 2004 @@ -2401,7 +2401,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) @@ -2418,7 +2418,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c --- a/drivers/usb/gadget/pxa2xx_udc.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/pxa2xx_udc.c Sun Mar 28 13:17:10 2004 @@ -94,7 +94,7 @@ #define UDC_PROC_FILE #endif -#ifdef CONFIG_ARCH_IXP425 +#ifdef CONFIG_ARCH_IXP4XX #undef USE_DMA /* cpu-specific register addresses are compiled in to this code */ @@ -2374,8 +2374,8 @@ #if defined(CONFIG_ARCH_PXA) #define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */ -#elif defined(CONFIG_ARCH_IXP425) -#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp425 */ +#elif defined(CONFIG_ARCH_IXP4XX) +#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp4xx */ #endif @@ -2434,7 +2434,7 @@ /* fall through */ case PXA250_C0: case PXA210_C0: break; -#elif defined(CONFIG_ARCH_IXP425) +#elif defined(CONFIG_ARCH_IXP4XX) case IXP425_A0: out_dma = 0; break; diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c --- a/drivers/usb/gadget/serial.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/serial.c Sun Mar 28 13:17:10 2004 @@ -207,6 +207,27 @@ /* + * Dummy_hcd, software-based loopback controller. + * + * This imitates the abilities of the NetChip 2280, so we will use + * the same configuration. + */ +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define CHIP "dummy" +#define EP0_MAXPACKET 64 +static const char EP_OUT_NAME[] = "ep-a"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME[] = "ep-b"; +#define EP_IN_NUM 2 +#define HIGHSPEED +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0) +#endif + + +/* * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. * * This has fifteen fixed-function full speed endpoints, and it diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c --- a/drivers/usb/gadget/usbstring.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/usbstring.c Sun Mar 28 13:17:10 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/gadget/zero.c Sun Mar 28 13:17:10 2004 @@ -89,10 +89,12 @@ #include #include +#include "gadget_chips.h" + /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "Bastille Day 2003" +#define DRIVER_VERSION "St Patrick's Day 2004" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -105,100 +107,12 @@ /* * driver assumes self-powered hardware, and * has no way for users to trigger remote wakeup. - */ - -/* - * hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * - * add other defines for other portability issues, like hardware that - * for some reason doesn't handle full speed bulk maxpacket of 64. - */ - -/* - * DRIVER_VERSION_NUM 0x0000 (?): Martin Diehl's ezusb an21/fx code - */ - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#if defined(CONFIG_USB_GADGET_NET2280) || defined(CONFIG_USB_GADGET_DUMMY_HCD) -#define CHIP "net2280" -#define DRIVER_VERSION_NUM 0x0101 -static const char EP_OUT_NAME [] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep-b"; -#define EP_IN_NUM 2 -#endif - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. + * this version autoconfigures as much as possible, + * which is reasonable for most "bulk-only" drivers. */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0103 -static const char EP_OUT_NAME [] = "ep12out-bulk"; -#define EP_OUT_NUM 12 -static const char EP_IN_NAME [] = "ep11in-bulk"; -#define EP_IN_NUM 11 -#endif - -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * This has only two fixed function endpoints, which can only - * be used for bulk (or interrupt) transfers. (Plus control.) - * - * Since it can't flush its TX fifos without disabling the UDC, - * the current configuration or altsettings can't change except - * in special situations. So this is a case of "choose it right - * during enumeration" ... - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define DRIVER_VERSION_NUM 0x0105 -static const char EP_OUT_NAME [] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -#endif - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0106 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -#endif - -/*-------------------------------------------------------------------------*/ - -#ifndef EP_OUT_NUM -# error Configure some USB peripheral controller driver! -#endif +static const char *EP_IN_NAME; /* source */ +static const char *EP_OUT_NAME; /* sink */ /*-------------------------------------------------------------------------*/ @@ -222,20 +136,19 @@ dev_printk(level , &(d)->gadget->dev , fmt , ## args) #ifdef DEBUG -#undef DEBUG -#define DEBUG(dev,fmt,args...) \ +#define DBG(dev,fmt,args...) \ xprintk(dev , KERN_DEBUG , fmt , ## args) #else -#define DEBUG(dev,fmt,args...) \ +#define DBG(dev,fmt,args...) \ do { } while (0) #endif /* DEBUG */ #ifdef VERBOSE -#define VDEBUG DEBUG +#define VDBG DBG #else -#define VDEBUG(dev,fmt,args...) \ +#define VDBG(dev,fmt,args...) \ do { } while (0) -#endif /* DEBUG */ +#endif /* VERBOSE */ #define ERROR(dev,fmt,args...) \ xprintk(dev , KERN_ERR , fmt , ## args) @@ -305,7 +218,6 @@ .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), - .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIAL, @@ -362,24 +274,22 @@ /* two full speed bulk endpoints; their use is config-dependent */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; static const struct usb_descriptor_header *fs_source_sink_function [] = { @@ -643,7 +553,7 @@ case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ - VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) check_read_data (dev, ep, req); @@ -656,7 +566,7 @@ */ default: #if 1 - DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name, + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length); #endif case -EREMOTEIO: /* short read */ @@ -747,7 +657,7 @@ break; } if (result == 0) - DEBUG (dev, "buflen %d\n", buflen); + DBG (dev, "buflen %d\n", buflen); /* caller is responsible for cleanup on error */ return result; @@ -858,14 +768,14 @@ req->complete = loopback_complete; result = usb_ep_queue (ep, req, GFP_ATOMIC); if (result) - DEBUG (dev, "%s queue req --> %d\n", + DBG (dev, "%s queue req --> %d\n", ep->name, result); } else result = -ENOMEM; } } if (result == 0) - DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen); + DBG (dev, "qlen %d, buflen %d\n", qlen, buflen); /* caller is responsible for cleanup on error */ return result; @@ -878,7 +788,7 @@ if (dev->config == 0) return; - DEBUG (dev, "reset config\n"); + DBG (dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. @@ -913,13 +823,11 @@ if (number == dev->config) return 0; -#ifdef CONFIG_USB_GADGET_SA1100 - if (dev->config) { + if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } -#endif zero_reset_config (dev); switch (number) { @@ -963,7 +871,7 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) - DEBUG ((struct zero_dev *) ep->driver_data, + DBG ((struct zero_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } @@ -1111,7 +1019,7 @@ default: unknown: - VDEBUG (dev, + VDBG (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); @@ -1122,7 +1030,7 @@ req->length = value; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { - DEBUG (dev, "ep_queue --> %d\n", value); + DBG (dev, "ep_queue --> %d\n", value); req->status = 0; zero_setup_complete (gadget->ep0, req); } @@ -1159,7 +1067,7 @@ { struct zero_dev *dev = get_gadget_data (gadget); - DEBUG (dev, "unbind\n"); + DBG (dev, "unbind\n"); /* we've already been disconnected ... no i/o is active */ if (dev->req) @@ -1172,7 +1080,70 @@ zero_bind (struct usb_gadget *gadget) { struct zero_dev *dev; + struct usb_ep *ep; + /* Bulk-only drivers like this one SHOULD be able to + * autoconfigure on any sane usb controller driver, + * but there may also be important quirks to address. + */ + usb_ep_autoconfig_reset (gadget); + ep = usb_ep_autoconfig (gadget, &fs_source_desc); + if (!ep) { +autoconf_fail: + printk (KERN_ERR "%s: can't autoconfigure on %s\n", + shortname, gadget->name); + return -ENODEV; + } + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + + /* + * DRIVER POLICY CHOICE: you may want to do this differently. + * One thing to avoid is reusing a bcdDevice revision code + * with different host-visible configurations or behavior + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc + */ + if (gadget_is_net2280 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); + } else if (gadget_is_pxa (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203); +#if 0 + } else if (gadget_is_sh(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204); + /* SH has only one configuration; see "loopdefault" */ + device_desc.bNumConfigurations = 1; + /* FIXME make 1 == default.bConfigurationValue */ +#endif + } else if (gadget_is_sa1100 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205); + } else if (gadget_is_goku (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206); + } else if (gadget_is_mq11xx (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); + } else if (gadget_is_omap (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else { + /* gadget zero is so simple (for now, no altsettings) that + * it SHOULD NOT have problems with bulk-capable hardware. + * so warn about unrcognized controllers, don't panic. + * + * things like configuration and altsetting numbering + * can need hardware-specific attention though. + */ + printk (KERN_WARNING "%s: controller '%s' not recognized\n", + shortname, gadget->name); + device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999); + } + + + /* ok, we made sense of the hardware ... */ dev = kmalloc (sizeof *dev, SLAB_KERNEL); if (!dev) return -ENOMEM; @@ -1202,6 +1173,8 @@ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif + + usb_gadget_set_selfpowered (gadget); gadget->ep0->driver_data = dev; diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/ehci-hcd.c Sun Mar 28 13:17:10 2004 @@ -374,6 +374,10 @@ u32 hcc_params; u8 tempbyte; + init_timer (&ehci->watchdog); + ehci->watchdog.function = ehci_watchdog; + ehci->watchdog.data = (unsigned long) ehci; + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -467,10 +471,6 @@ dbg_cmd (ehci, "init", temp); /* set async sleep time = 10 us ... ? */ - - init_timer (&ehci->watchdog); - ehci->watchdog.function = ehci_watchdog; - ehci->watchdog.data = (unsigned long) ehci; /* wire up the root hub */ bus = hcd_to_bus (hcd); diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/ohci-hcd.c Sun Mar 28 13:17:10 2004 @@ -344,8 +344,11 @@ if (!ed) goto done; - if (!HCD_IS_RUNNING (ohci->hcd.state)) + if (!HCD_IS_RUNNING (ohci->hcd.state)) { ed->state = ED_IDLE; + finish_unlinks (ohci, 0, 0); + } + switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/ohci-q.c Sun Mar 28 13:17:10 2004 @@ -156,6 +156,7 @@ wmb (); *prev = ed; *prev_p = cpu_to_le32p (&ed->dma); + wmb(); } ohci->load [i] += ed->load; } @@ -195,6 +196,7 @@ } ed->ed_prev = ohci->ed_controltail; if (!ohci->ed_controltail && !ohci->ed_rm_list) { + wmb(); ohci->hc_control |= OHCI_CTRL_CLE; writel (0, &ohci->regs->ed_controlcurrent); writel (ohci->hc_control, &ohci->regs->control); @@ -212,6 +214,7 @@ } ed->ed_prev = ohci->ed_bulktail; if (!ohci->ed_bulktail && !ohci->ed_rm_list) { + wmb(); ohci->hc_control |= OHCI_CTRL_BLE; writel (0, &ohci->regs->ed_bulkcurrent); writel (ohci->hc_control, &ohci->regs->control); @@ -868,6 +871,7 @@ td_dma = le32_to_cpup (&ohci->hcca->done_head); ohci->hcca->done_head = 0; + wmb(); /* get TD from hc's singly linked list, and * prepend to ours. ed->td_list changes later. diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/uhci-debug.c Sun Mar 28 13:17:10 2004 @@ -27,7 +27,7 @@ p = strchr(buf, '\n'); if (p) *p = 0; - printk("%s\n", buf); + printk(KERN_DEBUG "%s\n", buf); buf = p; if (buf) buf++; @@ -328,21 +328,17 @@ //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); - spin_lock(&urbp->urb->lock); count = 0; list_for_each(tmp, &urbp->td_list) count++; - spin_unlock(&urbp->urb->lock); out += sprintf(out, "TDs=%d ",count); if (urbp->queued) out += sprintf(out, "queued\n"); else { - spin_lock(&uhci->frame_list_lock); count = 0; list_for_each(tmp, &urbp->queue_list) count++; - spin_unlock(&uhci->frame_list_lock); out += sprintf(out, "queued URBs=%d\n", count); } @@ -352,12 +348,10 @@ static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) { char *out = buf; - unsigned long flags; struct list_head *head, *tmp; int count; out += sprintf(out, "Main list URBs:"); - spin_lock_irqsave(&uhci->urb_list_lock, flags); if (list_empty(&uhci->urb_list)) out += sprintf(out, " Empty\n"); else { @@ -373,10 +367,8 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); out += sprintf(out, "Remove list URBs:"); - spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); if (list_empty(&uhci->urb_remove_list)) out += sprintf(out, " Empty\n"); else { @@ -392,10 +384,8 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); out += sprintf(out, "Complete list URBs:"); - spin_lock_irqsave(&uhci->complete_list_lock, flags); if (list_empty(&uhci->complete_list)) out += sprintf(out, " Empty\n"); else { @@ -411,7 +401,6 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->complete_list_lock, flags); return out - buf; } @@ -425,7 +414,7 @@ struct uhci_td *td; struct list_head *tmp, *head; - spin_lock_irqsave(&uhci->frame_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); @@ -508,11 +497,11 @@ } } - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); - if (debug > 2) out += uhci_show_lists(uhci, out, len - (out - buf)); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); + return out - buf; } @@ -623,4 +612,3 @@ .release = uhci_proc_release, }; #endif - diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/uhci-hcd.c Sun Mar 28 13:17:10 2004 @@ -117,26 +117,18 @@ */ static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) { - unsigned long flags; - - spin_lock_irqsave(&uhci->frame_list_lock, flags); uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) { - spin_lock(&uhci->frame_list_lock); uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); - spin_unlock(&uhci->frame_list_lock); } static inline void uhci_moveto_complete(struct uhci_hcd *uhci, struct urb_priv *urbp) { - spin_lock(&uhci->complete_list_lock); list_move_tail(&urbp->urb_list, &uhci->complete_list); - spin_unlock(&uhci->complete_list_lock); } static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) @@ -178,12 +170,8 @@ */ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) { - unsigned long flags; - framenum %= UHCI_NUMFRAMES; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - td->frame = framenum; /* Is there a TD already mapped there? */ @@ -204,18 +192,13 @@ uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); uhci->fl->frame_cpu[framenum] = td; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) { - unsigned long flags; - /* If it's not inserted, don't remove it */ - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame == -1 && list_empty(&td->fl_list)) - goto out; + return; if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { @@ -240,9 +223,6 @@ list_del_init(&td->fl_list); td->frame = -1; - -out: - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -339,12 +319,11 @@ /* * Append this urb's qh after the last qh in skelqh->list - * MUST be called with uhci->frame_list_lock acquired * * Note that urb_priv.queue_list doesn't have a separate queue head; * it's a ring with every element "live". */ -static void _uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) +static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct list_head *tmp; @@ -396,36 +375,20 @@ list_add_tail(&urbp->qh->list, &skelqh->list); } -static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) -{ - unsigned long flags; - - spin_lock_irqsave(&uhci->frame_list_lock, flags); - _uhci_insert_qh(uhci, skelqh, urb); - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); -} - /* * Start removal of QH from schedule; it finishes next frame. * TDs should be unlinked before this is called. */ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - unsigned long flags; struct uhci_qh *pqh; if (!qh) return; - qh->urbp = NULL; - /* * Only go through the hoops if it's actually linked in - * Queued QHs are removed in uhci_delete_queued_urb, - * since (for queued URBs) the pqh is pointed to the next - * QH in the queue, not the next endpoint's QH. */ - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (!list_empty(&qh->list)) { pqh = list_entry(qh->list.prev, struct uhci_qh, list); @@ -450,11 +413,19 @@ /* continue the rest of the schedule */ qh->element = UHCI_PTR_TERM; + /* If our queue is nonempty, make the next URB the head */ + if (!list_empty(&qh->urbp->queue_list)) { + struct urb_priv *nurbp; + + nurbp = list_entry(qh->urbp->queue_list.next, + struct urb_priv, queue_list); + nurbp->queued = 0; + list_add_tail(&nurbp->qh->list, &qh->list); + } list_del_init(&qh->list); } - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); - spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); + qh->urbp = NULL; /* Check to see if the remove list is empty. Set the IOC bit */ /* to force an interrupt so we can remove the QH */ @@ -462,8 +433,6 @@ uhci_set_next_interrupt(uhci); list_add(&qh->remove_list, &uhci->qh_remove_list); - - spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); } static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) @@ -497,13 +466,10 @@ struct urb_priv *eurbp, *urbp, *furbp, *lurbp; struct list_head *tmp; struct uhci_td *lltd; - unsigned long flags; eurbp = eurb->hcpriv; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - /* Find the first URB in the queue */ if (eurbp->queued) { struct list_head *head = &eurbp->queue_list; @@ -543,8 +509,6 @@ list_add_tail(&urbp->queue_list, &furbp->queue_list); urbp->queued = 1; - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) @@ -554,14 +518,11 @@ struct urb_priv *purbp; struct uhci_td *pltd; unsigned int toggle; - unsigned long flags; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if (list_empty(&urbp->queue_list)) - goto out; + return; nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); @@ -603,39 +564,9 @@ usb_pipeout(urb->pipe), toggle); } - if (!urbp->queued) { - struct uhci_qh *pqh; - - nurbp->queued = 0; - - /* - * Fixup the previous QH's queue to link to the new head - * of this queue. - */ - pqh = list_entry(urbp->qh->list.prev, struct uhci_qh, list); - - if (pqh->urbp) { - struct list_head *head, *tmp; - - head = &pqh->urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - tmp = tmp->next; - - turbp->qh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - } - } - - pqh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - - list_add_tail(&nurbp->qh->list, &urbp->qh->list); - list_del_init(&urbp->qh->list); - } else { - /* We're somewhere in the middle (or end). A bit trickier */ - /* than the head scenario */ + if (urbp->queued) { + /* We're somewhere in the middle (or end). The case where + * we're at the head is handled in uhci_remove_qh(). */ purbp = list_entry(urbp->queue_list.prev, struct urb_priv, queue_list); @@ -649,9 +580,6 @@ } list_del_init(&urbp->queue_list); - -out: - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) @@ -679,9 +607,6 @@ return urbp; } -/* - * MUST be called with urb->lock acquired - */ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -691,9 +616,6 @@ list_add_tail(&td->list, &urbp->td_list); } -/* - * MUST be called with urb->lock acquired - */ static void uhci_remove_td_from_urb(struct uhci_td *td) { if (list_empty(&td->list)) @@ -704,14 +626,10 @@ td->urb = NULL; } -/* - * MUST be called with urb->lock acquired - */ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp; - unsigned long flags; urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) @@ -721,8 +639,6 @@ dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " "or uhci->remove_list!\n", urb); - spin_lock_irqsave(&uhci->td_remove_list_lock, flags); - /* Check to see if the remove list is empty. Set the IOC bit */ /* to force an interrupt so we can remove the TD's*/ if (list_empty(&uhci->td_remove_list)) @@ -740,42 +656,30 @@ list_add(&td->remove_list, &uhci->td_remove_list); } - spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags); - urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb) { - unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) { urbp->fsbr = 1; if (!uhci->fsbr++ && !uhci->fsbrtimeout) uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) { - unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) uhci->fsbrtimeout = jiffies + FSBR_DELAY; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -840,13 +744,16 @@ urb->setup_dma); /* - * If direction is "send", change the frame from SETUP (0x2D) - * to OUT (0xE1). Else change it from SETUP to IN (0x69). + * If direction is "send", change the packet ID from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69) and + * set Short Packet Detect (SPD) for all data packets. */ - destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe)); - - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (usb_pipeout(urb->pipe)) + destination ^= (USB_PID_SETUP ^ USB_PID_OUT); + else { + destination ^= (USB_PID_SETUP ^ USB_PID_IN); status |= TD_CTRL_SPD; + } /* * Build the DATA TD's @@ -923,50 +830,23 @@ } /* - * If control was short, then end status packet wasn't sent, so this - * reorganize s so it's sent to finish the transfer. The original QH is - * removed from the skel and discarded; all TDs except the last (status) - * are deleted; the last (status) TD is put on a new QH which is reinserted - * into the skel. Since the last TD and urb_priv are reused, the TD->link - * and urb_priv maintain any queued QHs. + * If control-IN transfer was short, the status packet wasn't sent. + * This routine changes the element pointer in the QH to point at the + * status TD. It's safe to do this even while the QH is live, because + * the hardware only updates the element pointer following a successful + * transfer. The inactive TD for the short packet won't cause an update, + * so the pointer won't get overwritten. The next time the controller + * sees this QH, it will send the status packet. */ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td; urbp->short_control_packet = 1; - /* Create a new QH to avoid pointer overwriting problems */ - uhci_remove_qh(uhci, urbp->qh); - - /* Delete all of the TD's except for the status TD at the end */ - head = &urbp->td_list; - tmp = head->next; - while (tmp != head && tmp->next != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - uhci_remove_td_from_urb(td); - uhci_remove_td(uhci, td); - uhci_free_td(uhci, td); - } - - urbp->qh = uhci_alloc_qh(uhci, urb->dev); - if (!urbp->qh) - return -ENOMEM; - - urbp->qh->urbp = urbp; - - /* One TD, who cares about Breadth first? */ - uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH); - - /* Low-speed transfers get a different queue */ - if (urb->dev->speed == USB_SPEED_LOW) - uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb); - else - uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb); + td = list_entry(urbp->td_list.prev, struct uhci_td, list); + urbp->qh->element = td->dma_handle; return -EINPROGRESS; } @@ -1101,17 +981,20 @@ status = uhci_maxerr(3) | TD_CTRL_ACTIVE; if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (usb_pipein(urb->pipe)) status |= TD_CTRL_SPD; /* * Build the DATA TD's */ do { /* Allow zero length packets */ - int pktsze = len; + int pktsze = maxsze; - if (pktsze > maxsze) - pktsze = maxsze; + if (pktsze >= len) { + pktsze = len; + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + status &= ~TD_CTRL_SPD; + } td = uhci_alloc_td(uhci, urb->dev); if (!td) @@ -1154,7 +1037,8 @@ } /* Set the flag on the last packet */ - td->status |= cpu_to_le32(TD_CTRL_IOC); + if (!(urb->transfer_flags & URB_NO_INTERRUPT)) + td->status |= cpu_to_le32(TD_CTRL_IOC); qh = uhci_alloc_qh(uhci, urb->dev); if (!qh) @@ -1409,9 +1293,6 @@ return ret; } -/* - * MUST be called with uhci->urb_list_lock acquired - */ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *tmp, *head; @@ -1449,7 +1330,7 @@ struct urb *eurb; int bustime; - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); if (urb->status != -EINPROGRESS) /* URB already unlinked! */ goto out; @@ -1506,14 +1387,12 @@ ret = 0; out: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); return ret; } /* * Return the result of a transfer - * - * MUST be called with urb_list_lock acquired */ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) { @@ -1549,7 +1428,6 @@ case PIPE_BULK: case PIPE_ISOCHRONOUS: /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ if (urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 1); uhci_unlink_generic(uhci, urb); @@ -1557,15 +1435,12 @@ case PIPE_INTERRUPT: /* Release bandwidth for Interrupt or Isoc. transfers */ /* Make sure we don't release if we have a queued URB */ - spin_lock(&uhci->frame_list_lock); - /* Spinlock needed ? */ if (list_empty(&urbp->queue_list) && urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); else /* bandwidth was passed on to queued URB, */ /* so don't let usb_unlink_urb() release it */ urb->bandwidth = 0; - spin_unlock(&uhci->frame_list_lock); uhci_unlink_generic(uhci, urb); break; default: @@ -1581,9 +1456,6 @@ spin_unlock(&urb->lock); } -/* - * MUST be called with urb->lock acquired - */ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *head, *tmp; @@ -1639,7 +1511,7 @@ unsigned long flags; struct urb_priv *urbp; - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); urbp = urb->hcpriv; if (!urbp) /* URB was never linked! */ goto done; @@ -1647,16 +1519,13 @@ uhci_unlink_generic(uhci, urb); - spin_lock(&uhci->urb_remove_list_lock); - /* If we're the first, set the next interrupt bit */ if (list_empty(&uhci->urb_remove_list)) uhci_set_next_interrupt(uhci); list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); - spin_unlock(&uhci->urb_remove_list_lock); done: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); return 0; } @@ -1718,7 +1587,7 @@ INIT_LIST_HEAD(&list); - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1734,12 +1603,15 @@ uhci_fsbr_timeout(uhci, u); /* Check if the URB timed out */ - if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) + if (u->timeout && u->status == -EINPROGRESS && + time_after_eq(jiffies, up->inserttime + u->timeout)) { + u->status = -ETIMEDOUT; list_move_tail(&up->urb_list, &list); + } spin_unlock(&u->lock); } - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); head = &list; tmp = head->next; @@ -1781,7 +1653,6 @@ { struct list_head *tmp, *head; - spin_lock(&uhci->qh_remove_list_lock); head = &uhci->qh_remove_list; tmp = head->next; while (tmp != head) { @@ -1793,14 +1664,12 @@ uhci_free_qh(uhci, qh); } - spin_unlock(&uhci->qh_remove_list_lock); } static void uhci_free_pending_tds(struct uhci_hcd *uhci) { struct list_head *tmp, *head; - spin_lock(&uhci->td_remove_list_lock); head = &uhci->td_remove_list; tmp = head->next; while (tmp != head) { @@ -1812,18 +1681,17 @@ uhci_free_td(uhci, td); } - spin_unlock(&uhci->td_remove_list_lock); } static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - spin_lock(&urb->lock); uhci_destroy_urb_priv(uhci, urb); - spin_unlock(&urb->lock); + spin_unlock(&uhci->schedule_lock); usb_hcd_giveback_urb(hcd, urb, regs); + spin_lock(&uhci->schedule_lock); } static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) @@ -1831,7 +1699,6 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct list_head *tmp, *head; - spin_lock(&uhci->complete_list_lock); head = &uhci->complete_list; tmp = head->next; while (tmp != head) { @@ -1839,26 +1706,18 @@ struct urb *urb = urbp->urb; list_del_init(&urbp->urb_list); - spin_unlock(&uhci->complete_list_lock); - uhci_finish_urb(hcd, urb, regs); - spin_lock(&uhci->complete_list_lock); head = &uhci->complete_list; tmp = head->next; } - spin_unlock(&uhci->complete_list_lock); } static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) { - spin_lock(&uhci->urb_remove_list_lock); - spin_lock(&uhci->complete_list_lock); /* Splice the urb_remove_list onto the end of the complete_list */ list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); - spin_unlock(&uhci->complete_list_lock); - spin_unlock(&uhci->urb_remove_list_lock); } static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) @@ -1895,16 +1754,15 @@ if (status & USBSTS_RD) uhci->resume_detect = 1; - uhci_free_pending_qhs(uhci); + spin_lock(&uhci->schedule_lock); + uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); - uhci_remove_pending_urbps(uhci); uhci_clear_next_interrupt(uhci); /* Walk the list of pending URB's to see which ones completed */ - spin_lock(&uhci->urb_list_lock); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1916,9 +1774,10 @@ /* Checks the status and does all of the magic necessary */ uhci_transfer_result(uhci, urb); } - spin_unlock(&uhci->urb_list_lock); - uhci_finish_completion(hcd, regs); + + spin_unlock(&uhci->schedule_lock); + return IRQ_HANDLED; } @@ -2208,23 +2067,17 @@ uhci->fsbr = 0; uhci->fsbrtimeout = 0; - spin_lock_init(&uhci->qh_remove_list_lock); + spin_lock_init(&uhci->schedule_lock); INIT_LIST_HEAD(&uhci->qh_remove_list); - spin_lock_init(&uhci->td_remove_list_lock); INIT_LIST_HEAD(&uhci->td_remove_list); - spin_lock_init(&uhci->urb_remove_list_lock); INIT_LIST_HEAD(&uhci->urb_remove_list); - spin_lock_init(&uhci->urb_list_lock); INIT_LIST_HEAD(&uhci->urb_list); - spin_lock_init(&uhci->complete_list_lock); INIT_LIST_HEAD(&uhci->complete_list); - spin_lock_init(&uhci->frame_list_lock); - uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), &dma_handle, 0); if (!uhci->fl) { @@ -2416,7 +2269,6 @@ static void uhci_stop(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; del_timer_sync(&uhci->stall_timer); @@ -2424,16 +2276,18 @@ * At this point, we're guaranteed that no new connects can be made * to this bus since there are no more parents */ - local_irq_save(flags); + spin_lock_irq(&uhci->schedule_lock); uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); uhci_remove_pending_urbps(uhci); + spin_unlock_irq(&uhci->schedule_lock); reset_hc(uhci); + spin_lock_irq(&uhci->schedule_lock); uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); - local_irq_restore(flags); + spin_unlock_irq(&uhci->schedule_lock); release_uhci(uhci); } diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/host/uhci-hcd.h Sun Mar 28 13:17:10 2004 @@ -342,8 +342,8 @@ struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ - spinlock_t frame_list_lock; - struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ + spinlock_t schedule_lock; + struct uhci_frame_list *fl; /* P: uhci->schedule_lock */ int fsbr; /* Full-speed bandwidth reclamation */ unsigned long fsbrtimeout; /* FSBR delay */ @@ -353,24 +353,19 @@ unsigned int saved_framenumber; /* Save during PM suspend */ /* Main list of URB's currently controlled by this HC */ - spinlock_t urb_list_lock; - struct list_head urb_list; /* P: uhci->urb_list_lock */ + struct list_head urb_list; /* P: uhci->schedule_lock */ /* List of QH's that are done, but waiting to be unlinked (race) */ - spinlock_t qh_remove_list_lock; - struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ + struct list_head qh_remove_list; /* P: uhci->schedule_lock */ /* List of TD's that are done, but waiting to be freed (race) */ - spinlock_t td_remove_list_lock; - struct list_head td_remove_list; /* P: uhci->td_remove_list_lock */ + struct list_head td_remove_list; /* P: uhci->schedule_lock */ /* List of asynchronously unlinked URB's */ - spinlock_t urb_remove_list_lock; - struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ + struct list_head urb_remove_list; /* P: uhci->schedule_lock */ /* List of URB's awaiting completion callback */ - spinlock_t complete_list_lock; - struct list_head complete_list; /* P: uhci->complete_list_lock */ + struct list_head complete_list; /* P: uhci->schedule_lock */ int rh_numports; @@ -401,26 +396,15 @@ /* * Locking in uhci.c * - * spinlocks are used extensively to protect the many lists and data - * structures we have. It's not that pretty, but it's necessary. We - * need to be done with all of the locks (except complete_list_lock) when - * we call urb->complete. I've tried to make it simple enough so I don't - * have to spend hours racking my brain trying to figure out if the - * locking is safe. + * Almost everything relating to the hardware schedule and processing + * of URBs is protected by uhci->schedule_lock. urb->status is protected + * by urb->lock; that's the one exception. * - * Here's the safe locking order to prevent deadlocks: + * To prevent deadlocks, never lock uhci->schedule_lock while holding + * urb->lock. The safe order of locking is: * - * #1 uhci->urb_list_lock + * #1 uhci->schedule_lock * #2 urb->lock - * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, - * uhci->qh_remove_list_lock - * #4 uhci->complete_list_lock - * - * If you're going to grab 2 or more locks at once, ALWAYS grab the lock - * at the lowest level FIRST and NEVER grab locks at the same level at the - * same time. - * - * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock */ #endif diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/aiptek.c Sun Mar 28 13:17:10 2004 @@ -265,7 +265,7 @@ const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev (intf); - struct usb_host_interface *interface = intf->altsetting + 0; + struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; int err = -ENOMEM; diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c --- a/drivers/usb/input/ati_remote.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/ati_remote.c Sun Mar 28 13:17:10 2004 @@ -99,7 +99,7 @@ #define DATA_BUFSIZE 63 /* size of URB data buffers */ #define ATI_INPUTNUM 1 /* Which input device to register as */ -unsigned long channel_mask = 0; +static unsigned long channel_mask = 0; module_param(channel_mask, ulong, 444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); @@ -139,6 +139,8 @@ */ #define FILTER_TIME (HZ >> 4) +static DECLARE_MUTEX(disconnect_sem); + struct ati_remote { struct input_dev idev; struct usb_device *udev; @@ -286,12 +288,12 @@ static void ati_remote_dump(unsigned char *data, unsigned int len) { if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - warn("Weird byte 0x%02x\n", data[0]); + warn("Weird byte 0x%02x", data[0]); else if (len == 4) - warn("Weird key %02x %02x %02x %02x\n", + warn("Weird key %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); else - warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", len, data[0], data[1], data[2], data[3], data[4], data[5]); } @@ -301,9 +303,12 @@ static int ati_remote_open(struct input_dev *inputdev) { struct ati_remote *ati_remote = inputdev->private; + int retval = 0; + + down(&disconnect_sem); if (ati_remote->open++) - return 0; + goto exit; /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; @@ -311,10 +316,12 @@ dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __FUNCTION__); ati_remote->open--; - return -EIO; + retval = -EIO; } - return 0; +exit: + up(&disconnect_sem); + return retval; } /* @@ -354,8 +361,7 @@ ati_remote->send_flags |= SEND_FLAG_COMPLETE; wmb(); - if (waitqueue_active(&ati_remote->wait)) - wake_up(&ati_remote->wait); + wake_up(&ati_remote->wait); } /* @@ -377,18 +383,16 @@ ati_remote->out_urb->dev = ati_remote->udev; ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ati_remote->wait, &wait); - - retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL); + retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); if (retval) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&ati_remote->wait, &wait); dev_dbg(&ati_remote->interface->dev, "sendpacket: usb_submit_urb failed: %d\n", retval); return retval; } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ati_remote->wait, &wait); + while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) { timeout = schedule_timeout(timeout); @@ -594,11 +598,7 @@ if (ati_remote->out_urb) usb_unlink_urb(ati_remote->out_urb); - if (ati_remote->irq_urb) - usb_free_urb(ati_remote->irq_urb); - - if (ati_remote->out_urb) - usb_free_urb(ati_remote->out_urb); + input_unregister_device(&ati_remote->idev); if (ati_remote->inbuf) usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, @@ -608,6 +608,12 @@ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, ati_remote->inbuf, ati_remote->outbuf_dma); + if (ati_remote->irq_urb) + usb_free_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_free_urb(ati_remote->out_urb); + kfree(ati_remote); } @@ -779,14 +785,14 @@ usb_set_intfdata(interface, ati_remote); ati_remote->present = 1; - kfree(buf); - return 0; error: if (buf) kfree(buf); - ati_remote_delete(ati_remote); + if (retval) + ati_remote_delete(ati_remote); + return retval; } @@ -796,7 +802,9 @@ static void ati_remote_disconnect(struct usb_interface *interface) { struct ati_remote *ati_remote; - + + down(&disconnect_sem); + ati_remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!ati_remote) { @@ -804,14 +812,14 @@ return; } - input_unregister_device(&ati_remote->idev); - /* Mark device as unplugged */ ati_remote->present = 0; /* If device is still open, ati_remote_close will call delete. */ if (!ati_remote->open) ati_remote_delete(ati_remote); + + up(&disconnect_sem); } /* diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/hiddev.c Sun Mar 28 13:17:10 2004 @@ -403,8 +403,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref_multi uref_multi; - struct hiddev_usage_ref *uref = &uref_multi.uref; + struct hiddev_usage_ref_multi *uref_multi=NULL; + struct hiddev_usage_ref *uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -576,26 +576,31 @@ return 0; case HIDIOCGUCODE: - if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) + goto fault; rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto inval; uref->usage_code = field->usage[uref->usage_index].hid; if (copy_to_user((void *) arg, uref, sizeof(*uref))) - return -EFAULT; + goto fault; + kfree(uref_multi); return 0; case HIDIOCGUSAGE: @@ -603,42 +608,46 @@ case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (copy_from_user(&uref_multi, (void *) arg, + if (copy_from_user(uref_multi, (void *) arg, sizeof(uref_multi))) - return -EFAULT; + goto fault; } else { if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + goto fault; } if (cmd != HIDIOCGUSAGE && cmd != HIDIOCGUSAGES && uref->report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + goto inval; if (uref->report_id == HID_REPORT_ID_UNKNOWN) { field = hiddev_lookup_usage(hid, uref); if (field == NULL) - return -EINVAL; + goto inval; } else { rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto inval; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi.num_values >= HID_MAX_USAGES || + if (uref_multi->num_values >= HID_MAX_USAGES || uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi.num_values) >= field->maxusage) - return -EINVAL; + (uref->usage_index + uref_multi->num_values) >= field->maxusage) + goto inval; } } @@ -646,31 +655,40 @@ case HIDIOCGUSAGE: uref->value = field->value[uref->usage_index]; if (copy_to_user((void *) arg, uref, sizeof(*uref))) - return -EFAULT; - return 0; + goto fault; + goto goodreturn; case HIDIOCSUSAGE: field->value[uref->usage_index] = uref->value; - return 0; + goto goodreturn; case HIDIOCGCOLLECTIONINDEX: + kfree(uref_multi); return field->usage[uref->usage_index].collection_index; case HIDIOCGUSAGES: - for (i = 0; i < uref_multi.num_values; i++) - uref_multi.values[i] = + for (i = 0; i < uref_multi->num_values; i++) + uref_multi->values[i] = field->value[uref->usage_index + i]; - if (copy_to_user((void *) arg, &uref_multi, - sizeof(uref_multi))) - return -EFAULT; - return 0; + if (copy_to_user((void *) arg, uref_multi, + sizeof(*uref_multi))) + goto fault; + goto goodreturn; case HIDIOCSUSAGES: - for (i = 0; i < uref_multi.num_values; i++) + for (i = 0; i < uref_multi->num_values; i++) field->value[uref->usage_index + i] = - uref_multi.values[i]; - return 0; + uref_multi->values[i]; + goto goodreturn; } +goodreturn: + kfree(uref_multi); return 0; +fault: + kfree(uref_multi); + return -EFAULT; +inval: + kfree(uref_multi); + return -EINVAL; case HIDIOCGCOLLECTIONINFO: if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/kbtab.c Sun Mar 28 13:17:10 2004 @@ -182,7 +182,7 @@ kbtab->dev.dev = &intf->dev; kbtab->usbdev = dev; - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(kbtab->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/powermate.c Sun Mar 28 13:17:10 2004 @@ -305,7 +305,7 @@ int pipe, maxp; char path[64]; - interface = intf->altsetting + 0; + interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; if (!(endpoint->bEndpointAddress & 0x80)) return -EIO; diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/wacom.c Sun Mar 28 13:17:10 2004 @@ -698,7 +698,7 @@ wacom->dev.dev = &intf->dev; wacom->usbdev = dev; - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; if (wacom->features->pktlen > 10) BUG(); diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/input/xpad.c Sun Mar 28 13:17:10 2004 @@ -252,7 +252,7 @@ return -ENOMEM; } - ep_irq_in = &intf->altsetting[0].endpoint[0].desc; + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/media/Kconfig Sun Mar 28 13:17:10 2004 @@ -108,7 +108,7 @@ config USB_PWC tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV + depends on USB && VIDEO_DEV && BROKEN ---help--- Say Y or M here if you want to use one of these Philips & OEM webcams: diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/media/vicam.c Sun Mar 28 13:17:10 2004 @@ -1269,6 +1269,8 @@ /** * vicam_probe + * @intf: the interface + * @id: the device id * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. diff -Nru a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c --- a/drivers/usb/media/w9968cf.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/media/w9968cf.c Sun Mar 28 13:17:10 2004 @@ -905,8 +905,7 @@ spin_unlock(&cam->urb_lock); /* Wake up the user process */ - if (waitqueue_active(&cam->wait_queue)) - wake_up_interruptible(&cam->wait_queue); + wake_up_interruptible(&cam->wait_queue); } @@ -2690,6 +2689,7 @@ up(&cam->dev_sem); return -EWOULDBLOCK; } +retry: up(&cam->dev_sem); err = wait_event_interruptible(cam->open, cam->disconnected || (cam->users == 0)); @@ -2698,6 +2698,9 @@ if (cam->disconnected) return -ENODEV; down(&cam->dev_sem); + /*recheck - there may be several waiters */ + if (cam->users) + goto retry; } DBG(5, "Opening '%s', /dev/video%d ...", @@ -2758,8 +2761,7 @@ cam->users--; w9968cf_deallocate_memory(cam); - if (waitqueue_active(&cam->open)) - wake_up_interruptible(&cam->open); + wake_up_interruptible(&cam->open); DBG(5, "Video device closed.") up(&cam->dev_sem); diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig --- a/drivers/usb/misc/Kconfig Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/misc/Kconfig Sun Mar 28 13:17:10 2004 @@ -108,6 +108,19 @@ To compile this driver as a module, choose M here: the module will be called usbled. +config USB_CYTHERM + tristate "Cypress USB thermometer driver support" + depends on USB + help + Say Y here if you want to connect a Cypress USB thermometer + device to your computer's USB port. This device is also known + as the Cypress USB Starter kit or demo board. The Elektor + magazine published a modified version of this device in issue + #291. + + To compile this driver as a module, choose M here: the + module will be called cytherm. + config USB_SPEEDTOUCH tristate "Alcatel Speedtouch USB support" depends on USB && ATM diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile --- a/drivers/usb/misc/Makefile Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/misc/Makefile Sun Mar 28 13:17:10 2004 @@ -4,8 +4,9 @@ # obj-$(CONFIG_USB_AUERSWALD) += auerswald.o -obj-$(CONFIG_USB_EMI62) += emi62.o +obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o +obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o diff -Nru a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/misc/cytherm.c Sun Mar 28 13:17:10 2004 @@ -0,0 +1,433 @@ +/* -*- linux-c -*- + * Cypress USB Thermometer driver + * + * Copyright (c) 2004 Erik Rigtorp + * + * This driver works with Elektor magazine USB Interface as published in + * issue #291. It should also work with the original starter kit/demo board + * from Cypress. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + + +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Erik Rigtorp" +#define DRIVER_DESC "Cypress USB Thermometer driver" + +#define USB_SKEL_VENDOR_ID 0x04b4 +#define USB_SKEL_PRODUCT_ID 0x0002 + +static struct usb_device_id id_table [] = { + { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, + { } +}; +MODULE_DEVICE_TABLE (usb, id_table); + +/* Structure to hold all of our device specific stuff */ +struct usb_cytherm { + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + int brightness; +}; + + +/* local function prototypes */ +static int cytherm_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void cytherm_disconnect(struct usb_interface *interface); +int vendor_command(struct usb_device *dev, unsigned char request, + unsigned char value, unsigned char index, + void *buf, int size); + + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver cytherm_driver = { + .owner = THIS_MODULE, + .name = "cytherm", + .probe = cytherm_probe, + .disconnect = cytherm_disconnect, + .id_table = id_table, +}; + +/* Vendor requests */ +/* They all operate on one byte at a time */ +#define PING 0x00 +#define READ_ROM 0x01 /* Reads form ROM, value = address */ +#define READ_RAM 0x02 /* Reads form RAM, value = address */ +#define WRITE_RAM 0x03 /* Write to RAM, value = address, index = data */ +#define READ_PORT 0x04 /* Reads from port, value = address */ +#define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ + + +/* Send a vendor command to device */ +int vendor_command(struct usb_device *dev, unsigned char request, + unsigned char value, unsigned char index, + void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, + index, buf, size, + HZ * USB_CTRL_GET_TIMEOUT); +} + + + +#define BRIGHTNESS 0x2c /* RAM location for brightness value */ +#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */ + +static ssize_t show_brightness(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + return sprintf(buf, "%i", cytherm->brightness); +} + +static ssize_t set_brightness(struct device *dev, const char *buf, + size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + cytherm->brightness = simple_strtoul(buf, NULL, 10); + + if (cytherm->brightness > 0xFF) + cytherm->brightness = 0xFF; + else if (cytherm->brightness < 0) + cytherm->brightness = 0; + + /* Set brightness */ + retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, + cytherm->brightness, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + /* Inform µC that we have changed the brightness setting */ + retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM, + 0x01, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, + show_brightness, set_brightness); + + +#define TEMP 0x33 /* RAM location for temperature */ +#define SIGN 0x34 /* RAM location for temperature sign */ + +static ssize_t show_temp(struct device *dev, char *buf) +{ + + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + int temp, sign; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + /* read temperature */ + retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + temp = buffer[1]; + + /* read sign */ + retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + sign = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1, + 5*(temp - ((temp >> 1) << 1))); +} + + +static ssize_t set_temp(struct device *dev, const char *buf, size_t count) +{ + return count; +} + +static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp); + + +#define BUTTON 0x7a + +static ssize_t show_button(struct device *dev, char *buf) +{ + + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + /* check button */ + retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + if (retval) + return sprintf(buf, "1"); + else + return sprintf(buf, "0"); +} + + +static ssize_t set_button(struct device *dev, const char *buf, size_t count) +{ + return count; +} + +static DEVICE_ATTR(button, S_IRUGO, show_button, set_button); + + +static ssize_t show_port0(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%d", retval); +} + + +static ssize_t set_port0(struct device *dev, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + int tmp; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + tmp = simple_strtoul(buf, NULL, 10); + + if (tmp > 0xFF) + tmp = 0xFF; + else if (tmp < 0) + tmp = 0; + + retval = vendor_command(cytherm->udev, WRITE_PORT, 0, + tmp, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0); + +static ssize_t show_port1(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%d", retval); +} + + +static ssize_t set_port1(struct device *dev, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + int tmp; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + tmp = simple_strtoul(buf, NULL, 10); + + if (tmp > 0xFF) + tmp = 0xFF; + else if (tmp < 0) + tmp = 0; + + retval = vendor_command(cytherm->udev, WRITE_PORT, 1, + tmp, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1); + + + +static int cytherm_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_cytherm *dev = NULL; + int retval = -ENOMEM; + + dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL); + if (dev == NULL) { + dev_err (&interface->dev, "Out of memory\n"); + goto error; + } + memset (dev, 0x00, sizeof (*dev)); + + dev->udev = usb_get_dev(udev); + + usb_set_intfdata (interface, dev); + + dev->brightness = 0xFF; + + device_create_file(&interface->dev, &dev_attr_brightness); + device_create_file(&interface->dev, &dev_attr_temp); + device_create_file(&interface->dev, &dev_attr_button); + device_create_file(&interface->dev, &dev_attr_port0); + device_create_file(&interface->dev, &dev_attr_port1); + + dev_info (&interface->dev, + "Cypress thermometer device now attached\n"); + return 0; + + error: + kfree(dev); + return retval; +} + +static void cytherm_disconnect(struct usb_interface *interface) +{ + struct usb_cytherm *dev; + + dev = usb_get_intfdata (interface); + usb_set_intfdata (interface, NULL); + + device_remove_file(&interface->dev, &dev_attr_brightness); + device_remove_file(&interface->dev, &dev_attr_temp); + device_remove_file(&interface->dev, &dev_attr_button); + device_remove_file(&interface->dev, &dev_attr_port0); + device_remove_file(&interface->dev, &dev_attr_port1); + + usb_put_dev(dev->udev); + + kfree(dev); + + dev_info(&interface->dev, "Cypress thermometer now disconnected\n"); +} + + +static int __init usb_cytherm_init(void) +{ + int result; + + result = usb_register(&cytherm_driver); + if (result) + { + err("usb_register failed. Error number %d", result); + return result; + } + + info(DRIVER_VERSION ":" DRIVER_DESC); + return 0; +} + +static void __exit usb_cytherm_exit(void) +{ + usb_deregister(&cytherm_driver); +} + + +module_init (usb_cytherm_init); +module_exit (usb_cytherm_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/misc/usbtest.c Sun Mar 28 13:17:10 2004 @@ -1169,7 +1169,8 @@ /* set halt (protocol test only), verify it worked */ retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, 0, ep, + USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, ep, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); if (retval < 0) { dbg ("ep %02x couldn't set halt, %d", ep, retval); diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig --- a/drivers/usb/net/Kconfig Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/net/Kconfig Sun Mar 28 13:17:10 2004 @@ -69,7 +69,7 @@ config USB_PEGASUS tristate "USB Pegasus/Pegasus-II based ethernet device support" - depends on USB && NET_ETHERNET + depends on USB && NET select MII ---help--- Say Y here if you know you have Pegasus or Pegasus-II based adapter. diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/net/rtl8150.c Sun Mar 28 13:17:10 2004 @@ -20,7 +20,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v0.5.7 (2002/12/31)" +#define DRIVER_VERSION "v0.6.1 (2004/03/13)" #define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "rtl8150 based usb-ethernet driver" @@ -43,6 +43,8 @@ #define ANAR 0x0144 #define ANLP 0x0146 #define AER 0x0148 +#define CSCR 0x014C /* This one has the link status */ +#define CSCR_LINK_STATUS (1 << 3) #define IDR_EEPROM 0x1202 @@ -58,6 +60,60 @@ #define RTL8150_REQ_GET_REGS 0x05 #define RTL8150_REQ_SET_REGS 0x05 + +/* Transmit status register errors */ +#define TSR_ECOL (1<<5) +#define TSR_LCOL (1<<4) +#define TSR_LOSS_CRS (1<<3) +#define TSR_JBR (1<<2) +#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) +/* Receive status register errors */ +#define RSR_CRC (1<<2) +#define RSR_FAE (1<<1) +#define RSR_ERRORS (RSR_CRC | RSR_FAE) + +/* Media status register definitions */ +#define MSR_DUPLEX (1<<4) +#define MSR_SPEED (1<<3) +#define MSR_LINK (1<<2) + +/* Interrupt pipe data */ +#define INT_TSR 0x00 +#define INT_RSR 0x01 +#define INT_MSR 0x02 +#define INT_WAKSR 0x03 +#define INT_TXOK_CNT 0x04 +#define INT_RXLOST_CNT 0x05 +#define INT_CRERR_CNT 0x06 +#define INT_COL_CNT 0x07 + +/* Transmit status register errors */ +#define TSR_ECOL (1<<5) +#define TSR_LCOL (1<<4) +#define TSR_LOSS_CRS (1<<3) +#define TSR_JBR (1<<2) +#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) +/* Receive status register errors */ +#define RSR_CRC (1<<2) +#define RSR_FAE (1<<1) +#define RSR_ERRORS (RSR_CRC | RSR_FAE) + +/* Media status register definitions */ +#define MSR_DUPLEX (1<<4) +#define MSR_SPEED (1<<3) +#define MSR_LINK (1<<2) + +/* Interrupt pipe data */ +#define INT_TSR 0x00 +#define INT_RSR 0x01 +#define INT_MSR 0x02 +#define INT_WAKSR 0x03 +#define INT_TXOK_CNT 0x04 +#define INT_RXLOST_CNT 0x05 +#define INT_CRERR_CNT 0x06 +#define INT_COL_CNT 0x07 + + #define RTL8150_MTU 1540 #define RTL8150_TX_TIMEOUT (HZ) #define RX_SKB_POOL_SIZE 4 @@ -71,9 +127,13 @@ /* Define these values to match your device */ #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_MELCO 0x0411 +#define VENDOR_ID_MICRONET 0x3980 +#define VENDOR_ID_LONGSHINE 0x07b8 #define PRODUCT_ID_RTL8150 0x8150 #define PRODUCT_ID_LUAKTX 0x0012 +#define PRODUCT_ID_LCS8138TX 0x401a +#define PRODUCT_ID_SP128AR 0x0003 #undef EEPROM_WRITE @@ -81,6 +141,8 @@ static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, + {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, + {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, {} }; @@ -368,6 +430,9 @@ if (!dev->rx_skb) goto resched; + /* protect against short packets (tell me why we got some?!?) */ + if (urb->actual_length < 4) + goto goon; res = urb->actual_length; rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4)); @@ -454,6 +519,7 @@ void intr_callback(struct urb *urb, struct pt_regs *regs) { rtl8150_t *dev; + __u8 *d; int status; dev = urb->context; @@ -472,7 +538,28 @@ goto resubmit; } - /* FIXME if this doesn't do anything, don't submit the urb! */ + d = urb->transfer_buffer; + if (d[0] & TSR_ERRORS) { + dev->stats.tx_errors++; + if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) + dev->stats.tx_aborted_errors++; + if (d[INT_TSR] & TSR_LCOL) + dev->stats.tx_window_errors++; + if (d[INT_TSR] & TSR_LOSS_CRS) + dev->stats.tx_carrier_errors++; + } + /* Report link status changes to the network stack */ + if ((d[INT_MSR] & MSR_LINK) == 0) { + if (netif_carrier_ok(dev->netdev)) { + netif_carrier_off(dev->netdev); + dbg("%s: LINK LOST\n", __func__); + } + } else { + if (!netif_carrier_ok(dev->netdev)) { + netif_carrier_on(dev->netdev); + dbg("%s: LINK CAME BACK\n", __func__); + } + } resubmit: status = usb_submit_urb (urb, SLAB_ATOMIC); @@ -482,6 +569,7 @@ dev->udev->devpath, status); } + /* ** ** network related part of the code @@ -538,7 +626,7 @@ warn("%s - device reset failed", __FUNCTION__); } /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ - rcr = 0x9e; /* bit7=1 attach Rx info at the end */ + rcr = 0x9e; dev->rx_creg = cpu_to_le16(rcr); tcr = 0xd8; cr = 0x0c; @@ -626,6 +714,19 @@ return 0; } + +static void set_carrier(struct net_device *netdev) +{ + rtl8150_t *dev = netdev->priv; + short tmp; + + get_registers(dev, CSCR, 2, &tmp); + if (tmp & CSCR_LINK_STATUS) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); +} + static int rtl8150_open(struct net_device *netdev) { rtl8150_t *dev; @@ -653,6 +754,7 @@ warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); netif_start_queue(netdev); enable_net_traffic(dev); + set_carrier(netdev); return res; } @@ -674,7 +776,7 @@ return res; } -static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr) +static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) { rtl8150_t *dev; int cmd; @@ -759,7 +861,7 @@ switch (cmd) { case SIOCETHTOOL: - res = rtl8150_ethtool_ioctl(netdev, (void __user *)rq->ifr_data); + res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = dev->phy; @@ -774,6 +876,7 @@ default: res = -EOPNOTSUPP; } + return res; } @@ -796,7 +899,6 @@ kfree(dev); return -ENOMEM; } - netdev = alloc_etherdev(0); if (!netdev) { kfree(dev->intr_buff); @@ -837,7 +939,6 @@ info("%s: rtl8150 is detected", netdev->name); usb_set_intfdata(intf, dev); - SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { err("couldn't register the device"); diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/net/usbnet.c Sun Mar 28 13:17:10 2004 @@ -3104,7 +3104,7 @@ } if (status < 0) - goto out2; + goto out1; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); @@ -3127,7 +3127,6 @@ out3: if (info->unbind) info->unbind (dev, udev); -out2: free_netdev(net); out1: kfree(dev); diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/serial/ftdi_sio.c Sun Mar 28 13:17:10 2004 @@ -435,7 +435,28 @@ { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -532,6 +553,11 @@ { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -789,8 +815,14 @@ static int set_rts(struct usb_serial_port *port, int high_or_low) { struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; + char *buf; unsigned ftdi_high_or_low; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; + if (high_or_low) { ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH; priv->last_dtr_rts |= TIOCM_RTS; @@ -798,20 +830,29 @@ ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW; priv->last_dtr_rts &= ~TIOCM_RTS; } - return(usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, ftdi_high_or_low, 0, - buf, 0, WDR_TIMEOUT)); + buf, 0, WDR_TIMEOUT); + + kfree(buf); + return rv; } static int set_dtr(struct usb_serial_port *port, int high_or_low) { struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; + char *buf; unsigned ftdi_high_or_low; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; + if (high_or_low) { ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH; priv->last_dtr_rts |= TIOCM_DTR; @@ -819,12 +860,15 @@ ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW; priv->last_dtr_rts &= ~TIOCM_DTR; } - return(usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, ftdi_high_or_low, 0, - buf, 0, WDR_TIMEOUT)); + buf, 0, WDR_TIMEOUT); + + kfree(buf); + return rv; } @@ -833,21 +877,29 @@ static int change_speed(struct usb_serial_port *port) { - char buf[1]; + char *buf; __u16 urb_value; __u16 urb_index; __u32 urb_index_value; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); - return (usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, urb_value, urb_index, - buf, 0, 100) < 0); + buf, 0, 100); + + kfree(buf); + return rv; } diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/serial/ftdi_sio.h Sun Mar 28 13:17:10 2004 @@ -160,7 +160,36 @@ #define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ #define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ #define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ -#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ +#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ + +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_E808_PID 0xE808 +#define FTDI_GUDEADS_E809_PID 0xE809 +#define FTDI_GUDEADS_E80A_PID 0xE80A +#define FTDI_GUDEADS_E80B_PID 0xE80B +#define FTDI_GUDEADS_E80C_PID 0xE80C +#define FTDI_GUDEADS_E80D_PID 0xE80D +#define FTDI_GUDEADS_E80E_PID 0xE80E +#define FTDI_GUDEADS_E80F_PID 0xE80F +#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ +#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ +#define FTDI_GUDEADS_E88A_PID 0xE88A +#define FTDI_GUDEADS_E88B_PID 0xE88B +#define FTDI_GUDEADS_E88C_PID 0xE88C +#define FTDI_GUDEADS_E88D_PID 0xE88D +#define FTDI_GUDEADS_E88E_PID 0xE88E +#define FTDI_GUDEADS_E88F_PID 0xE88F + +/* + * Linx Technologies product ids + */ +#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ +#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ +#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ +#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ +#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/serial/io_ti.c Sun Mar 28 13:17:10 2004 @@ -274,7 +274,7 @@ /** * TIReadDownloadMemory - Read edgeport memory from TI chip * @dev: usb device pointer - * @address: Device CPU address at which to read + * @start_address: Device CPU address at which to read * @length: Length of above data * @address_type: Can read both XDATA and I2C * @buffer: pointer to input data buffer diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c --- a/drivers/usb/serial/kobil_sct.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/serial/kobil_sct.c Sun Mar 28 13:17:10 2004 @@ -262,7 +262,7 @@ // allocate memory for transfer buffer transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { - return -1; + return -ENOMEM; } else { memset(transfer_buffer, 0, transfer_buffer_length); } @@ -274,7 +274,7 @@ if (!port->write_urb) { dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number); kfree(transfer_buffer); - return -1; + return -ENOMEM; } } @@ -282,7 +282,9 @@ port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); if (! port->write_urb->transfer_buffer) { kfree(transfer_buffer); - return -1; + usb_free_urb(port->write_urb); + port->write_urb = NULL; + return -ENOMEM; } // get hardware version diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/serial/whiteheat.c Sun Mar 28 13:17:10 2004 @@ -91,6 +91,10 @@ #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ #include "whiteheat.h" /* WhiteHEAT specific commands */ +#ifndef CMSPAR +#define CMSPAR 0 +#endif + /* * Version Information */ @@ -1128,7 +1132,6 @@ struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; struct whiteheat_private *info; - int timeout; __u8 *transfer_buffer; int retval = 0; unsigned long flags; @@ -1153,10 +1156,8 @@ } /* wait for the command to complete */ - timeout = COMMAND_TIMEOUT; - while (timeout && (command_info->command_finished == FALSE)) { - timeout = interruptible_sleep_on_timeout (&command_info->wait_command, timeout); - } + wait_event_interruptible_timeout(command_info->wait_command, + (command_info->command_finished != FALSE), COMMAND_TIMEOUT); spin_lock_irqsave(&command_info->lock, flags); diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/storage/transport.c Sun Mar 28 13:17:10 2004 @@ -256,8 +256,9 @@ endp |= USB_DIR_IN; result = usb_stor_control_msg(us, us->send_ctrl_pipe, - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, 3*HZ); + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, + NULL, 0, 3*HZ); /* reset the toggles and endpoint flags */ usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/storage/unusual_devs.h Sun Mar 28 13:17:10 2004 @@ -160,7 +160,7 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, "Panasonic", "LS-120 Camera", - US_SC_UFI, US_PR_CBI, NULL, 0), + US_SC_UFI, US_PR_DEVICE, NULL, 0), /* From Yukihiro Nakai, via zaitcev@yahoo.com. * This is needed for CB instead of CBI */ @@ -384,7 +384,7 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, "Lexar", "USB CF Reader", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Reported by Carlos Villegas @@ -392,15 +392,15 @@ * That is the only reason this entry is needed. */ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, - "SIIG", - "CompactFlash Card Reader", + "Genesys Logic", + "USB to IDE Card Reader", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Submitted Alexander Oltu */ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, - "", - "USB TO IDE", + "Genesys Logic", + "USB to IDE Optical", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), @@ -411,16 +411,9 @@ * * ST818 slim drives (rev 0.02) don't need special care. */ -UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001, - "EagleTec", - "External Hard Disk", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Reported by Henning Schild */ -UNUSUAL_DEV( 0x05e3, 0x0702, 0x0113, 0x0113, - "EagleTec", - "External Hard Disk", +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, + "Genesys Logic", + "USB to IDE Disk", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Sun Mar 28 13:17:10 2004 +++ b/drivers/usb/usb-skeleton.c Sun Mar 28 13:17:10 2004 @@ -516,7 +516,7 @@ dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); if (dev == NULL) { err ("Out of memory"); - goto error; + return -ENOMEM; } memset (dev, 0x00, sizeof (*dev)); diff -Nru a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h --- a/include/linux/usb_ch9.h Sun Mar 28 13:17:10 2004 +++ b/include/linux/usb_ch9.h Sun Mar 28 13:17:10 2004 @@ -68,6 +68,20 @@ #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (high speed only) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* dev may initiate HNP */ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* other RH port does */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + /** * struct usb_ctrlrequest - SETUP data for a USB device control request diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h --- a/include/linux/usb_gadget.h Sun Mar 28 13:17:10 2004 +++ b/include/linux/usb_gadget.h Sun Mar 28 13:17:10 2004 @@ -731,6 +731,15 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, void *buf, unsigned buflen, const struct usb_descriptor_header **desc); +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *) __init; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __init; + #endif /* __KERNEL__ */ #endif /* __LINUX_USB_GADGET_H */