bk://kernel.bkbits.net/gregkh/linux/usb-2.6 mochel@digitalimplant.org|ChangeSet|20040326192525|49444 mochel diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c --- a/drivers/isdn/hisax/hfc_usb.c Fri Mar 26 12:25:30 2004 +++ b/drivers/isdn/hisax/hfc_usb.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/isdn/hisax/st5481_b.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/isdn/hisax/st5481_d.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/isdn/hisax/st5481_init.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/isdn/hisax/st5481_usb.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/Makefile Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/config.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/devio.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/hcd-pci.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/hcd.c Fri Mar 26 12:25:30 2004 @@ -42,6 +42,8 @@ #include #include + +#include "usb.h" #include "hcd.h" @@ -678,8 +680,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 +808,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/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/hub.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/message.c Fri Mar 26 12:25:30 2004 @@ -935,7 +935,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; } @@ -953,8 +954,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; @@ -1233,18 +1235,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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/usb.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/core/usb.h Fri Mar 26 12:25:30 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/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/gadget/Makefile Fri Mar 26 12:25:30 2004 @@ -8,7 +8,7 @@ # # USB gadget drivers # -g_zero-objs := zero.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 g_serial-objs := serial.o usbstring.o gadgetfs-objs := inode.o usbstring.o 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 Fri Mar 26 12:25:30 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/usbstring.c b/drivers/usb/gadget/usbstring.c --- a/drivers/usb/gadget/usbstring.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/gadget/usbstring.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/gadget/zero.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/host/ehci-hcd.c Fri Mar 26 12:25:30 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/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/host/uhci-debug.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/host/uhci-hcd.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/host/uhci-hcd.h Fri Mar 26 12:25:30 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/ati_remote.c b/drivers/usb/input/ati_remote.c --- a/drivers/usb/input/ati_remote.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/input/ati_remote.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/input/hiddev.c Fri Mar 26 12:25:30 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/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/media/vicam.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/media/w9968cf.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/misc/Kconfig Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/misc/Makefile Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 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/net/Kconfig b/drivers/usb/net/Kconfig --- a/drivers/usb/net/Kconfig Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/net/Kconfig Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/net/rtl8150.c Fri Mar 26 12:25:30 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/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/serial/ftdi_sio.c Fri Mar 26 12:25:30 2004 @@ -436,6 +436,7 @@ { 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_ELV_UO100_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_889_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -789,8 +790,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 +805,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 +835,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 +852,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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/serial/ftdi_sio.h Fri Mar 26 12:25:30 2004 @@ -162,6 +162,11 @@ #define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ #define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_889_PID 0xe889 /* USB RS323 OptoBridge */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/serial/io_ti.c Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/serial/kobil_sct.c Fri Mar 26 12:25:30 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/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/storage/unusual_devs.h Fri Mar 26 12:25:30 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 Fri Mar 26 12:25:30 2004 +++ b/drivers/usb/usb-skeleton.c Fri Mar 26 12:25:30 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_gadget.h b/include/linux/usb_gadget.h --- a/include/linux/usb_gadget.h Fri Mar 26 12:25:30 2004 +++ b/include/linux/usb_gadget.h Fri Mar 26 12:25:30 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 */