diff options
Diffstat (limited to 'drivers/usb')
133 files changed, 9119 insertions, 2292 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 73f62caa860..2642b8a11e0 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -6,9 +6,26 @@ config USB_ARCH_HAS_OHCI bool +config USB_OHCI_BIG_ENDIAN_DESC + bool + +config USB_OHCI_BIG_ENDIAN_MMIO + bool + +config USB_OHCI_LITTLE_ENDIAN + bool + default n if STB03xxx || PPC_MPC52xx + default y + config USB_ARCH_HAS_EHCI bool +config USB_EHCI_BIG_ENDIAN_MMIO + bool + +config USB_EHCI_BIG_ENDIAN_DESC + bool + config USB_ARCH_HAS_XHCI bool diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 2b3132ede23..70d7c5b92c3 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_USB_ISP1760_HCD) += host/ obj-$(CONFIG_USB_IMX21_HCD) += host/ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ obj-$(CONFIG_USB_FUSBH200_HCD) += host/ +obj-$(CONFIG_USB_FOTG210_HCD) += host/ obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile index a5d792ec3ad..ac278946b06 100644 --- a/drivers/usb/atm/Makefile +++ b/drivers/usb/atm/Makefile @@ -1,9 +1,6 @@ # # Makefile for USB ATM/xDSL drivers # - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - obj-$(CONFIG_USB_CXACRU) += cxacru.o obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o obj-$(CONFIG_USB_UEAGLEATM) += ueagle-atm.o diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 807627b36cc..69461d65397 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -888,7 +888,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, usb_fill_int_urb(instance->int_urb, usb_dev, usb_rcvintpipe(usb_dev, ENDPOINT_INT), instance->int_data, sizeof(instance->int_data), - speedtch_handle_int, instance, 50); + speedtch_handle_int, instance, 16); else usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__); diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 5e0d33a7da5..25a7bfcf666 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -311,8 +311,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4); u8 pti = ((source[3] & 0xe) >> 1); - vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); - if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) { instance->cached_vpi = vpi; instance->cached_vci = vci; @@ -344,7 +342,6 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char __func__, sarb->len, vcc); /* discard cells already received */ skb_trim(sarb, 0); - UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end); } memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); @@ -437,8 +434,6 @@ static void usbatm_extract_cells(struct usbatm_data *instance, unsigned char *cell_buf = instance->cell_buf; unsigned int space_left = stride - buf_usage; - UDSL_ASSERT(instance, buf_usage <= stride); - if (avail_data >= space_left) { /* add new data and process cell */ memcpy(cell_buf + buf_usage, source, space_left); @@ -479,10 +474,6 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance, unsigned int bytes_written; unsigned int stride = instance->tx_channel.stride; - vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u", - __func__, skb->len, avail_space); - UDSL_ASSERT(instance, !(avail_space % stride)); - for (bytes_written = 0; bytes_written < avail_space && ctrl->len; bytes_written += stride, target += stride) { unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD); @@ -553,8 +544,6 @@ static void usbatm_rx_process(unsigned long data) if (!urb->iso_frame_desc[i].status) { unsigned int actual_length = urb->iso_frame_desc[i].actual_length; - UDSL_ASSERT(instance, actual_length <= packet_size); - if (!merge_length) merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; merge_length += actual_length; @@ -645,7 +634,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance, { struct sk_buff *skb, *n; - atm_dbg(instance, "%s entered\n", __func__); spin_lock_irq(&instance->sndqueue.lock); skb_queue_walk_safe(&instance->sndqueue, skb, n) { if (UDSL_SKB(skb)->atm.vcc == vcc) { @@ -663,7 +651,6 @@ static void usbatm_cancel_send(struct usbatm_data *instance, usbatm_pop(vcc, skb); } tasklet_enable(&instance->tx_channel.tasklet); - atm_dbg(instance, "%s done\n", __func__); } static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) @@ -674,16 +661,13 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) /* racy disconnection check - fine */ if (!instance || instance->disconnected) { -#ifdef DEBUG +#ifdef VERBOSE_DEBUG printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance"); #endif err = -ENODEV; goto fail; } - vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__, - skb, skb->len); - if (vcc->qos.aal != ATM_AAL5) { atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); err = -EINVAL; @@ -723,8 +707,6 @@ static void usbatm_destroy_instance(struct kref *kref) { struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount); - usb_dbg(instance, "%s\n", __func__); - tasklet_kill(&instance->rx_channel.tasklet); tasklet_kill(&instance->tx_channel.tasklet); usb_put_dev(instance->usb_dev); @@ -733,15 +715,11 @@ static void usbatm_destroy_instance(struct kref *kref) static void usbatm_get_instance(struct usbatm_data *instance) { - usb_dbg(instance, "%s\n", __func__); - kref_get(&instance->refcount); } static void usbatm_put_instance(struct usbatm_data *instance) { - usb_dbg(instance, "%s\n", __func__); - kref_put(&instance->refcount, usbatm_destroy_instance); } @@ -757,7 +735,6 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev) if (!instance) return; - usb_dbg(instance, "%s\n", __func__); atm_dev->dev_data = NULL; /* catch bugs */ usbatm_put_instance(instance); /* taken in usbatm_atm_init */ } @@ -813,8 +790,6 @@ static int usbatm_atm_open(struct atm_vcc *vcc) if (!instance) return -ENODEV; - atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci); - /* only support AAL5 */ if ((vcc->qos.aal != ATM_AAL5)) { atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); @@ -891,11 +866,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc) if (!instance || !vcc_data) return; - atm_dbg(instance, "%s entered\n", __func__); - - atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n", - __func__, vcc_data, vcc_data->vpi, vcc_data->vci); - usbatm_cancel_send(instance, vcc); mutex_lock(&instance->serialize); /* vs self, usbatm_atm_open, usbatm_usb_disconnect */ @@ -922,8 +892,6 @@ static void usbatm_atm_close(struct atm_vcc *vcc) clear_bit(ATM_VF_ADDR, &vcc->flags); mutex_unlock(&instance->serialize); - - atm_dbg(instance, "%s successful\n", __func__); } static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, @@ -1060,12 +1028,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, int i, length; unsigned int maxpacket, num_packets; - dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n", - __func__, driver->driver_name, - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - intf->altsetting->desc.bInterfaceNumber); - /* instance init */ instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); if (!instance) { @@ -1158,14 +1120,13 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, instance->rx_channel.buf_size = num_packets * maxpacket; instance->rx_channel.packet_size = maxpacket; -#ifdef DEBUG for (i = 0; i < 2; i++) { struct usbatm_channel *channel = i ? &instance->tx_channel : &instance->rx_channel; - dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel); + dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", + __func__, channel->buf_size, i ? "tx" : "rx", channel); } -#endif /* initialize urbs */ @@ -1176,8 +1137,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, struct urb *urb; unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0; - UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint)); - urb = usb_alloc_urb(iso_packets, GFP_KERNEL); if (!urb) { dev_err(dev, "%s: no memory for urb %d!\n", __func__, i); @@ -1266,8 +1225,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf) struct usbatm_vcc_data *vcc_data; int i; - dev_dbg(dev, "%s entered\n", __func__); - if (!instance) { dev_dbg(dev, "%s: NULL instance!\n", __func__); return; diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h index 5fc48940521..5651231a743 100644 --- a/drivers/usb/atm/usbatm.h +++ b/drivers/usb/atm/usbatm.h @@ -39,31 +39,14 @@ #define VERBOSE_DEBUG */ -#ifdef DEBUG -#define UDSL_ASSERT(instance, x) BUG_ON(!(x)) -#else -#define UDSL_ASSERT(instance, x) \ - do { \ - if (!(x)) \ - dev_warn(&(instance)->usb_intf->dev, \ - "failed assertion '%s' at line %d", \ - __stringify(x), __LINE__); \ - } while (0) -#endif - #define usb_err(instance, format, arg...) \ dev_err(&(instance)->usb_intf->dev , format , ## arg) #define usb_info(instance, format, arg...) \ dev_info(&(instance)->usb_intf->dev , format , ## arg) #define usb_warn(instance, format, arg...) \ dev_warn(&(instance)->usb_intf->dev , format , ## arg) -#ifdef DEBUG -#define usb_dbg(instance, format, arg...) \ - dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg) -#else #define usb_dbg(instance, format, arg...) \ - do {} while (0) -#endif + dev_dbg(&(instance)->usb_intf->dev , format , ## arg) /* FIXME: move to dev_* once ATM is driver model aware */ #define atm_printk(level, instance, format, arg...) \ @@ -76,18 +59,12 @@ atm_printk(KERN_INFO, instance , format , ## arg) #define atm_warn(instance, format, arg...) \ atm_printk(KERN_WARNING, instance , format , ## arg) -#ifdef DEBUG -#define atm_dbg(instance, format, arg...) \ - atm_printk(KERN_DEBUG, instance , format , ## arg) -#define atm_rldbg(instance, format, arg...) \ +#define atm_dbg(instance, format, arg...) \ + dynamic_pr_debug("ATM dev %d: " format , \ + (instance)->atm_dev->number , ## arg) +#define atm_rldbg(instance, format, arg...) \ if (printk_ratelimit()) \ - atm_printk(KERN_DEBUG, instance , format , ## arg) -#else -#define atm_dbg(instance, format, arg...) \ - do {} while (0) -#define atm_rldbg(instance, format, arg...) \ - do {} while (0) -#endif + atm_dbg(instance , format , ## arg) /* flags, set by mini-driver in bind() */ diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c index fe815ecd557..8db3380c332 100644 --- a/drivers/usb/c67x00/c67x00-drv.c +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -131,7 +131,7 @@ static int c67x00_drv_probe(struct platform_device *pdev) if (!res2) return -ENODEV; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) return -ENODEV; @@ -154,7 +154,7 @@ static int c67x00_drv_probe(struct platform_device *pdev) spin_lock_init(&c67x00->hpi.lock); c67x00->hpi.regstep = pdata->hpi_regstep; - c67x00->pdata = pdev->dev.platform_data; + c67x00->pdata = dev_get_platdata(&pdev->dev); c67x00->pdev = pdev; c67x00_ll_init(c67x00); diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index eb2aa2e5a84..d1bd8ef1f9c 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -12,7 +12,7 @@ if USB_CHIPIDEA config USB_CHIPIDEA_UDC bool "ChipIdea device controller" - depends on USB_GADGET=y || USB_CHIPIDEA=m + depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m) help Say Y here to enable device controller functionality of the ChipIdea driver. @@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC config USB_CHIPIDEA_HOST bool "ChipIdea host controller" depends on USB=y - depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m + depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m) select USB_EHCI_ROOT_HUB_TT help Say Y here to enable host controller functionality of the diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa0261220..1b23e354f9f 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -50,7 +50,7 @@ #define PORTSC_PTC (0x0FUL << 16) /* PTS and PTW for non lpm version only */ #define PORTSC_PTS(d) \ - ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0)) + (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0)) #define PORTSC_PTW BIT(28) #define PORTSC_STS BIT(29) @@ -59,7 +59,7 @@ #define DEVLC_PSPD_HS (0x02UL << 25) #define DEVLC_PTW BIT(27) #define DEVLC_STS BIT(28) -#define DEVLC_PTS(d) (((d) & 0x7) << 29) +#define DEVLC_PTS(d) (u32)(((d) & 0x7) << 29) /* Encoding for DEVLC_PTS and PORTSC_PTS */ #define PTS_UTMI 0 diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 9f49bfe4c6f..3e7560f004f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1295,7 +1295,7 @@ skip_countries: usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, /* works around buggy devices */ - epctrl->bInterval ? epctrl->bInterval : 0xff); + epctrl->bInterval ? epctrl->bInterval : 16); acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; acm->ctrlurb->transfer_dma = acm->ctrl_dma; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8a230f0ef77..d3318a0df8e 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -209,6 +209,7 @@ skip_error: static void wdm_int_callback(struct urb *urb) { int rv = 0; + int responding; int status = urb->status; struct wdm_device *desc; struct usb_cdc_notification *dr; @@ -262,8 +263,8 @@ static void wdm_int_callback(struct urb *urb) spin_lock(&desc->iuspin); clear_bit(WDM_READ, &desc->flags); - set_bit(WDM_RESPONDING, &desc->flags); - if (!test_bit(WDM_DISCONNECTING, &desc->flags) + responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); + if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags) && !test_bit(WDM_SUSPENDING, &desc->flags)) { rv = usb_submit_urb(desc->response, GFP_ATOMIC); dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", @@ -685,16 +686,20 @@ static void wdm_rxwork(struct work_struct *work) { struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); unsigned long flags; - int rv; + int rv = 0; + int responding; spin_lock_irqsave(&desc->iuspin, flags); if (test_bit(WDM_DISCONNECTING, &desc->flags)) { spin_unlock_irqrestore(&desc->iuspin, flags); } else { + responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); spin_unlock_irqrestore(&desc->iuspin, flags); - rv = usb_submit_urb(desc->response, GFP_KERNEL); + if (!responding) + rv = usb_submit_urb(desc->response, GFP_KERNEL); if (rv < 0 && rv != -EPERM) { spin_lock_irqsave(&desc->iuspin, flags); + clear_bit(WDM_RESPONDING, &desc->flags); if (!test_bit(WDM_DISCONNECTING, &desc->flags)) schedule_work(&desc->rxwork); spin_unlock_irqrestore(&desc->iuspin, flags); diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 609dbc2f715..60dd8918aeb 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -19,6 +19,8 @@ * http://www.gnu.org/copyleft/gpl.html. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> @@ -119,7 +121,6 @@ static void usbtmc_delete(struct kref *kref) struct usbtmc_device_data *data = to_usbtmc_data(kref); usb_put_dev(data->usb_dev); - kfree(data); } static int usbtmc_open(struct inode *inode, struct file *filp) @@ -130,10 +131,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp) intf = usb_find_interface(&usbtmc_driver, iminor(inode)); if (!intf) { - printk(KERN_ERR KBUILD_MODNAME - ": can not find device for minor %d", iminor(inode)); - retval = -ENODEV; - goto exit; + pr_err("can not find device for minor %d", iminor(inode)); + return -ENODEV; } data = usb_get_intfdata(intf); @@ -142,7 +141,6 @@ static int usbtmc_open(struct inode *inode, struct file *filp) /* Store pointer in file structure's private data field */ filp->private_data = data; -exit: return retval; } @@ -394,12 +392,12 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t */ buffer[0] = 2; buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); + buffer[2] = ~data->bTag; buffer[3] = 0; /* Reserved */ - buffer[4] = (transfer_size) & 255; - buffer[5] = ((transfer_size) >> 8) & 255; - buffer[6] = ((transfer_size) >> 16) & 255; - buffer[7] = ((transfer_size) >> 24) & 255; + buffer[4] = transfer_size >> 0; + buffer[5] = transfer_size >> 8; + buffer[6] = transfer_size >> 16; + buffer[7] = transfer_size >> 24; buffer[8] = data->TermCharEnabled * 2; /* Use term character? */ buffer[9] = data->TermChar; @@ -418,7 +416,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t /* Increment bTag -- and increment again if zero */ data->bTag++; if (!data->bTag) - (data->bTag)++; + data->bTag++; if (retval < 0) { dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval); @@ -473,7 +471,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, done = 0; while (remaining > 0) { - if (!(data->rigol_quirk)) { + if (!data->rigol_quirk) { dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count); if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3) @@ -510,7 +508,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, } /* Parse header in first packet */ - if ((done == 0) || (!(data->rigol_quirk))) { + if ((done == 0) || !data->rigol_quirk) { /* Sanity checks for the header */ if (actual < USBTMC_HEADER_SIZE) { dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE); @@ -554,14 +552,14 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, if (remaining > n_characters) remaining = n_characters; /* Remove padding if it exists */ - if (actual > remaining) + if (actual > remaining) actual = remaining; } else { if (this_part > n_characters) this_part = n_characters; /* Remove padding if it exists */ - if (actual > this_part) + if (actual > this_part) actual = this_part; } @@ -570,7 +568,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, remaining -= actual; /* Terminate if end-of-message bit received from device */ - if ((buffer[8] & 0x01) && (actual >= n_characters)) + if ((buffer[8] & 0x01) && (actual >= n_characters)) remaining = 0; dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done); @@ -585,7 +583,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, done += actual; } else { - if (actual > remaining) + if (actual > remaining) actual = remaining; remaining -= actual; @@ -651,12 +649,12 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, /* Setup IO buffer for DEV_DEP_MSG_OUT message */ buffer[0] = 1; buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); + buffer[2] = ~data->bTag; buffer[3] = 0; /* Reserved */ - buffer[4] = this_part & 255; - buffer[5] = (this_part >> 8) & 255; - buffer[6] = (this_part >> 16) & 255; - buffer[7] = (this_part >> 24) & 255; + buffer[4] = this_part >> 0; + buffer[5] = this_part >> 8; + buffer[6] = this_part >> 16; + buffer[7] = this_part >> 24; /* buffer[8] is set above... */ buffer[9] = 0; /* Reserved */ buffer[10] = 0; /* Reserved */ @@ -1102,7 +1100,7 @@ static int usbtmc_probe(struct usb_interface *intf, dev_dbg(&intf->dev, "%s called\n", __func__); - data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL); + data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(&intf->dev, "Unable to allocate kernel memory\n"); return -ENOMEM; diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b0585e623ba..23559746be9 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -43,10 +43,11 @@ static const size_t pool_max[HCD_BUFFER_POOLS] = { * * Call this as part of initializing a host controller that uses the dma * memory allocators. It initializes some pools of dma-coherent memory that - * will be shared by all drivers using that controller, or returns a negative - * errno value on error. + * will be shared by all drivers using that controller. * * Call hcd_buffer_destroy() to clean up after using those pools. + * + * Return: 0 if successful. A negative errno value otherwise. */ int hcd_buffer_create(struct usb_hcd *hcd) { diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 7199adccf44..a6b2cabe793 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -424,7 +424,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); if (config->desc.bDescriptorType != USB_DT_CONFIG || - config->desc.bLength < USB_DT_CONFIG_SIZE) { + config->desc.bLength < USB_DT_CONFIG_SIZE || + config->desc.bLength > size) { dev_err(ddev, "invalid descriptor for config index %d: " "type = 0x%X, length = %d\n", cfgidx, config->desc.bDescriptorType, config->desc.bLength); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 05986507b58..737e3c19967 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -725,15 +725,15 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, /* * check for the special corner case 'get_device_id' in the printer - * class specification, where wIndex is (interface << 8 | altsetting) - * instead of just interface + * class specification, which we always want to allow as it is used + * to query things like ink level, etc. */ if (requesttype == 0xa1 && request == 0) { alt_setting = usb_find_alt_setting(ps->dev->actconfig, index >> 8, index & 0xff); if (alt_setting && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER) - index >>= 8; + return 0; } index &= 0xff; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7609ac4aed1..124bcc50b0b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -117,6 +117,8 @@ static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id); * @count: input size * * Removes a dynamic usb device ID from this driver. + * + * Return: @count on success. A negative error code otherwise. */ static ssize_t store_remove_id(struct device_driver *driver, const char *buf, size_t count) @@ -457,6 +459,8 @@ static int usb_unbind_interface(struct device *dev) * Callers must own the device lock, so driver probe() entries don't need * extra locking, but other call contexts may need to explicitly claim that * lock. + * + * Return: 0 on success. */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) @@ -658,6 +662,8 @@ EXPORT_SYMBOL_GPL(usb_match_one_id); * These device tables are exported with MODULE_DEVICE_TABLE, through * modutils, to support the driver loading functionality of USB hotplugging. * + * Return: The first matching usb_device_id, or %NULL. + * * What Matches: * * The "match_flags" element in a usb_device_id controls which @@ -823,7 +829,8 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) * Registers a USB device driver with the USB core. The list of * unattached devices will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized devices. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. */ int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) @@ -879,7 +886,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * Registers a USB interface driver with the USB core. The list of * unattached interfaces will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized interfaces. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. * * NOTE: if you want your driver to use the USB major number, you must call * usb_register_dev() to enable that functionality. This function no longer @@ -1213,6 +1221,8 @@ done: * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 if the suspend succeeded. */ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { @@ -1294,6 +1304,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 on success. */ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) { @@ -1491,6 +1503,8 @@ void usb_autosuspend_device(struct usb_device *udev) * The caller must hold @udev's device lock. * * This routine can run only in process context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autoresume_device(struct usb_device *udev) { @@ -1600,6 +1614,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); * However if the autoresume fails then the counter is re-decremented. * * This routine can run only in process context. + * + * Return: 0 on success. */ int usb_autopm_get_interface(struct usb_interface *intf) { @@ -1633,6 +1649,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface); * resumed. * * This routine can run in atomic context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autopm_get_interface_async(struct usb_interface *intf) { diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 68cc6532e74..f13a289a074 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/slab.h> -#include <linux/idr.h> #include <linux/usb.h> #include "usb.h" diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 6a4c40766f0..7421888087a 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -153,7 +153,7 @@ void usb_major_cleanup(void) * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. * - * Returns -EINVAL if something bad happens with trying to register a + * Return: -EINVAL if something bad happens with trying to register a * device, and 0 on success. */ int usb_register_dev(struct usb_interface *intf, diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index caeb8d6d39f..b9d3c43e385 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -171,6 +171,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, * through the hotplug entry's driver_data. * * Store this function in the HCD's struct pci_driver as probe(). + * + * Return: 0 if successful. */ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 014dc996b4f..5aa1d133eaf 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -378,9 +378,10 @@ MODULE_PARM_DESC(authorized_default, * @buf: Buffer for USB string descriptor (header + UTF-16LE) * @len: Length (in bytes; may be odd) of descriptor buffer. * - * The return value is the number of bytes filled in: 2 + 2*strlen(s) or - * buflen, whichever is less. + * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len, + * whichever is less. * + * Note: * USB String descriptors can contain at most 126 characters; input * strings longer than that are truncated. */ @@ -416,7 +417,8 @@ ascii2desc(char const *s, u8 *buf, unsigned len) * * Produces either a manufacturer, product or serial number string for the * virtual root hub device. - * Returns the number of bytes filled in: the length of the descriptor or + * + * Return: The number of bytes filled in: the length of the descriptor or * of the provided buffer, whichever is less. */ static unsigned @@ -694,15 +696,7 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); usb_hcd_unlink_urb_from_ep(hcd, urb); - - /* This peculiar use of spinlocks echoes what real HC drivers do. - * Avoiding calls to local_irq_disable/enable makes the code - * RT-friendly. - */ - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); - spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -742,9 +736,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, 0); - spin_lock(&hcd_root_hub_lock); } else { length = 0; set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); @@ -834,10 +826,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (urb == hcd->status_urb) { hcd->status_urb = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); } } done: @@ -938,6 +927,8 @@ static void usb_bus_init (struct usb_bus *bus) * * Assigns a bus number, and links the controller into usbcore data * structures so that it can be seen by scanning the bus list. + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_register_bus(struct usb_bus *bus) { @@ -1002,6 +993,8 @@ static void usb_deregister_bus (struct usb_bus *bus) * the device properly in the device tree and then calls usb_new_device() * to register the usb device. It also assigns the root hub's USB address * (always 1). + * + * Return: 0 if successful. A negative error code otherwise. */ static int register_root_hub(struct usb_hcd *hcd) { @@ -1108,7 +1101,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume); * @isoc: true for isochronous transactions, false for interrupt ones * @bytecount: how many bytes in the transaction. * - * Returns approximate bus time in nanoseconds for a periodic transaction. + * Return: Approximate bus time in nanoseconds for a periodic transaction. + * + * Note: * See USB 2.0 spec section 5.11.3; only periodic transfers need to be * scheduled in software, this function is only used for such scheduling. */ @@ -1166,7 +1161,7 @@ EXPORT_SYMBOL_GPL(usb_calc_bus_time); * be disabled. The actions carried out here are required for URB * submission, as well as for endpoint shutdown and for usb_kill_urb. * - * Returns 0 for no error, otherwise a negative error code (in which case + * Return: 0 for no error, otherwise a negative error code (in which case * the enqueue() method must fail). If no error occurs but enqueue() fails * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing * the private spinlock and returning. @@ -1221,7 +1216,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); * be disabled. The actions carried out here are required for making * sure than an unlink is valid. * - * Returns 0 for no error, otherwise a negative error code (in which case + * Return: 0 for no error, otherwise a negative error code (in which case * the dequeue() method must fail). The possible error codes are: * * -EIDRM: @urb was not submitted or has already completed. @@ -1648,6 +1643,72 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) /*-------------------------------------------------------------------------*/ +static void __usb_hcd_giveback_urb(struct urb *urb) +{ + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + int status = urb->unlinked; + unsigned long flags; + + urb->hcpriv = NULL; + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !status)) + status = -EREMOTEIO; + + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb, status); + usb_unanchor_urb(urb); + + /* pass ownership to the completion handler */ + urb->status = status; + + /* + * We disable local IRQs here avoid possible deadlock because + * drivers may call spin_lock() to hold lock which might be + * acquired in one hard interrupt handler. + * + * The local_irq_save()/local_irq_restore() around complete() + * will be removed if current USB drivers have been cleaned up + * and no one may trigger the above deadlock situation when + * running complete() in tasklet. + */ + local_irq_save(flags); + urb->complete(urb); + local_irq_restore(flags); + + atomic_dec(&urb->use_count); + if (unlikely(atomic_read(&urb->reject))) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); +} + +static void usb_giveback_urb_bh(unsigned long param) +{ + struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param; + struct list_head local_list; + + spin_lock_irq(&bh->lock); + bh->running = true; + restart: + list_replace_init(&bh->head, &local_list); + spin_unlock_irq(&bh->lock); + + while (!list_empty(&local_list)) { + struct urb *urb; + + urb = list_entry(local_list.next, struct urb, urb_list); + list_del_init(&urb->urb_list); + __usb_hcd_giveback_urb(urb); + } + + /* check if there are new URBs to giveback */ + spin_lock_irq(&bh->lock); + if (!list_empty(&bh->head)) + goto restart; + bh->running = false; + spin_unlock_irq(&bh->lock); +} + /** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB @@ -1667,25 +1728,37 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - urb->hcpriv = NULL; - if (unlikely(urb->unlinked)) - status = urb->unlinked; - else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < urb->transfer_buffer_length && - !status)) - status = -EREMOTEIO; + struct giveback_urb_bh *bh; + bool running, high_prio_bh; - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, status); - usb_unanchor_urb(urb); + /* pass status to tasklet via unlinked */ + if (likely(!urb->unlinked)) + urb->unlinked = status; - /* pass ownership to the completion handler */ - urb->status = status; - urb->complete (urb); - atomic_dec (&urb->use_count); - if (unlikely(atomic_read(&urb->reject))) - wake_up (&usb_kill_urb_queue); - usb_put_urb (urb); + if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) { + __usb_hcd_giveback_urb(urb); + return; + } + + if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) { + bh = &hcd->high_prio_bh; + high_prio_bh = true; + } else { + bh = &hcd->low_prio_bh; + high_prio_bh = false; + } + + spin_lock(&bh->lock); + list_add_tail(&urb->urb_list, &bh->head); + running = bh->running; + spin_unlock(&bh->lock); + + if (running) + ; + else if (high_prio_bh) + tasklet_hi_schedule(&bh->bh); + else + tasklet_schedule(&bh->bh); } EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); @@ -1784,7 +1857,7 @@ rescan: * pass in the current alternate interface setting in cur_alt, * and pass in the new alternate interface setting in new_alt. * - * Returns an error if the requested bandwidth change exceeds the + * Return: An error if the requested bandwidth change exceeds the * bus bandwidth or host controller internal resources. */ int usb_hcd_alloc_bandwidth(struct usb_device *udev, @@ -1954,9 +2027,12 @@ void usb_hcd_reset_endpoint(struct usb_device *udev, * @num_streams: number of streams to allocate. * @mem_flags: flags hcd should use to allocate memory. * - * Sets up a group of bulk endpoints to have num_streams stream IDs available. + * Sets up a group of bulk endpoints to have @num_streams stream IDs available. * Drivers may queue multiple transfers to different stream IDs, which may * complete in a different order than they were queued. + * + * Return: On success, the number of allocated streams. On failure, a negative + * error code. */ int usb_alloc_streams(struct usb_interface *interface, struct usb_host_endpoint **eps, unsigned int num_eps, @@ -2201,6 +2277,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); * khubd identifying and possibly configuring the device. * This is needed by OTG controller drivers, where it helps meet * HNP protocol timing requirements for starting a port reset. + * + * Return: 0 if successful. */ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) { @@ -2235,6 +2313,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. + * + * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise. */ irqreturn_t usb_hcd_irq (int irq, void *__hcd) { @@ -2307,6 +2387,14 @@ EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ +static void init_giveback_urb_bh(struct giveback_urb_bh *bh) +{ + + spin_lock_init(&bh->lock); + INIT_LIST_HEAD(&bh->head); + tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh); +} + /** * usb_create_shared_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd @@ -2320,7 +2408,8 @@ EXPORT_SYMBOL_GPL (usb_hc_died); * HC driver's private data. Initialize the generic members of the * hcd structure. * - * If memory is unavailable, returns NULL. + * Return: On success, a pointer to the created and initialized HCD structure. + * On failure (e.g. if memory is unavailable), %NULL. */ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, @@ -2384,7 +2473,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd); * HC driver's private data. Initialize the generic members of the * hcd structure. * - * If memory is unavailable, returns NULL. + * Return: On success, a pointer to the created and initialized HCD + * structure. On failure (e.g. if memory is unavailable), %NULL. */ struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name) @@ -2563,7 +2653,7 @@ int usb_add_hcd(struct usb_hcd *hcd, * should already have been reset (and boot firmware kicked off etc). */ if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup\n"); + dev_err(hcd->self.controller, "can't setup: %d\n", retval); goto err_hcd_driver_setup; } hcd->rh_pollable = 1; @@ -2573,6 +2663,10 @@ int usb_add_hcd(struct usb_hcd *hcd, && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + /* initialize tasklets */ + init_giveback_urb_bh(&hcd->high_prio_bh); + init_giveback_urb_bh(&hcd->low_prio_bh); + /* enable irqs just before we start the controller, * if the BIOS provides legacy PCI irqs. */ @@ -2681,6 +2775,16 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_disconnect(&rhdev); /* Sets rhdev to NULL */ mutex_unlock(&usb_bus_list_lock); + /* + * tasklet_kill() isn't needed here because: + * - driver's disconnect() called from usb_disconnect() should + * make sure its URBs are completed during the disconnect() + * callback + * + * - it is too late to run complete() here since driver may have + * been removed already now + */ + /* Prevent any more root-hub status calls from the timer. * The HCD might still restart the timer (if a port status change * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4a8a1d68002..5d6d28a76e0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -734,6 +734,8 @@ static void hub_tt_work(struct work_struct *work) * * call this function to control port's power via setting or * clearing the port's PORT_POWER feature. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, int port1, bool set) @@ -762,6 +764,8 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, * * It may not be possible for that hub to handle additional full (or low) * speed transactions until that state is fully cleared out. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_hub_clear_tt_buffer(struct urb *urb) { @@ -964,6 +968,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) * see that the device has been disconnected. When the device is * physically unplugged and something is plugged in, the events will * be received and processed normally. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_remove_device(struct usb_device *udev) { @@ -1464,11 +1470,10 @@ static int hub_configure(struct usb_hub *hub, * and battery-powered root hubs (may provide just 8 mA). */ ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus); - if (ret < 2) { + if (ret) { message = "can't get hub status"; goto fail; } - le16_to_cpus(&hubstatus); hcd = bus_to_hcd(hdev->bus); if (hdev == hdev->bus->root_hub) { if (hcd->power_budget > 0) @@ -2116,6 +2121,8 @@ static inline void announce_device(struct usb_device *udev) { } * @udev: newly addressed device (in ADDRESS state) * * Finish enumeration for On-The-Go devices + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_enumerate_device_otg(struct usb_device *udev) { @@ -2198,6 +2205,8 @@ fail: * If the device is WUSB and not authorized, we don't attempt to read * the string descriptors, as they will be errored out by the device * until it has been authorized. + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_enumerate_device(struct usb_device *udev) { @@ -2278,13 +2287,14 @@ static void set_usb_port_removable(struct usb_device *udev) * udev has already been installed, but udev is not yet visible through * sysfs or other filesystem code. * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * * This call is synchronous, and may not be used in an interrupt context. * * Only the hub driver or root-hub registrar should ever call this. + * + * Return: Whether the device is configured properly or not. Zero if the + * interface was registered with the driver core; else a negative errno + * value. + * */ int usb_new_device(struct usb_device *udev) { @@ -2392,6 +2402,8 @@ fail: * * We share a lock (that we have) with device_del(), so we need to * defer its call. + * + * Return: 0. */ int usb_deauthorize_device(struct usb_device *usb_dev) { @@ -2838,20 +2850,51 @@ void usb_enable_ltm(struct usb_device *udev) } EXPORT_SYMBOL_GPL(usb_enable_ltm); -#ifdef CONFIG_PM /* - * usb_disable_function_remotewakeup - disable usb3.0 - * device's function remote wakeup + * usb_enable_remote_wakeup - enable remote wakeup for a device * @udev: target device * - * Assume there's only one function on the USB 3.0 - * device and disable remote wake for the first - * interface. FIXME if the interface association - * descriptor shows there's more than one function. + * For USB-2 devices: Set the device's remote wakeup feature. + * + * For USB-3 devices: Assume there's only one function on the device and + * enable remote wake for the first interface. FIXME if the interface + * association descriptor shows there's more than one function. */ -static int usb_disable_function_remotewakeup(struct usb_device *udev) +static int usb_enable_remote_wakeup(struct usb_device *udev) { - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + if (udev->speed < USB_SPEED_SUPER) + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + else + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, + USB_INTRF_FUNC_SUSPEND, + USB_INTRF_FUNC_SUSPEND_RW | + USB_INTRF_FUNC_SUSPEND_LP, + NULL, 0, USB_CTRL_SET_TIMEOUT); +} + +/* + * usb_disable_remote_wakeup - disable remote wakeup for a device + * @udev: target device + * + * For USB-2 devices: Clear the device's remote wakeup feature. + * + * For USB-3 devices: Assume there's only one function on the device and + * disable remote wake for the first interface. FIXME if the interface + * association descriptor shows there's more than one function. + */ +static int usb_disable_remote_wakeup(struct usb_device *udev) +{ + if (udev->speed < USB_SPEED_SUPER) + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + else + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE, USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); @@ -2918,7 +2961,6 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) { struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); struct usb_port *port_dev = hub->ports[udev->portnum - 1]; - enum pm_qos_flags_status pm_qos_stat; int port1 = udev->portnum; int status; bool really_suspend = true; @@ -2930,33 +2972,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) * we don't explicitly enable it here. */ if (udev->do_remote_wakeup) { - if (!hub_is_superspeed(hub->hdev)) { - status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - } else { - /* Assume there's only one function on the USB 3.0 - * device and enable remote wake for the first - * interface. FIXME if the interface association - * descriptor shows there's more than one function. - */ - status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, - USB_RECIP_INTERFACE, - USB_INTRF_FUNC_SUSPEND, - USB_INTRF_FUNC_SUSPEND_RW | - USB_INTRF_FUNC_SUSPEND_LP, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - } + status = usb_enable_remote_wakeup(udev); if (status) { dev_dbg(&udev->dev, "won't remote wakeup, status %d\n", status); /* bail if autosuspend is requested */ if (PMSG_IS_AUTO(msg)) - return status; + goto err_wakeup; } } @@ -2965,14 +2987,16 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_usb2_hardware_lpm(udev, 0); if (usb_disable_ltm(udev)) { - dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.", - __func__); - return -ENOMEM; + dev_err(&udev->dev, "Failed to disable LTM before suspend\n."); + status = -ENOMEM; + if (PMSG_IS_AUTO(msg)) + goto err_ltm; } if (usb_unlocked_disable_lpm(udev)) { - dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.", - __func__); - return -ENOMEM; + dev_err(&udev->dev, "Failed to disable LPM before suspend\n."); + status = -ENOMEM; + if (PMSG_IS_AUTO(msg)) + goto err_lpm3; } /* see 7.1.7.6 */ @@ -3000,28 +3024,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (status) { dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); - /* paranoia: "should not happen" */ - if (udev->do_remote_wakeup) { - if (!hub_is_superspeed(hub->hdev)) { - (void) usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, - USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - } else - (void) usb_disable_function_remotewakeup(udev); - - } + /* Try to enable USB3 LPM and LTM again */ + usb_unlocked_enable_lpm(udev); + err_lpm3: + usb_enable_ltm(udev); + err_ltm: /* Try to enable USB2 hardware LPM again */ if (udev->usb2_hw_lpm_capable == 1) usb_set_usb2_hardware_lpm(udev, 1); - /* Try to enable USB3 LTM and LPM again */ - usb_enable_ltm(udev); - usb_unlocked_enable_lpm(udev); + if (udev->do_remote_wakeup) + (void) usb_disable_remote_wakeup(udev); + err_wakeup: /* System sleep transitions should never fail */ if (!PMSG_IS_AUTO(msg)) @@ -3043,14 +3058,15 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) * Check whether current status meets the requirement of * usb port power off mechanism */ - pm_qos_stat = dev_pm_qos_flags(&port_dev->dev, - PM_QOS_FLAG_NO_POWER_OFF); - if (!udev->do_remote_wakeup - && pm_qos_stat != PM_QOS_FLAGS_ALL - && udev->persist_enabled - && !status) { - pm_runtime_put_sync(&port_dev->dev); - port_dev->did_runtime_put = true; + if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { + enum pm_qos_flags_status pm_qos_stat; + + pm_qos_stat = dev_pm_qos_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF); + if (pm_qos_stat != PM_QOS_FLAGS_ALL) { + pm_runtime_put_sync(&port_dev->dev); + port_dev->did_runtime_put = true; + } } usb_mark_last_busy(hub->hdev); @@ -3102,8 +3118,6 @@ static int finish_port_resume(struct usb_device *udev) if (status == 0) { devstatus = 0; status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - if (status >= 0) - status = (status > 0 ? 0 : -ENODEV); /* If a normal resume failed, try doing a reset-resume */ if (status && !udev->reset_resume && udev->persist_enabled) { @@ -3123,24 +3137,15 @@ static int finish_port_resume(struct usb_device *udev) * udev->reset_resume */ } else if (udev->actconfig && !udev->reset_resume) { - if (!hub_is_superspeed(udev->parent)) { - le16_to_cpus(&devstatus); + if (udev->speed < USB_SPEED_SUPER) { if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, - USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); + status = usb_disable_remote_wakeup(udev); } else { status = usb_get_status(udev, USB_RECIP_INTERFACE, 0, &devstatus); - le16_to_cpus(&devstatus); if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW)) - status = - usb_disable_function_remotewakeup(udev); + status = usb_disable_remote_wakeup(udev); } if (status) @@ -3274,8 +3279,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) return status; } -#endif /* CONFIG_PM */ - #ifdef CONFIG_PM_RUNTIME /* caller has locked udev */ @@ -3843,7 +3846,8 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm); void usb_enable_ltm(struct usb_device *udev) { } EXPORT_SYMBOL_GPL(usb_enable_ltm); -#endif + +#endif /* CONFIG_PM */ /* USB 2.0 spec, 7.1.7.3 / fig 7-29: @@ -4483,11 +4487,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstat); - if (status < 2) { + if (status) { dev_dbg(&udev->dev, "get status %d ?\n", status); goto loop_disable; } - le16_to_cpus(&devstat); if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) { dev_err(&udev->dev, "can't connect bus-powered hub " @@ -4798,7 +4801,8 @@ static void hub_events(void) hub->ports[i - 1]->child; dev_dbg(hub_dev, "warm reset port %d\n", i); - if (!udev) { + if (!udev || !(portstatus & + USB_PORT_STAT_CONNECTION)) { status = hub_port_reset(hub, i, NULL, HUB_BH_RESET_TIME, true); @@ -4808,8 +4812,8 @@ static void hub_events(void) usb_lock_device(udev); status = usb_reset_device(udev); usb_unlock_device(udev); + connect_change = 0; } - connect_change = 0; } if (connect_change) @@ -5034,10 +5038,11 @@ static int descriptors_changed(struct usb_device *udev, * re-connected. All drivers will be unbound, and the device will be * re-enumerated and probed all over again. * - * Returns 0 if the reset succeeded, -ENODEV if the device has been + * Return: 0 if the reset succeeded, -ENODEV if the device has been * flagged for logical disconnection, or some other negative error code * if the reset wasn't even attempted. * + * Note: * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock @@ -5193,8 +5198,9 @@ re_enumerate: * method), performs the port reset, and then lets the drivers know that * the reset is over (using their post_reset method). * - * Return value is the same as for usb_reset_and_verify_device(). + * Return: The same as for usb_reset_and_verify_device(). * + * Note: * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock @@ -5332,7 +5338,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device); * USB drivers call this function to get hub's child device * pointer. * - * Return NULL if input param is invalid and + * Return: %NULL if input param is invalid and * child's usb_device pointer if non-NULL. */ struct usb_device *usb_hub_find_child(struct usb_device *hdev, @@ -5366,8 +5372,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, * @hdev: USB device belonging to the usb hub * @port1: port num of the port * - * Return connect type of the port and if input params are - * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN. + * Return: The connect type of the port if successful. Or + * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. */ enum usb_port_connect_type usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) @@ -5427,8 +5433,8 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev, * @hdev: USB device belonging to the usb hub * @port1: port num of the port * - * Return port's acpi handle if successful, NULL if params are - * invaild. + * Return: Port's acpi handle if successful, %NULL if params are + * invalid. */ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, int port1) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index e7ee1e45166..82927e1ed27 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -119,15 +119,15 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, * This function sends a simple control message to a specified endpoint and * waits for the message to complete, or timeout. * - * If successful, it returns the number of bytes transferred, otherwise a - * negative error number. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb(). * If a thread in your driver uses this call, make sure your disconnect() * method can wait for it to complete. Since you don't have a handle on the * URB used, you can't cancel the request. + * + * Return: If successful, the number of bytes transferred. Otherwise, a negative + * error number. */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, @@ -170,15 +170,16 @@ EXPORT_SYMBOL_GPL(usb_control_msg); * This function sends a simple interrupt message to a specified endpoint and * waits for the message to complete, or timeout. * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb() If a thread in your * driver uses this call, make sure your disconnect() method can wait for it to * complete. Since you don't have a handle on the URB used, you can't cancel * the request. + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of actual + * bytes transferred will be stored in the @actual_length paramater. */ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) @@ -203,9 +204,6 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb() If a thread in your @@ -217,6 +215,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * users are forced to abuse this routine by using it to submit URBs for * interrupt endpoints. We will take the liberty of creating an interrupt URB * (with the default interval) if the target is an interrupt endpoint. + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of actual + * bytes transferred will be stored in the @actual_length paramater. + * */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) @@ -341,9 +344,9 @@ static void sg_complete(struct urb *urb) * send every byte identified in the list. * @mem_flags: SLAB_* flags affecting memory allocations in this call * - * Returns zero for success, else a negative errno value. This initializes a - * scatter/gather request, allocating resources such as I/O mappings and urb - * memory (except maybe memory used by USB controller drivers). + * This initializes a scatter/gather request, allocating resources such as + * I/O mappings and urb memory (except maybe memory used by USB controller + * drivers). * * The request must be issued using usb_sg_wait(), which waits for the I/O to * complete (or to be canceled) and then cleans up all resources allocated by @@ -351,6 +354,8 @@ static void sg_complete(struct urb *urb) * * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. + * + * Return: Zero for success, else a negative errno value. */ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, unsigned pipe, unsigned period, struct scatterlist *sg, @@ -623,7 +628,7 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ int usb_get_descriptor(struct usb_device *dev, unsigned char type, @@ -671,7 +676,7 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ static int usb_get_string(struct usb_device *dev, unsigned short langid, @@ -805,7 +810,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) * * This call is synchronous, and may not be used in an interrupt context. * - * Returns length of the string (>= 0) or usb_control_msg status (< 0). + * Return: length of the string (>= 0) or usb_control_msg status (< 0). */ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { @@ -853,8 +858,8 @@ EXPORT_SYMBOL_GPL(usb_string); * @udev: the device whose string descriptor is being read * @index: the descriptor index * - * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, - * or NULL if the index is 0 or the string could not be read. + * Return: A pointer to a kmalloc'ed buffer containing the descriptor string, + * or %NULL if the index is 0 or the string could not be read. */ char *usb_cache_string(struct usb_device *udev, int index) { @@ -894,7 +899,7 @@ char *usb_cache_string(struct usb_device *udev, int index) * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) @@ -934,13 +939,13 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. + * Returns 0 and the status value in *@data (in host byte order) on success, + * or else the status code from the underlying usb_control_msg() call. */ int usb_get_status(struct usb_device *dev, int type, int target, void *data) { int ret; - u16 *status = kmalloc(sizeof(*status), GFP_KERNEL); + __le16 *status = kmalloc(sizeof(*status), GFP_KERNEL); if (!status) return -ENOMEM; @@ -949,7 +954,12 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data) USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status, sizeof(*status), USB_CTRL_GET_TIMEOUT); - *(u16 *)data = *status; + if (ret == 2) { + *(u16 *) data = le16_to_cpu(*status); + ret = 0; + } else if (ret >= 0) { + ret = -EIO; + } kfree(status); return ret; } @@ -975,7 +985,7 @@ EXPORT_SYMBOL_GPL(usb_get_status); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns zero on success, or else the status code returned by the + * Return: Zero on success, or else the status code returned by the * underlying usb_control_msg() call. */ int usb_clear_halt(struct usb_device *dev, int pipe) @@ -1272,7 +1282,7 @@ void usb_enable_interface(struct usb_device *dev, * endpoints in that interface; all such urbs must first be completed * (perhaps forced by unlinking). * - * Returns zero on success, or else the status code returned by the + * Return: Zero on success, or else the status code returned by the * underlying usb_control_msg() call. */ int usb_set_interface(struct usb_device *dev, int interface, int alternate) @@ -1426,7 +1436,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * * The caller must own the device lock. * - * Returns zero on success, else a negative error code. + * Return: Zero on success, else a negative error code. */ int usb_reset_configuration(struct usb_device *dev) { @@ -1968,7 +1978,7 @@ static void cancel_async_set_config(struct usb_device *udev) * routine gets around the normal restrictions by using a work thread to * submit the change-config request. * - * Returns 0 if the request was successfully queued, error code otherwise. + * Return: 0 if the request was successfully queued, error code otherwise. * The caller has no way to know whether the queued request will eventually * succeed. */ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 16927fa88fb..c12bc790a6a 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -7,6 +7,7 @@ #include <linux/usb.h> #include <linux/wait.h> #include <linux/usb/hcd.h> +#include <linux/scatterlist.h> #define to_urb(d) container_of(d, struct urb, kref) @@ -54,12 +55,12 @@ EXPORT_SYMBOL_GPL(usb_init_urb); * Creates an urb for the USB driver to use, initializes a few internal * structures, incrementes the usage counter, and returns a pointer to it. * - * If no memory is available, NULL is returned. - * * If the driver want to use this urb for interrupt, control, or bulk * endpoints, pass '0' as the number of iso packets. * * The driver must call usb_free_urb() when it is finished with the urb. + * + * Return: A pointer to the new urb, or %NULL if no memory is available. */ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { @@ -102,7 +103,7 @@ EXPORT_SYMBOL_GPL(usb_free_urb); * host controller driver. This allows proper reference counting to happen * for urbs. * - * A pointer to the urb with the incremented reference counter is returned. + * Return: A pointer to the urb with the incremented reference counter. */ struct urb *usb_get_urb(struct urb *urb) { @@ -199,13 +200,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * the particular kind of transfer, although they will not initialize * any transfer flags. * - * Successful submissions return 0; otherwise this routine returns a - * negative error number. If the submission is successful, the complete() - * callback from the URB will be called exactly once, when the USB core and - * Host Controller Driver (HCD) are finished with the URB. When the completion - * function is called, control of the URB is returned to the device - * driver which issued the request. The completion handler may then - * immediately free or reuse that URB. + * If the submission is successful, the complete() callback from the URB + * will be called exactly once, when the USB core and Host Controller Driver + * (HCD) are finished with the URB. When the completion function is called, + * control of the URB is returned to the device driver which issued the + * request. The completion handler may then immediately free or reuse that + * URB. * * With few exceptions, USB device drivers should never access URB fields * provided by usbcore or the HCD until its complete() is called. @@ -240,6 +240,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * that are standardized in the USB 2.0 specification. For bulk * endpoints, a synchronous usb_bulk_msg() call is available. * + * Return: + * 0 on successful submissions. A negative error number otherwise. + * * Request Queuing: * * URBs may be submitted to endpoints before previous ones complete, to @@ -413,6 +416,14 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->iso_frame_desc[n].status = -EXDEV; urb->iso_frame_desc[n].actual_length = 0; } + } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint && + dev->speed != USB_SPEED_WIRELESS) { + struct scatterlist *sg; + int i; + + for_each_sg(urb->sg, sg, urb->num_sgs - 1, i) + if (sg->length % max) + return -EINVAL; } /* the I/O buffer must be mapped/unmapped, except when length=0 */ @@ -564,6 +575,9 @@ EXPORT_SYMBOL_GPL(usb_submit_urb); * particular, when a driver calls this routine, it must insure that the * completion handler cannot deallocate the URB. * + * Return: -EINPROGRESS on success. See description for other values on + * failure. + * * Unlinking and Endpoint Queues: * * [The behaviors and guarantees described below do not apply to virtual @@ -838,6 +852,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); * * Call this is you want to be sure all an anchor's * URBs have finished + * + * Return: Non-zero if the anchor became unused. Zero on timeout. */ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout) @@ -851,8 +867,11 @@ EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); * usb_get_from_anchor - get an anchor's oldest urb * @anchor: the anchor whose urb you want * - * this will take the oldest urb from an anchor, + * This will take the oldest urb from an anchor, * unanchor and return it + * + * Return: The oldest urb from @anchor, or %NULL if @anchor has no + * urbs associated with it. */ struct urb *usb_get_from_anchor(struct usb_anchor *anchor) { @@ -901,7 +920,7 @@ EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); * usb_anchor_empty - is an anchor empty * @anchor: the anchor you want to query * - * returns 1 if the anchor has no urbs associated with it + * Return: 1 if the anchor has no urbs associated with it. */ int usb_anchor_empty(struct usb_anchor *anchor) { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7dad603dde4..0a6ee2e70b2 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -68,6 +68,8 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); * @alt_num: alternate interface setting number to search for. * * Search the configuration's interface cache for the given alt setting. + * + * Return: The alternate setting, if found. %NULL otherwise. */ struct usb_host_interface *usb_find_alt_setting( struct usb_host_config *config, @@ -103,8 +105,7 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting); * @ifnum: the desired interface * * This walks the device descriptor for the currently active configuration - * and returns a pointer to the interface with that particular interface - * number, or null. + * to find the interface object with the particular interface number. * * Note that configuration descriptors are not required to assign interface * numbers sequentially, so that it would be incorrect to assume that @@ -115,6 +116,9 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting); * * Don't call this function unless you are bound to one of the interfaces * on this device or you have locked the device! + * + * Return: A pointer to the interface that has @ifnum as interface number, + * if found. %NULL otherwise. */ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, unsigned ifnum) @@ -139,8 +143,7 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if); * @altnum: the desired alternate setting number * * This searches the altsetting array of the specified interface for - * an entry with the correct bAlternateSetting value and returns a pointer - * to that entry, or null. + * an entry with the correct bAlternateSetting value. * * Note that altsettings need not be stored sequentially by number, so * it would be incorrect to assume that the first altsetting entry in @@ -149,6 +152,9 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if); * * Don't call this function unless you are bound to the intf interface * or you have locked the device! + * + * Return: A pointer to the entry of the altsetting array of @intf that + * has @altnum as the alternate setting number. %NULL if not found. */ struct usb_host_interface *usb_altnum_to_altsetting( const struct usb_interface *intf, @@ -191,6 +197,8 @@ static int __find_interface(struct device *dev, void *data) * This walks the bus device list and returns a pointer to the interface * with the matching minor and driver. Note, this only works for devices * that share the USB major number. + * + * Return: A pointer to the interface with the matching major and @minor. */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { @@ -390,6 +398,9 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) * controllers) should ever call this. * * This call may not be used in a non-sleeping context. + * + * Return: On success, a pointer to the allocated usb device. %NULL on + * failure. */ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) @@ -501,7 +512,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, * their probe() methods, when they bind to an interface, and release * them by calling usb_put_dev(), in their disconnect() methods. * - * A pointer to the device with the incremented reference counter is returned. + * Return: A pointer to the device with the incremented reference counter. */ struct usb_device *usb_get_dev(struct usb_device *dev) { @@ -535,8 +546,7 @@ EXPORT_SYMBOL_GPL(usb_put_dev); * their probe() methods, when they bind to an interface, and release * them by calling usb_put_intf(), in their disconnect() methods. * - * A pointer to the interface with the incremented reference counter is - * returned. + * Return: A pointer to the interface with the incremented reference counter. */ struct usb_interface *usb_get_intf(struct usb_interface *intf) { @@ -589,7 +599,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf); * disconnect; in some drivers (such as usb-storage) the disconnect() * or suspend() method will block waiting for a device reset to complete. * - * Returns a negative error code for failure, otherwise 0. + * Return: A negative error code for failure, otherwise 0. */ int usb_lock_device_for_reset(struct usb_device *udev, const struct usb_interface *iface) @@ -628,14 +638,15 @@ EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); * usb_get_current_frame_number - return current bus frame number * @dev: the device whose bus is being queried * - * Returns the current frame number for the USB host controller - * used with the given USB device. This can be used when scheduling + * Return: The current frame number for the USB host controller used + * with the given USB device. This can be used when scheduling * isochronous requests. * - * Note that different kinds of host controller have different - * "scheduling horizons". While one type might support scheduling only - * 32 frames into the future, others could support scheduling up to - * 1024 frames into the future. + * Note: Different kinds of host controller have different "scheduling + * horizons". While one type might support scheduling only 32 frames + * into the future, others could support scheduling up to 1024 frames + * into the future. + * */ int usb_get_current_frame_number(struct usb_device *dev) { @@ -685,11 +696,12 @@ EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); * @mem_flags: affect whether allocation may block * @dma: used to return DMA address of buffer * - * Return value is either null (indicating no buffer could be allocated), or - * the cpu-space pointer to a buffer that may be used to perform DMA to the + * Return: Either null (indicating no buffer could be allocated), or the + * cpu-space pointer to a buffer that may be used to perform DMA to the * specified device. Such cpu-space buffers are returned along with the DMA * address (through the pointer provided). * + * Note: * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU * hardware during URB completion/resubmit. The implementation varies between @@ -735,17 +747,18 @@ EXPORT_SYMBOL_GPL(usb_free_coherent); * usb_buffer_map - create DMA mapping(s) for an urb * @urb: urb whose transfer_buffer/setup_packet will be mapped * - * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_TRANSFER_DMA_MAP is - * added to urb->transfer_flags if the operation succeeds. If the device - * is connected to this system through a non-DMA controller, this operation - * always succeeds. + * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation + * succeeds. If the device is connected to this system through a non-DMA + * controller, this operation always succeeds. * * This call would normally be used for an urb which is reused, perhaps * as the target of a large periodic transfer, with usb_buffer_dmasync() * calls to synchronize memory and dma state. * * Reverse the effect of this call with usb_buffer_unmap(). + * + * Return: Either %NULL (indicating no buffer could be mapped), or @urb. + * */ #if 0 struct urb *usb_buffer_map(struct urb *urb) @@ -850,9 +863,10 @@ EXPORT_SYMBOL_GPL(usb_buffer_unmap); * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * - * Return value is either < 0 (indicating no buffers could be mapped), or - * the number of DMA mapping array entries in the scatterlist. + * Return: Either < 0 (indicating no buffers could be mapped), or the + * number of DMA mapping array entries in the scatterlist. * + * Note: * The caller is responsible for placing the resulting DMA addresses from * the scatterlist into URB transfer buffer pointers, and for setting the * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f48712ffe26..c1c113ef950 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -449,14 +449,20 @@ fail: static int __exit eth_unbind(struct usb_composite_dev *cdev) { - if (has_rndis()) + if (has_rndis()) { + usb_put_function(f_rndis); usb_put_function_instance(fi_rndis); - if (use_eem) + } + if (use_eem) { + usb_put_function(f_eem); usb_put_function_instance(fi_eem); - else if (can_support_ecm(cdev->gadget)) + } else if (can_support_ecm(cdev->gadget)) { + usb_put_function(f_ecm); usb_put_function_instance(fi_ecm); - else + } else { + usb_put_function(f_geth); usb_put_function_instance(fi_geth); + } return 0; } diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 1bf26e9f38c..eb3aa817a66 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; int status, i; -#ifndef USBF_PHONET_INCLUDED struct f_phonet_opts *phonet_opts; phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst); @@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f) return status; phonet_opts->bound = true; } -#endif /* Reserve interface IDs */ status = usb_interface_id(c, f); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 032b96a51ce..2a1ebefd8f9 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c) return ret; f_acm_rndis = usb_get_function(fi_acm); - if (IS_ERR(f_acm_rndis)) { - ret = PTR_ERR(f_acm_rndis); - goto err_func_acm; - } + if (IS_ERR(f_acm_rndis)) + return PTR_ERR(f_acm_rndis); ret = usb_add_function(c, f_acm_rndis); if (ret) @@ -178,7 +176,6 @@ err_fsg: usb_remove_function(c, f_acm_rndis); err_conf: usb_put_function(f_acm_rndis); -err_func_acm: return ret; } @@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c) /* implicit port_num is zero */ f_acm_multi = usb_get_function(fi_acm); if (IS_ERR(f_acm_multi)) - goto err_func_acm; + return PTR_ERR(f_acm_multi); ret = usb_add_function(c, f_acm_multi); if (ret) @@ -241,7 +238,6 @@ err_fsg: usb_remove_function(c, f_acm_multi); err_conf: usb_put_function(f_acm_multi); -err_func_acm: return ret; } diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index dbce3a9074e..8c71212a8c5 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -172,7 +172,7 @@ MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); */ #define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS -#endif /* CONFIG_USB_DEBUG */ +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ /* check if fsg_num_buffers is within a valid range */ static inline int fsg_num_buffers_validate(void) diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 3122ab942f7..546bfda3059 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -110,7 +110,7 @@ static void usb_gadget_state_work(struct work_struct *work) { struct usb_gadget *gadget = work_to_gadget(work); - sysfs_notify(&gadget->dev.kobj, NULL, "status"); + sysfs_notify(&gadget->dev.kobj, NULL, "state"); } void usb_gadget_set_state(struct usb_gadget *gadget, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5064e06e25b..e3ea970fe42 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -113,12 +113,6 @@ config USB_EHCI_HCD_PMC_MSP Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's. If unsure, say N. -config USB_EHCI_BIG_ENDIAN_MMIO - bool - -config USB_EHCI_BIG_ENDIAN_DESC - bool - config XPS_USB_HCD_XILINX bool "Use Xilinx usb host EHCI controller core" depends on (PPC32 || MICROBLAZE) @@ -351,6 +345,18 @@ config USB_FUSBH200_HCD To compile this driver as a module, choose M here: the module will be called fusbh200-hcd. +config USB_FOTG210_HCD + tristate "FOTG210 HCD support" + depends on USB + default N + ---help--- + Faraday FOTG210 is an OTG controller which can be configured as + an USB2.0 host. It is designed to meet USB2.0 EHCI specification + with minor modification. + + To compile this driver as a module, choose M here: the + module will be called fotg210-hcd. + config USB_OHCI_HCD tristate "OHCI HCD (USB 1.1) support" select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 @@ -494,20 +500,6 @@ config USB_OCTEON_OHCI controller. It is needed for low-speed USB 1.0 device support. All CN6XXX based chips with USB are supported. - -config USB_OHCI_BIG_ENDIAN_DESC - bool - default n - -config USB_OHCI_BIG_ENDIAN_MMIO - bool - default n - -config USB_OHCI_LITTLE_ENDIAN - bool - default n if STB03xxx || PPC_MPC52xx - default y - endif # USB_OHCI_HCD config USB_UHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index bea71127b15..829a3397882 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -58,3 +58,4 @@ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o obj-$(CONFIG_USB_FUSBH200_HCD) += fusbh200-hcd.o +obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index bd831ec06dc..e44f442e2fb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, pr_debug("initializing FSL-SOC USB Controller\n"); /* Need platform data for setup */ - pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "No platform data for %s.\n", dev_name(&pdev->dev)); @@ -190,7 +190,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, static void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); if (!IS_ERR_OR_NULL(hcd->phy)) { otg_set_host(hcd->phy->otg, NULL); @@ -218,7 +218,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; struct device *dev = hcd->self.controller; - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); if (pdata->controller_ver < 0) { dev_warn(hcd->self.controller, "Could not get controller version\n"); @@ -291,7 +291,7 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) struct fsl_usb2_platform_data *pdata; void __iomem *non_ehci = hcd->regs; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); if (pdata->have_sysif_regs) { /* @@ -363,7 +363,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) struct device *dev; dev = hcd->self.controller; - pdata = hcd->self.controller->platform_data; + pdata = dev_get_platdata(hcd->self.controller); ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_mmio = pdata->big_endian_mmio; @@ -415,7 +415,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; #ifdef DEBUG @@ -484,7 +484,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); u32 tmp; dev_dbg(dev, "suspend=%d already_suspended=%d\n", @@ -669,7 +669,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index a77bd8dc33f..b52a66ce92e 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -43,7 +43,7 @@ static const struct hc_driver ehci_grlib_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -167,15 +167,6 @@ static int ehci_hcd_grlib_remove(struct platform_device *op) } -static void ehci_hcd_grlib_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = platform_get_drvdata(op); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_grlib_of_match[] = { { .name = "GAISLER_EHCI", @@ -191,7 +182,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match); static struct platform_driver ehci_grlib_driver = { .probe = ehci_hcd_grlib_probe, .remove = ehci_hcd_grlib_remove, - .shutdown = ehci_hcd_grlib_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "grlib-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 7abf1ce3a67..73c72997cd4 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -487,6 +487,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->periodic_size = DEFAULT_I_TDPS; INIT_LIST_HEAD(&ehci->async_unlink); INIT_LIST_HEAD(&ehci->async_idle); + INIT_LIST_HEAD(&ehci->intr_unlink_wait); INIT_LIST_HEAD(&ehci->intr_unlink); INIT_LIST_HEAD(&ehci->intr_qh_list); INIT_LIST_HEAD(&ehci->cached_itd_list); @@ -942,7 +943,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); unsigned long flags; - struct ehci_qh *qh, *tmp; + struct ehci_qh *qh; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ @@ -972,17 +973,13 @@ rescan: qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - for (tmp = ehci->async->qh_next.qh; - tmp && tmp != qh; - tmp = tmp->qh_next.qh) - continue; - /* periodic qh self-unlinks on empty, and a COMPLETING qh - * may already be unlinked. - */ - if (tmp) + WARN_ON(!list_empty(&qh->qtd_list)); + if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT) start_unlink_async(ehci, qh); + else + start_unlink_intr(ehci, qh); /* FALL THROUGH */ + case QH_STATE_COMPLETING: /* already in unlinking */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: idle_timeout: @@ -1169,7 +1166,7 @@ static const struct hc_driver ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 6280bd269e1..f8b215fa0d9 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -345,6 +345,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) end_unlink_async(ehci); unlink_empty_async_suspended(ehci); + ehci_handle_start_intr_unlinks(ehci); ehci_handle_intr_unlinks(ehci); end_free_itds(ehci); @@ -711,6 +712,142 @@ ehci_hub_descriptor ( } /*-------------------------------------------------------------------------*/ +#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06 + +static void usb_ehset_completion(struct urb *urb) +{ + struct completion *done = urb->context; + + complete(done); +} +static int submit_single_step_set_feature( + struct usb_hcd *hcd, + struct urb *urb, + int is_setup +); + +/* + * Allocate and initialize a control URB. This request will be used by the + * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages + * of the GetDescriptor request are sent 15 seconds after the SETUP stage. + * Return NULL if failed. + */ +static struct urb *request_single_step_set_feature_urb( + struct usb_device *udev, + void *dr, + void *buf, + struct completion *done +) { + struct urb *urb; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + struct usb_host_endpoint *ep; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return NULL; + + urb->pipe = usb_rcvctrlpipe(udev, 0); + ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) { + usb_free_urb(urb); + return NULL; + } + + urb->ep = ep; + urb->dev = udev; + urb->setup_packet = (void *)dr; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = USB_DT_DEVICE_SIZE; + urb->complete = usb_ehset_completion; + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->transfer_flags = URB_DIR_IN; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + urb->setup_dma = dma_map_single( + hcd->self.controller, + urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + urb->transfer_dma = dma_map_single( + hcd->self.controller, + urb->transfer_buffer, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + urb->context = done; + return urb; +} + +static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port) +{ + int retval = -ENOMEM; + struct usb_ctrlrequest *dr; + struct urb *urb; + struct usb_device *udev; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct usb_device_descriptor *buf; + DECLARE_COMPLETION_ONSTACK(done); + + /* Obtain udev of the rhub's child port */ + udev = usb_hub_find_child(hcd->self.root_hub, port); + if (!udev) { + ehci_err(ehci, "No device attached to the RootHub\n"); + return -ENODEV; + } + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + if (!dr) { + kfree(buf); + return -ENOMEM; + } + + /* Fill Setup packet for GetDescriptor */ + dr->bRequestType = USB_DIR_IN; + dr->bRequest = USB_REQ_GET_DESCRIPTOR; + dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); + dr->wIndex = 0; + dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); + urb = request_single_step_set_feature_urb(udev, dr, buf, &done); + if (!urb) + goto cleanup; + + /* Submit just the SETUP stage */ + retval = submit_single_step_set_feature(hcd, urb, 1); + if (retval) + goto out1; + if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__); + goto out1; + } + msleep(15 * 1000); + + /* Complete remaining DATA and STATUS stages using the same URB */ + urb->status = -EINPROGRESS; + usb_get_urb(urb); + atomic_inc(&urb->use_count); + atomic_inc(&urb->dev->urbnum); + retval = submit_single_step_set_feature(hcd, urb, 0); + if (!retval && !wait_for_completion_timeout(&done, + msecs_to_jiffies(2000))) { + usb_kill_urb(urb); + retval = -ETIMEDOUT; + ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__); + } +out1: + usb_free_urb(urb); +cleanup: + kfree(dr); + kfree(buf); + return retval; +} +/*-------------------------------------------------------------------------*/ static int ehci_hub_control ( struct usb_hcd *hcd, @@ -801,6 +938,8 @@ static int ehci_hub_control ( ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); + set_bit(wIndex, &ehci->resuming_ports); + usb_hcd_start_port_resume(&hcd->self, wIndex); break; case USB_PORT_FEAT_C_SUSPEND: clear_bit(wIndex, &ehci->port_c_suspend); @@ -865,11 +1004,11 @@ static int ehci_hub_control ( } } - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { + /* no reset or resume pending */ + if (!ehci->reset_done[wIndex]) { /* Remote Wakeup received? */ - if (!ehci->reset_done[wIndex]) { + if (temp & PORT_RESUME) { /* resume signaling for 20 msec */ ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); @@ -880,38 +1019,34 @@ static int ehci_hub_control ( ehci->reset_done[wIndex]); } - /* resume completed? */ - else if (time_after_eq(jiffies, - ehci->reset_done[wIndex])) { - clear_bit(wIndex, &ehci->suspended_ports); - set_bit(wIndex, &ehci->port_c_suspend); - ehci->reset_done[wIndex] = 0; - usb_hcd_end_port_resume(&hcd->self, wIndex); - - /* stop resume signaling */ - temp &= ~(PORT_RWC_BITS | - PORT_SUSPEND | PORT_RESUME); - ehci_writel(ehci, temp, status_reg); - clear_bit(wIndex, &ehci->resuming_ports); - retval = ehci_handshake(ehci, status_reg, - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err(ehci, - "port %d resume error %d\n", + /* reset or resume not yet complete */ + } else if (!time_after_eq(jiffies, ehci->reset_done[wIndex])) { + ; /* wait until it is complete */ + + /* resume completed */ + } else if (test_bit(wIndex, &ehci->resuming_ports)) { + clear_bit(wIndex, &ehci->suspended_ports); + set_bit(wIndex, &ehci->port_c_suspend); + ehci->reset_done[wIndex] = 0; + usb_hcd_end_port_resume(&hcd->self, wIndex); + + /* stop resume signaling */ + temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME); + ehci_writel(ehci, temp, status_reg); + clear_bit(wIndex, &ehci->resuming_ports); + retval = ehci_handshake(ehci, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + ehci_err(ehci, "port %d resume error %d\n", wIndex + 1, retval); - goto error; - } - temp = ehci_readl(ehci, status_reg); + goto error; } - } + temp = ehci_readl(ehci, status_reg); /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - ehci->reset_done[wIndex])) { + } else { status |= USB_PORT_STAT_C_RESET << 16; ehci->reset_done [wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); /* force reset to complete */ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), @@ -932,11 +1067,6 @@ static int ehci_hub_control ( ehci_readl(ehci, status_reg)); } - if (!(temp & (PORT_RESUME|PORT_RESET))) { - ehci->reset_done[wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); - } - /* transfer dedicated ports to the companion hc */ if ((temp & PORT_CONNECT) && test_bit(wIndex, &ehci->companion_ports)) { @@ -1057,7 +1187,7 @@ static int ehci_hub_control ( status_reg); break; case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) + if (temp & (PORT_SUSPEND|PORT_RESUME)) goto error; /* line status bits may report this as low speed, * which can be fine if this root hub has a @@ -1092,7 +1222,13 @@ static int ehci_hub_control ( * about the EHCI-specific stuff. */ case USB_PORT_FEAT_TEST: - if (!selector || selector > 5) + if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) { + spin_unlock_irqrestore(&ehci->lock, flags); + retval = ehset_single_step_set_feature(hcd, + wIndex); + spin_lock_irqsave(&ehci->lock, flags); + break; + } else if (!selector || selector > 5) goto error; spin_unlock_irqrestore(&ehci->lock, flags); ehci_quiesce(ehci); diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index ef2c3a1eca4..52a77734a22 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -93,6 +93,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); + INIT_LIST_HEAD(&qh->unlink_node); /* dummy td enables safe urb queuing */ qh->dummy = ehci_qtd_alloc (ehci, flags); diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 915c2db96dc..417c10da945 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -96,7 +96,7 @@ static const struct hc_driver mv_ehci_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -131,7 +131,7 @@ static const struct hc_driver mv_ehci_hc_driver = { static int mv_ehci_probe(struct platform_device *pdev) { - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; + struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct ehci_hcd *ehci; struct ehci_hcd_mv *ehci_mv; diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index e4c34ac386c..5899ad6626c 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -49,7 +49,7 @@ static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = { static int ehci_mxc_drv_probe(struct platform_device *pdev) { - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct resource *res; int irq, ret; @@ -174,7 +174,7 @@ err_alloc: static int ehci_mxc_drv_remove(struct platform_device *pdev) { - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; + struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv; @@ -197,20 +197,12 @@ static int ehci_mxc_drv_remove(struct platform_device *pdev) return 0; } -static void ehci_mxc_drv_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - MODULE_ALIAS("platform:mxc-ehci"); static struct platform_driver ehci_mxc_driver = { .probe = ehci_mxc_drv_probe, .remove = ehci_mxc_drv_remove, - .shutdown = ehci_mxc_drv_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "mxc-ehci", }, diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index 45cc0015841..ab0397e4d8f 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -51,7 +51,7 @@ static const struct hc_driver ehci_octeon_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 9bd7dfe3315..78b01fa475b 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -100,7 +100,7 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { static int ehci_hcd_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct usb_hcd *hcd; void __iomem *regs; @@ -119,7 +119,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) /* For DT boot, get platform data from parent. i.e. usbhshost */ if (dev->of_node) { - pdata = dev->parent->platform_data; + pdata = dev_get_platdata(dev->parent); dev->platform_data = pdata; } @@ -278,14 +278,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev) return 0; } -static void ehci_hcd_omap_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - static const struct of_device_id omap_ehci_dt_ids[] = { { .compatible = "ti,ehci-omap" }, { } @@ -296,7 +288,7 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, .remove = ehci_hcd_omap_remove, - .shutdown = ehci_hcd_omap_shutdown, + .shutdown = usb_hcd_platform_shutdown, /*.suspend = ehci_hcd_omap_suspend, */ /*.resume = ehci_hcd_omap_resume, */ .driver = { diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 1a450aa13eb..d1dfb9db5b4 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -139,7 +139,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, static int ehci_orion_drv_probe(struct platform_device *pdev) { - struct orion_ehci_data *pd = pdev->dev.platform_data; + struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev); const struct mbus_dram_target_info *dram; struct resource *res; struct usb_hcd *hcd; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 595d210655b..6bd299e61f5 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -315,53 +315,11 @@ done: * Also they depend on separate root hub suspend/resume. */ -static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - (pdev->device == 0x1E26 || - pdev->device == 0x8C2D || - pdev->device == 0x8C26 || - pdev->device == 0x9C26); -} - -static void ehci_enable_xhci_companion(void) -{ - struct pci_dev *companion = NULL; - - /* The xHCI and EHCI controllers are not on the same PCI slot */ - for_each_pci_dev(companion) { - if (!usb_is_intel_switchable_xhci(companion)) - continue; - usb_enable_xhci_ports(companion); - return; - } -} - static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - /* The BIOS on systems with the Intel Panther Point chipset may or may - * not support xHCI natively. That means that during system resume, it - * may switch the ports back to EHCI so that users can use their - * keyboard to select a kernel from GRUB after resume from hibernate. - * - * The BIOS is supposed to remember whether the OS had xHCI ports - * enabled before resume, and switch the ports back to xHCI when the - * BIOS/OS semaphore is written, but we all know we can't trust BIOS - * writers. - * - * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. - */ - if (usb_is_intel_switchable_ehci(pdev)) - ehci_enable_xhci_companion(); - if (ehci_resume(hcd, hibernated) != 0) (void) ehci_pci_reinit(ehci, pdev); return 0; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 5196d728517..f6b790ca8cf 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -39,7 +39,7 @@ static const char hcd_name[] = "ehci-platform"; static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ehci_pdata *pdata = pdev->dev.platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; @@ -87,14 +87,14 @@ static int ehci_platform_probe(struct platform_device *dev) * use reasonable defaults so platforms don't have to provide these. * with DT probing on ARM, none of these are set. */ - if (!dev->dev.platform_data) + if (!dev_get_platdata(&dev->dev)) dev->dev.platform_data = &ehci_platform_defaults; if (!dev->dev.dma_mask) dev->dev.dma_mask = &dev->dev.coherent_dma_mask; if (!dev->dev.coherent_dma_mask) dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdata = dev->dev.platform_data; + pdata = dev_get_platdata(&dev->dev); irq = platform_get_irq(dev, 0); if (irq < 0) { @@ -148,7 +148,7 @@ err_power: static int ehci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->dev.platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); @@ -167,7 +167,7 @@ static int ehci_platform_remove(struct platform_device *dev) static int ehci_platform_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); bool do_wakeup = device_may_wakeup(dev); @@ -184,7 +184,7 @@ static int ehci_platform_suspend(struct device *dev) static int ehci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ehci_pdata *pdata = dev->platform_data; + struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 601e208bd78..893b707f000 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -286,7 +286,7 @@ static const struct hc_driver ehci_msp_hc_driver = { #else .irq = ehci_irq, #endif - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 86da09c0f8d..6cc5567bf9c 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -28,7 +28,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -215,15 +215,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op) } -static void ehci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = platform_get_drvdata(op); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_ppc_of_match[] = { { .compatible = "usb-ehci", @@ -236,7 +227,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); static struct platform_driver ehci_hcd_ppc_of_driver = { .probe = ehci_hcd_ppc_of_probe, .remove = ehci_hcd_ppc_of_remove, - .shutdown = ehci_hcd_ppc_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index fd983771b02..8188542ba17 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -71,7 +71,7 @@ static const struct hc_driver ps3_ehci_hc_driver = { .product_desc = "PS3 EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, .reset = ps3_ehci_hc_reset, .start = ehci_run, .stop = ehci_stop, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index d34b399b78e..903d00dd668 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -254,8 +254,6 @@ static int qtd_copy_status ( static void ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) -__releases(ehci->lock) -__acquires(ehci->lock) { if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { /* ... update hc-wide periodic stats */ @@ -281,11 +279,8 @@ __acquires(ehci->lock) urb->actual_length, urb->transfer_buffer_length); #endif - /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - spin_unlock (&ehci->lock); usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); - spin_lock (&ehci->lock); } static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -1144,6 +1139,107 @@ submit_async ( } /*-------------------------------------------------------------------------*/ +/* + * This function creates the qtds and submits them for the + * SINGLE_STEP_SET_FEATURE Test. + * This is done in two parts: first SETUP req for GetDesc is sent then + * 15 seconds later, the IN stage for GetDesc starts to req data from dev + * + * is_setup : i/p arguement decides which of the two stage needs to be + * performed; TRUE - SETUP and FALSE - IN+STATUS + * Returns 0 if success + */ +static int submit_single_step_set_feature( + struct usb_hcd *hcd, + struct urb *urb, + int is_setup +) { + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct list_head qtd_list; + struct list_head *head; + + struct ehci_qtd *qtd, *qtd_prev; + dma_addr_t buf; + int len, maxpacket; + u32 token; + + INIT_LIST_HEAD(&qtd_list); + head = &qtd_list; + + /* URBs map to sequences of QTDs: one logical transaction */ + qtd = ehci_qtd_alloc(ehci, GFP_KERNEL); + if (unlikely(!qtd)) + return -1; + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (EHCI_TUNE_CERR << 10); + + len = urb->transfer_buffer_length; + /* + * Check if the request is to perform just the SETUP stage (getDesc) + * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens + * 15 secs after the setup + */ + if (is_setup) { + /* SETUP pid */ + qtd_fill(ehci, qtd, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8), 8); + + submit_async(ehci, urb, &qtd_list, GFP_ATOMIC); + return 0; /*Return now; we shall come back after 15 seconds*/ + } + + /* + * IN: data transfer stage: buffer setup : start the IN txn phase for + * the get_Desc SETUP which was sent 15seconds back + */ + token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/ + buf = urb->transfer_dma; + + token |= (1 /* "in" */ << 8); /*This is IN stage*/ + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0)); + + qtd_fill(ehci, qtd, buf, len, token, maxpacket); + + /* + * Our IN phase shall always be a short read; so keep the queue running + * and let it advance to the next qtd which zero length OUT status + */ + qtd->hw_alt_next = EHCI_LIST_END(ehci); + + /* STATUS stage for GetDesc control request */ + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + + qtd_prev = qtd; + qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* dont fill any data in such packets */ + qtd_fill(ehci, qtd, 0, 0, token, 0); + + /* by default, enable interrupt on urb completion */ + if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC); + + submit_async(ehci, urb, &qtd_list, GFP_KERNEL); + + return 0; + +cleanup: + qtd_list_free(ehci, urb, head); + return -1; +} + +/*-------------------------------------------------------------------------*/ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) { diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 7cc26e621aa..7c3de95c705 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -75,7 +75,7 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev) static int s5p_ehci_probe(struct platform_device *pdev) { - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; + struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev); struct s5p_ehci_hcd *s5p_ehci; struct usb_hcd *hcd; struct ehci_hcd *ehci; @@ -220,14 +220,6 @@ static int s5p_ehci_remove(struct platform_device *pdev) return 0; } -static void s5p_ehci_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - #ifdef CONFIG_PM static int s5p_ehci_suspend(struct device *dev) { @@ -297,7 +289,7 @@ MODULE_DEVICE_TABLE(of, exynos_ehci_match); static struct platform_driver s5p_ehci_driver = { .probe = s5p_ehci_probe, .remove = s5p_ehci_remove, - .shutdown = s5p_ehci_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "s5p-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index f80d0330d54..94388738a6f 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -601,12 +601,29 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) list_del(&qh->intr_node); } +static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + if (qh->qh_state != QH_STATE_LINKED || + list_empty(&qh->unlink_node)) + return; + + list_del_init(&qh->unlink_node); + + /* + * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for + * avoiding unnecessary CPU wakeup + */ +} + static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) { /* If the QH isn't linked then there's nothing we can do. */ if (qh->qh_state != QH_STATE_LINKED) return; + /* if the qh is waiting for unlink, cancel it now */ + cancel_unlink_wait_intr(ehci, qh); + qh_unlink_periodic (ehci, qh); /* Make sure the unlinks are visible before starting the timer */ @@ -632,6 +649,27 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) } } +/* + * It is common only one intr URB is scheduled on one qh, and + * given complete() is run in tasklet context, introduce a bit + * delay to avoid unlink qh too early. + */ +static void start_unlink_intr_wait(struct ehci_hcd *ehci, + struct ehci_qh *qh) +{ + qh->unlink_cycle = ehci->intr_unlink_wait_cycle; + + /* New entries go at the end of the intr_unlink_wait list */ + list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait); + + if (ehci->rh_state < EHCI_RH_RUNNING) + ehci_handle_start_intr_unlinks(ehci); + else if (ehci->intr_unlink_wait.next == &qh->unlink_node) { + ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); + ++ehci->intr_unlink_wait_cycle; + } +} + static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qh_hw *hw = qh->hw; @@ -889,6 +927,9 @@ static int intr_submit ( if (qh->qh_state == QH_STATE_IDLE) { qh_refresh(ehci, qh); qh_link_periodic(ehci, qh); + } else { + /* cancel unlink wait for the qh */ + cancel_unlink_wait_intr(ehci, qh); } /* ... update usbfs periodic stats */ @@ -924,9 +965,11 @@ static void scan_intr(struct ehci_hcd *ehci) * in qh_unlink_periodic(). */ temp = qh_completions(ehci, qh); - if (unlikely(temp || (list_empty(&qh->qtd_list) && - qh->qh_state == QH_STATE_LINKED))) + if (unlikely(temp)) start_unlink_intr(ehci, qh); + else if (unlikely(list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED)) + start_unlink_intr_wait(ehci, qh); } } } diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index b2de52d3961..8a734498079 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -55,7 +55,7 @@ const struct hc_driver ehci_sead3_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index c4c0ee92a39..dc899eb2b86 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -36,7 +36,7 @@ static const struct hc_driver ehci_sh_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, /* * basic lifecycle operations @@ -104,7 +104,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) goto fail_create_hcd; } - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); /* initialize hcd */ hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index d72b2929c03..67026ffbf9a 100644 --- a/drivers/usb/host/ehci-tilegx.c +++ b/drivers/usb/host/ehci-tilegx.c @@ -61,7 +61,7 @@ static const struct hc_driver ehci_tilegx_hc_driver = { * Generic hardware linkage. */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * Basic lifecycle operations. @@ -101,7 +101,7 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct ehci_hcd *ehci; - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); pte_t pte = { 0 }; int my_cpu = smp_processor_id(); int ret; @@ -186,7 +186,7 @@ err_hcd: static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 11e5b32f73e..424ac5d8371 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ + 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */ 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ @@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci) /* Not in process context, so don't try to reset the controller */ } +/* start to unlink interrupt QHs */ +static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci) +{ + bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + while (!list_empty(&ehci->intr_unlink_wait)) { + struct ehci_qh *qh; + + qh = list_first_entry(&ehci->intr_unlink_wait, + struct ehci_qh, unlink_node); + if (!stopped && (qh->unlink_cycle == + ehci->intr_unlink_wait_cycle)) + break; + list_del_init(&qh->unlink_node); + start_unlink_intr(ehci, qh); + } + + /* Handle remaining entries later */ + if (!list_empty(&ehci->intr_unlink_wait)) { + ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); + ++ehci->intr_unlink_wait_cycle; + } +} /* Handle unlinked interrupt QHs once they are gone from the hardware */ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) @@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) unlink_node); if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) break; - list_del(&qh->unlink_node); + list_del_init(&qh->unlink_node); end_unlink_intr(ehci, qh); } @@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ + ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */ unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index 59e0e24c753..1c370dfbee0 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -108,7 +108,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_USB2|HCD_MEMORY, + .flags = HCD_USB2|HCD_MEMORY|HCD_BH, /* * basic lifecycle operations diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 35c7f90384a..95979f9f438 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -79,7 +79,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = { * generic hardware linkage */ .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, + .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, /* * basic lifecycle operations @@ -220,21 +220,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op) return 0; } -/** - * ehci_hcd_xilinx_of_shutdown - shutdown the hcd - * @op: pointer to platform_device structure that is to be removed - * - * Properly shutdown the hcd, call driver's shutdown routine. - */ -static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = platform_get_drvdata(op); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ehci_hcd_xilinx_of_match[] = { {.compatible = "xlnx,xps-usb-host-1.00.a",}, {}, @@ -244,7 +229,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match); static struct platform_driver ehci_hcd_xilinx_of_driver = { .probe = ehci_hcd_xilinx_of_probe, .remove = ehci_hcd_xilinx_of_remove, - .shutdown = ehci_hcd_xilinx_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xilinx-of-ehci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index d034d94a7fe..2822e79e1fb 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -88,6 +88,7 @@ enum ehci_hrtimer_event { EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ + EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */ EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ @@ -143,7 +144,9 @@ struct ehci_hcd { /* one per controller */ unsigned i_thresh; /* uframes HC might cache */ union ehci_shadow *pshadow; /* mirror hw periodic table */ + struct list_head intr_unlink_wait; struct list_head intr_unlink; + unsigned intr_unlink_wait_cycle; unsigned intr_unlink_cycle; unsigned now_frame; /* frame from HC hardware */ unsigned last_iso_frame; /* last frame scanned for iso */ diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c new file mode 100644 index 00000000000..fce13bcc4a3 --- /dev/null +++ b/drivers/usb/host/fotg210-hcd.c @@ -0,0 +1,6049 @@ +/* + * Faraday FOTG210 EHCI-like driver + * + * Copyright (c) 2013 Faraday Technology Corporation + * + * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com> + * Feng-Hsin Chiang <john453@faraday-tech.com> + * Po-Yu Chuang <ratbert.chuang@gmail.com> + * + * Most of code borrowed from the Linux-3.7 EHCI driver + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/module.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/hrtimer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/moduleparam.h> +#include <linux/dma-mapping.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/byteorder.h> +#include <asm/irq.h> +#include <asm/unaligned.h> + +/*-------------------------------------------------------------------------*/ +#define DRIVER_AUTHOR "Yuan-Hsin Chen" +#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver" + +static const char hcd_name[] = "fotg210_hcd"; + +#undef VERBOSE_DEBUG +#undef FOTG210_URB_TRACE + +#ifdef DEBUG +#define FOTG210_STATS +#endif + +/* magic numbers that can affect system performance */ +#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define FOTG210_TUNE_RL_TT 0 +#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define FOTG210_TUNE_MULT_TT 1 +/* + * Some drivers think it's safe to schedule isochronous transfers more than + * 256 ms into the future (partly as a result of an old bug in the scheduling + * code). In an attempt to avoid trouble, we will use a minimum scheduling + * length of 512 frames instead of 256. + */ +#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */ + +/* Initial IRQ latency: faster than hw default */ +static int log2_irq_thresh; /* 0 to 6 */ +module_param(log2_irq_thresh, int, S_IRUGO); +MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); + +/* initial park setting: slower than hw default */ +static unsigned park; +module_param(park, uint, S_IRUGO); +MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); + +/* for link power management(LPM) feature */ +static unsigned int hird; +module_param(hird, int, S_IRUGO); +MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); + +#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) + +#include "fotg210.h" + +/*-------------------------------------------------------------------------*/ + +#define fotg210_dbg(fotg210, fmt, args...) \ + dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_err(fotg210, fmt, args...) \ + dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_info(fotg210, fmt, args...) \ + dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) +#define fotg210_warn(fotg210, fmt, args...) \ + dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) + +#ifdef VERBOSE_DEBUG +# define fotg210_vdbg fotg210_dbg +#else + static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {} +#endif + +#ifdef DEBUG + +/* check the values in the HCSPARAMS register + * (host controller _Structural_ parameters) + * see EHCI spec, Table 2-4 for each value + */ +static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) +{ + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params); + + fotg210_dbg(fotg210, + "%s hcs_params 0x%x ports=%d\n", + label, params, + HCS_N_PORTS(params) + ); +} +#else + +static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {} + +#endif + +#ifdef DEBUG + +/* check the values in the HCCPARAMS register + * (host controller _Capability_ parameters) + * see EHCI Spec, Table 2-5 for each value + * */ +static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) +{ + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + fotg210_dbg(fotg210, + "%s hcc_params %04x uframes %s%s\n", + label, + params, + HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", + HCC_CANPARK(params) ? " park" : ""); +} +#else + +static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {} + +#endif + +#ifdef DEBUG + +static void __maybe_unused +dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd) +{ + fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, + hc32_to_cpup(fotg210, &qtd->hw_next), + hc32_to_cpup(fotg210, &qtd->hw_alt_next), + hc32_to_cpup(fotg210, &qtd->hw_token), + hc32_to_cpup(fotg210, &qtd->hw_buf[0])); + if (qtd->hw_buf[1]) + fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n", + hc32_to_cpup(fotg210, &qtd->hw_buf[1]), + hc32_to_cpup(fotg210, &qtd->hw_buf[2]), + hc32_to_cpup(fotg210, &qtd->hw_buf[3]), + hc32_to_cpup(fotg210, &qtd->hw_buf[4])); +} + +static void __maybe_unused +dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qh_hw *hw = qh->hw; + + fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, + qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current); + dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next); +} + +static void __maybe_unused +dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd) +{ + fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", + label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next), + itd->urb); + fotg210_dbg(fotg210, + " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fotg210, itd->hw_transaction[0]), + hc32_to_cpu(fotg210, itd->hw_transaction[1]), + hc32_to_cpu(fotg210, itd->hw_transaction[2]), + hc32_to_cpu(fotg210, itd->hw_transaction[3]), + hc32_to_cpu(fotg210, itd->hw_transaction[4]), + hc32_to_cpu(fotg210, itd->hw_transaction[5]), + hc32_to_cpu(fotg210, itd->hw_transaction[6]), + hc32_to_cpu(fotg210, itd->hw_transaction[7])); + fotg210_dbg(fotg210, + " buf: %08x %08x %08x %08x %08x %08x %08x\n", + hc32_to_cpu(fotg210, itd->hw_bufp[0]), + hc32_to_cpu(fotg210, itd->hw_bufp[1]), + hc32_to_cpu(fotg210, itd->hw_bufp[2]), + hc32_to_cpu(fotg210, itd->hw_bufp[3]), + hc32_to_cpu(fotg210, itd->hw_bufp[4]), + hc32_to_cpu(fotg210, itd->hw_bufp[5]), + hc32_to_cpu(fotg210, itd->hw_bufp[6])); + fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n", + itd->index[0], itd->index[1], itd->index[2], + itd->index[3], itd->index[4], itd->index[5], + itd->index[6], itd->index[7]); +} + +static int __maybe_unused +dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) +{ + return scnprintf(buf, len, + "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", + label, label[0] ? " " : "", status, + (status & STS_ASS) ? " Async" : "", + (status & STS_PSS) ? " Periodic" : "", + (status & STS_RECL) ? " Recl" : "", + (status & STS_HALT) ? " Halt" : "", + (status & STS_IAA) ? " IAA" : "", + (status & STS_FATAL) ? " FATAL" : "", + (status & STS_FLR) ? " FLR" : "", + (status & STS_PCD) ? " PCD" : "", + (status & STS_ERR) ? " ERR" : "", + (status & STS_INT) ? " INT" : "" + ); +} + +static int __maybe_unused +dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) +{ + return scnprintf(buf, len, + "%s%sintrenable %02x%s%s%s%s%s%s", + label, label[0] ? " " : "", enable, + (enable & STS_IAA) ? " IAA" : "", + (enable & STS_FATAL) ? " FATAL" : "", + (enable & STS_FLR) ? " FLR" : "", + (enable & STS_PCD) ? " PCD" : "", + (enable & STS_ERR) ? " ERR" : "", + (enable & STS_INT) ? " INT" : "" + ); +} + +static const char *const fls_strings[] = { "1024", "512", "256", "??" }; + +static int +dbg_command_buf(char *buf, unsigned len, const char *label, u32 command) +{ + return scnprintf(buf, len, + "%s%scommand %07x %s=%d ithresh=%d%s%s%s " + "period=%s%s %s", + label, label[0] ? " " : "", command, + (command & CMD_PARK) ? " park" : "(park)", + CMD_PARK_CNT(command), + (command >> 16) & 0x3f, + (command & CMD_IAAD) ? " IAAD" : "", + (command & CMD_ASE) ? " Async" : "", + (command & CMD_PSE) ? " Periodic" : "", + fls_strings[(command >> 2) & 0x3], + (command & CMD_RESET) ? " Reset" : "", + (command & CMD_RUN) ? "RUN" : "HALT" + ); +} + +static int +dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) +{ + char *sig; + + /* signaling state */ + switch (status & (3 << 10)) { + case 0 << 10: + sig = "se0"; + break; + case 1 << 10: + sig = "k"; + break; /* low speed */ + case 2 << 10: + sig = "j"; + break; + default: + sig = "?"; + break; + } + + return scnprintf(buf, len, + "%s%sport:%d status %06x %d " + "sig=%s%s%s%s%s%s%s%s", + label, label[0] ? " " : "", port, status, + status>>25,/*device address */ + sig, + (status & PORT_RESET) ? " RESET" : "", + (status & PORT_SUSPEND) ? " SUSPEND" : "", + (status & PORT_RESUME) ? " RESUME" : "", + (status & PORT_PEC) ? " PEC" : "", + (status & PORT_PE) ? " PE" : "", + (status & PORT_CSC) ? " CSC" : "", + (status & PORT_CONNECT) ? " CONNECT" : ""); +} + +#else +static inline void __maybe_unused +dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{} + +static inline int __maybe_unused +dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) +{ return 0; } + +static inline int __maybe_unused +dbg_command_buf(char *buf, unsigned len, const char *label, u32 command) +{ return 0; } + +static inline int __maybe_unused +dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) +{ return 0; } + +static inline int __maybe_unused +dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) +{ return 0; } + +#endif /* DEBUG */ + +/* functions have the "wrong" filename when they're output... */ +#define dbg_status(fotg210, label, status) { \ + char _buf[80]; \ + dbg_status_buf(_buf, sizeof(_buf), label, status); \ + fotg210_dbg(fotg210, "%s\n", _buf); \ +} + +#define dbg_cmd(fotg210, label, command) { \ + char _buf[80]; \ + dbg_command_buf(_buf, sizeof(_buf), label, command); \ + fotg210_dbg(fotg210, "%s\n", _buf); \ +} + +#define dbg_port(fotg210, label, port, status) { \ + char _buf[80]; \ + dbg_port_buf(_buf, sizeof(_buf), label, port, status); \ + fotg210_dbg(fotg210, "%s\n", _buf); \ +} + +/*-------------------------------------------------------------------------*/ + +#ifdef STUB_DEBUG_FILES + +static inline void create_debug_files(struct fotg210_hcd *bus) { } +static inline void remove_debug_files(struct fotg210_hcd *bus) { } + +#else + +/* troubleshooting help: expose state in debugfs */ + +static int debug_async_open(struct inode *, struct file *); +static int debug_periodic_open(struct inode *, struct file *); +static int debug_registers_open(struct inode *, struct file *); +static int debug_async_open(struct inode *, struct file *); + +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); +static int debug_close(struct inode *, struct file *); + +static const struct file_operations debug_async_fops = { + .owner = THIS_MODULE, + .open = debug_async_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; +static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, + .llseek = default_llseek, +}; + +static struct dentry *fotg210_debug_root; + +struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ + struct usb_bus *bus; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *output_buf; + size_t alloc_size; +}; + +#define speed_char(info1)({ char tmp; \ + switch (info1 & (3 << 12)) { \ + case QH_FULL_SPEED: \ + tmp = 'f'; break; \ + case QH_LOW_SPEED: \ + tmp = 'l'; break; \ + case QH_HIGH_SPEED: \ + tmp = 'h'; break; \ + default: \ + tmp = '?'; break; \ + }; tmp; }) + +static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token) +{ + __u32 v = hc32_to_cpu(fotg210, token); + + if (v & QTD_STS_ACTIVE) + return '*'; + if (v & QTD_STS_HALT) + return '-'; + if (!IS_SHORT_READ(v)) + return ' '; + /* tries to advance through hw_alt_next */ + return '/'; +} + +static void qh_lines( + struct fotg210_hcd *fotg210, + struct fotg210_qh *qh, + char **nextp, + unsigned *sizep +) +{ + u32 scratch; + u32 hw_curr; + struct fotg210_qtd *td; + unsigned temp; + unsigned size = *sizep; + char *next = *nextp; + char mark; + __le32 list_end = FOTG210_LIST_END(fotg210); + struct fotg210_qh_hw *hw = qh->hw; + + if (hw->hw_qtd_next == list_end) /* NEC does this */ + mark = '@'; + else + mark = token_mark(fotg210, hw->hw_token); + if (mark == '/') { /* qh_alt_next controls qh advance? */ + if ((hw->hw_alt_next & QTD_MASK(fotg210)) + == fotg210->async->hw->hw_alt_next) + mark = '#'; /* blocked */ + else if (hw->hw_alt_next == list_end) + mark = '.'; /* use hw_qtd_next */ + /* else alt_next points to some other qtd */ + } + scratch = hc32_to_cpup(fotg210, &hw->hw_info1); + hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0; + temp = scnprintf(next, size, + "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)", + qh, scratch & 0x007f, + speed_char(scratch), + (scratch >> 8) & 0x000f, + scratch, hc32_to_cpup(fotg210, &hw->hw_info2), + hc32_to_cpup(fotg210, &hw->hw_token), mark, + (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token) + ? "data1" : "data0", + (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f); + size -= temp; + next += temp; + + /* hc may be modifying the list as we read it ... */ + list_for_each_entry(td, &qh->qtd_list, qtd_list) { + scratch = hc32_to_cpup(fotg210, &td->hw_token); + mark = ' '; + if (hw_curr == td->qtd_dma) + mark = '*'; + else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma)) + mark = '+'; + else if (QTD_LENGTH(scratch)) { + if (td->hw_alt_next == fotg210->async->hw->hw_alt_next) + mark = '#'; + else if (td->hw_alt_next != list_end) + mark = '/'; + } + temp = snprintf(next, size, + "\n\t%p%c%s len=%d %08x urb %p", + td, mark, ({ char *tmp; + switch ((scratch>>8)&0x03) { + case 0: + tmp = "out"; + break; + case 1: + tmp = "in"; + break; + case 2: + tmp = "setup"; + break; + default: + tmp = "?"; + break; + } tmp; }), + (scratch >> 16) & 0x7fff, + scratch, + td->urb); + if (size < temp) + temp = size; + size -= temp; + next += temp; + if (temp == size) + goto done; + } + + temp = snprintf(next, size, "\n"); + if (size < temp) + temp = size; + size -= temp; + next += temp; + +done: + *sizep = size; + *nextp = next; +} + +static ssize_t fill_async_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + unsigned temp, size; + char *next; + struct fotg210_qh *qh; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + *next = 0; + + /* dumps a snapshot of the async schedule. + * usually empty except for long-term bulk reads, or head. + * one QH per line, and TDs we know about + */ + spin_lock_irqsave(&fotg210->lock, flags); + for (qh = fotg210->async->qh_next.qh; size > 0 && qh; + qh = qh->qh_next.qh) + qh_lines(fotg210, qh, &next, &size); + if (fotg210->async_unlink && size > 0) { + temp = scnprintf(next, size, "\nunlink =\n"); + size -= temp; + next += temp; + + for (qh = fotg210->async_unlink; size > 0 && qh; + qh = qh->unlink_next) + qh_lines(fotg210, qh, &next, &size); + } + spin_unlock_irqrestore(&fotg210->lock, flags); + + return strlen(buf->output_buf); +} + +#define DBG_SCHED_LIMIT 64 +static ssize_t fill_periodic_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + union fotg210_shadow p, *seen; + unsigned temp, size, seen_count; + char *next; + unsigned i; + __hc32 tag; + + seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC); + if (!seen) + return 0; + seen_count = 0; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size); + size -= temp; + next += temp; + + /* dump a snapshot of the periodic schedule. + * iso changes, interrupt usually doesn't. + */ + spin_lock_irqsave(&fotg210->lock, flags); + for (i = 0; i < fotg210->periodic_size; i++) { + p = fotg210->pshadow[i]; + if (likely(!p.ptr)) + continue; + tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]); + + temp = scnprintf(next, size, "%4d: ", i); + size -= temp; + next += temp; + + do { + struct fotg210_qh_hw *hw; + + switch (hc32_to_cpu(fotg210, tag)) { + case Q_TYPE_QH: + hw = p.qh->hw; + temp = scnprintf(next, size, " qh%d-%04x/%p", + p.qh->period, + hc32_to_cpup(fotg210, + &hw->hw_info2) + /* uframe masks */ + & (QH_CMASK | QH_SMASK), + p.qh); + size -= temp; + next += temp; + /* don't repeat what follows this qh */ + for (temp = 0; temp < seen_count; temp++) { + if (seen[temp].ptr != p.ptr) + continue; + if (p.qh->qh_next.ptr) { + temp = scnprintf(next, size, + " ..."); + size -= temp; + next += temp; + } + break; + } + /* show more info the first time around */ + if (temp == seen_count) { + u32 scratch = hc32_to_cpup(fotg210, + &hw->hw_info1); + struct fotg210_qtd *qtd; + char *type = ""; + + /* count tds, get ep direction */ + temp = 0; + list_for_each_entry(qtd, + &p.qh->qtd_list, + qtd_list) { + temp++; + switch (0x03 & (hc32_to_cpu( + fotg210, + qtd->hw_token) >> 8)) { + case 0: + type = "out"; + continue; + case 1: + type = "in"; + continue; + } + } + + temp = scnprintf(next, size, + "(%c%d ep%d%s " + "[%d/%d] q%d p%d)", + speed_char(scratch), + scratch & 0x007f, + (scratch >> 8) & 0x000f, type, + p.qh->usecs, p.qh->c_usecs, + temp, + 0x7ff & (scratch >> 16)); + + if (seen_count < DBG_SCHED_LIMIT) + seen[seen_count++].qh = p.qh; + } else + temp = 0; + tag = Q_NEXT_TYPE(fotg210, hw->hw_next); + p = p.qh->qh_next; + break; + case Q_TYPE_FSTN: + temp = scnprintf(next, size, + " fstn-%8x/%p", p.fstn->hw_prev, + p.fstn); + tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next); + p = p.fstn->fstn_next; + break; + case Q_TYPE_ITD: + temp = scnprintf(next, size, + " itd/%p", p.itd); + tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next); + p = p.itd->itd_next; + break; + } + size -= temp; + next += temp; + } while (p.ptr); + + temp = scnprintf(next, size, "\n"); + size -= temp; + next += temp; + } + spin_unlock_irqrestore(&fotg210->lock, flags); + kfree(seen); + + return buf->alloc_size - size; +} +#undef DBG_SCHED_LIMIT + +static const char *rh_state_string(struct fotg210_hcd *fotg210) +{ + switch (fotg210->rh_state) { + case FOTG210_RH_HALTED: + return "halted"; + case FOTG210_RH_SUSPENDED: + return "suspended"; + case FOTG210_RH_RUNNING: + return "running"; + case FOTG210_RH_STOPPING: + return "stopping"; + } + return "?"; +} + +static ssize_t fill_registers_buffer(struct debug_buffer *buf) +{ + struct usb_hcd *hcd; + struct fotg210_hcd *fotg210; + unsigned long flags; + unsigned temp, size, i; + char *next, scratch[80]; + static const char fmt[] = "%*s\n"; + static const char label[] = ""; + + hcd = bus_to_hcd(buf->bus); + fotg210 = hcd_to_fotg210(hcd); + next = buf->output_buf; + size = buf->alloc_size; + + spin_lock_irqsave(&fotg210->lock, flags); + + if (!HCD_HW_ACCESSIBLE(hcd)) { + size = scnprintf(next, size, + "bus %s, device %s\n" + "%s\n" + "SUSPENDED(no register access)\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc); + goto done; + } + + /* Capability Registers */ + i = HC_VERSION(fotg210, fotg210_readl(fotg210, + &fotg210->caps->hc_capbase)); + temp = scnprintf(next, size, + "bus %s, device %s\n" + "%s\n" + "EHCI %x.%02x, rh state %s\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc, + i >> 8, i & 0x0ff, rh_state_string(fotg210)); + size -= temp; + next += temp; + + /* FIXME interpret both types of params */ + i = fotg210_readl(fotg210, &fotg210->caps->hcs_params); + temp = scnprintf(next, size, "structural params 0x%08x\n", i); + size -= temp; + next += temp; + + i = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + temp = scnprintf(next, size, "capability params 0x%08x\n", i); + size -= temp; + next += temp; + + /* Operational Registers */ + temp = dbg_status_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->status)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_command_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->command)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = dbg_intr_buf(scratch, sizeof(scratch), label, + fotg210_readl(fotg210, &fotg210->regs->intr_enable)); + temp = scnprintf(next, size, fmt, temp, scratch); + size -= temp; + next += temp; + + temp = scnprintf(next, size, "uframe %04x\n", + fotg210_read_frame_index(fotg210)); + size -= temp; + next += temp; + + if (fotg210->async_unlink) { + temp = scnprintf(next, size, "async unlink qh %p\n", + fotg210->async_unlink); + size -= temp; + next += temp; + } + +#ifdef FOTG210_STATS + temp = scnprintf(next, size, + "irq normal %ld err %ld iaa %ld(lost %ld)\n", + fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa, + fotg210->stats.lost_iaa); + size -= temp; + next += temp; + + temp = scnprintf(next, size, "complete %ld unlink %ld\n", + fotg210->stats.complete, fotg210->stats.unlink); + size -= temp; + next += temp; +#endif + +done: + spin_unlock_irqrestore(&fotg210->lock, flags); + + return buf->alloc_size - size; +} + +static struct debug_buffer *alloc_buffer(struct usb_bus *bus, + ssize_t (*fill_func)(struct debug_buffer *)) +{ + struct debug_buffer *buf; + + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + + if (buf) { + buf->bus = bus; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + buf->alloc_size = PAGE_SIZE; + } + + return buf; +} + +static int fill_buffer(struct debug_buffer *buf) +{ + int ret = 0; + + if (!buf->output_buf) + buf->output_buf = vmalloc(buf->alloc_size); + + if (!buf->output_buf) { + ret = -ENOMEM; + goto out; + } + + ret = buf->fill_func(buf); + + if (ret >= 0) { + buf->count = ret; + ret = 0; + } + +out: + return ret; +} + +static ssize_t debug_output(struct file *file, char __user *user_buf, + size_t len, loff_t *offset) +{ + struct debug_buffer *buf = file->private_data; + int ret = 0; + + mutex_lock(&buf->mutex); + if (buf->count == 0) { + ret = fill_buffer(buf); + if (ret != 0) { + mutex_unlock(&buf->mutex); + goto out; + } + } + mutex_unlock(&buf->mutex); + + ret = simple_read_from_buffer(user_buf, len, offset, + buf->output_buf, buf->count); + +out: + return ret; + +} + +static int debug_close(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf = file->private_data; + + if (buf) { + vfree(buf->output_buf); + kfree(buf); + } + + return 0; +} +static int debug_async_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static int debug_periodic_open(struct inode *inode, struct file *file) +{ + struct debug_buffer *buf; + buf = alloc_buffer(inode->i_private, fill_periodic_buffer); + if (!buf) + return -ENOMEM; + + buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; + file->private_data = buf; + return 0; +} + +static int debug_registers_open(struct inode *inode, struct file *file) +{ + file->private_data = alloc_buffer(inode->i_private, + fill_registers_buffer); + + return file->private_data ? 0 : -ENOMEM; +} + +static inline void create_debug_files(struct fotg210_hcd *fotg210) +{ + struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; + + fotg210->debug_dir = debugfs_create_dir(bus->bus_name, + fotg210_debug_root); + if (!fotg210->debug_dir) + return; + + if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus, + &debug_async_fops)) + goto file_error; + + if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus, + &debug_periodic_fops)) + goto file_error; + + if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus, + &debug_registers_fops)) + goto file_error; + + return; + +file_error: + debugfs_remove_recursive(fotg210->debug_dir); +} + +static inline void remove_debug_files(struct fotg210_hcd *fotg210) +{ + debugfs_remove_recursive(fotg210->debug_dir); +} + +#endif /* STUB_DEBUG_FILES */ +/*-------------------------------------------------------------------------*/ + +/* + * handshake - spin reading hc until handshake completes or fails + * @ptr: address of hc register to be read + * @mask: bits to look at in result of read + * @done: value of those bits when handshake succeeds + * @usec: timeout in microseconds + * + * Returns negative errno, or zero on success + * + * Success happens when the "mask" bits have the specified value (hardware + * handshake done). There are two failure modes: "usec" have passed (major + * hardware flakeout), or the register reads as all-ones (hardware removed). + * + * That last failure should_only happen in cases like physical cardbus eject + * before driver shutdown. But it also seems to be caused by bugs in cardbus + * bridge shutdown: shutting down the bridge before the devices using it. + */ +static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = fotg210_readl(fotg210, ptr); + if (result == ~(u32)0) /* card removed */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* + * Force HC to halt state from unknown (EHCI spec section 2.3). + * Must be called with interrupts enabled and the lock not held. + */ +static int fotg210_halt(struct fotg210_hcd *fotg210) +{ + u32 temp; + + spin_lock_irq(&fotg210->lock); + + /* disable any irqs left enabled by previous code */ + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + + /* + * This routine gets called during probe before fotg210->command + * has been initialized, so we can't rely on its value. + */ + fotg210->command &= ~CMD_RUN; + temp = fotg210_readl(fotg210, &fotg210->regs->command); + temp &= ~(CMD_RUN | CMD_IAAD); + fotg210_writel(fotg210, temp, &fotg210->regs->command); + + spin_unlock_irq(&fotg210->lock); + synchronize_irq(fotg210_to_hcd(fotg210)->irq); + + return handshake(fotg210, &fotg210->regs->status, + STS_HALT, STS_HALT, 16 * 125); +} + +/* + * Reset a non-running (STS_HALT == 1) controller. + * Must be called with interrupts enabled and the lock not held. + */ +static int fotg210_reset(struct fotg210_hcd *fotg210) +{ + int retval; + u32 command = fotg210_readl(fotg210, &fotg210->regs->command); + + /* If the EHCI debug controller is active, special care must be + * taken before and after a host controller reset */ + if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210))) + fotg210->debug = NULL; + + command |= CMD_RESET; + dbg_cmd(fotg210, "reset", command); + fotg210_writel(fotg210, command, &fotg210->regs->command); + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210->next_statechange = jiffies; + retval = handshake(fotg210, &fotg210->regs->command, + CMD_RESET, 0, 250 * 1000); + + if (retval) + return retval; + + if (fotg210->debug) + dbgp_external_startup(fotg210_to_hcd(fotg210)); + + fotg210->port_c_suspend = fotg210->suspended_ports = + fotg210->resuming_ports = 0; + return retval; +} + +/* + * Idle the controller (turn off the schedules). + * Must be called with interrupts enabled and the lock not held. + */ +static void fotg210_quiesce(struct fotg210_hcd *fotg210) +{ + u32 temp; + + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + /* wait for any schedule enables/disables to take effect */ + temp = (fotg210->command << 10) & (STS_ASS | STS_PSS); + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp, + 16 * 125); + + /* then disable anything that's still active */ + spin_lock_irq(&fotg210->lock); + fotg210->command &= ~(CMD_ASE | CMD_PSE); + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + spin_unlock_irq(&fotg210->lock); + + /* hardware can take 16 microframes to turn off ... */ + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0, + 16 * 125); +} + +/*-------------------------------------------------------------------------*/ + +static void end_unlink_async(struct fotg210_hcd *fotg210); +static void unlink_empty_async(struct fotg210_hcd *fotg210); +static void fotg210_work(struct fotg210_hcd *fotg210); +static void start_unlink_intr(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh); +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +/*-------------------------------------------------------------------------*/ + +/* Set a bit in the USBCMD register */ +static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit) +{ + fotg210->command |= bit; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + + /* unblock posted write */ + fotg210_readl(fotg210, &fotg210->regs->command); +} + +/* Clear a bit in the USBCMD register */ +static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit) +{ + fotg210->command &= ~bit; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + + /* unblock posted write */ + fotg210_readl(fotg210, &fotg210->regs->command); +} + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI timer support... Now using hrtimers. + * + * Lots of different events are triggered from fotg210->hrtimer. Whenever + * the timer routine runs, it checks each possible event; events that are + * currently enabled and whose expiration time has passed get handled. + * The set of enabled events is stored as a collection of bitflags in + * fotg210->enabled_hrtimer_events, and they are numbered in order of + * increasing delay values (ranging between 1 ms and 100 ms). + * + * Rather than implementing a sorted list or tree of all pending events, + * we keep track only of the lowest-numbered pending event, in + * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its + * expiration time is set to the timeout value for this event. + * + * As a result, events might not get handled right away; the actual delay + * could be anywhere up to twice the requested delay. This doesn't + * matter, because none of the events are especially time-critical. The + * ones that matter most all have a delay of 1 ms, so they will be + * handled after 2 ms at most, which is okay. In addition to this, we + * allow for an expiration range of 1 ms. + */ + +/* + * Delay lengths for the hrtimer event types. + * Keep this list sorted by delay length, in the same order as + * the event types indexed by enum fotg210_hrtimer_event in fotg210.h. + */ +static unsigned event_delays_ns[] = { + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */ + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */ + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */ + 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */ + 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */ + 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */ + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ + 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */ + 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */ +}; + +/* Enable a pending hrtimer event */ +static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event, + bool resched) +{ + ktime_t *timeout = &fotg210->hr_timeouts[event]; + + if (resched) + *timeout = ktime_add(ktime_get(), + ktime_set(0, event_delays_ns[event])); + fotg210->enabled_hrtimer_events |= (1 << event); + + /* Track only the lowest-numbered pending event */ + if (event < fotg210->next_hrtimer_event) { + fotg210->next_hrtimer_event = event; + hrtimer_start_range_ns(&fotg210->hrtimer, *timeout, + NSEC_PER_MSEC, HRTIMER_MODE_ABS); + } +} + + +/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ +static void fotg210_poll_ASS(struct fotg210_hcd *fotg210) +{ + unsigned actual, want; + + /* Don't enable anything if the controller isn't running (e.g., died) */ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + want = (fotg210->command & CMD_ASE) ? STS_ASS : 0; + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fotg210->ASS_poll_count++ < 20) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS, + true); + return; + } + fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n", + want, actual); + } + fotg210->ASS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fotg210->async_count > 0) + fotg210_set_command_bit(fotg210, CMD_ASE); + + } else { /* Running */ + if (fotg210->async_count == 0) { + + /* Turn off the schedule after a while */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_DISABLE_ASYNC, + true); + } + } +} + +/* Turn off the async schedule after a brief delay */ +static void fotg210_disable_ASE(struct fotg210_hcd *fotg210) +{ + fotg210_clear_command_bit(fotg210, CMD_ASE); +} + + +/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ +static void fotg210_poll_PSS(struct fotg210_hcd *fotg210) +{ + unsigned actual, want; + + /* Don't do anything if the controller isn't running (e.g., died) */ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + want = (fotg210->command & CMD_PSE) ? STS_PSS : 0; + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (fotg210->PSS_poll_count++ < 20) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS, + true); + return; + } + fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n", + want, actual); + } + fotg210->PSS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (fotg210->periodic_count > 0) + fotg210_set_command_bit(fotg210, CMD_PSE); + + } else { /* Running */ + if (fotg210->periodic_count == 0) { + + /* Turn off the schedule after a while */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_DISABLE_PERIODIC, + true); + } + } +} + +/* Turn off the periodic schedule after a brief delay */ +static void fotg210_disable_PSE(struct fotg210_hcd *fotg210) +{ + fotg210_clear_command_bit(fotg210, CMD_PSE); +} + + +/* Poll the STS_HALT status bit; see when a dead controller stops */ +static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210) +{ + if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) { + + /* Give up after a few milliseconds */ + if (fotg210->died_poll_count++ < 5) { + /* Try again later */ + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_POLL_DEAD, true); + return; + } + fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n"); + } + + /* Clean up the mess */ + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + fotg210_work(fotg210); + end_unlink_async(fotg210); + + /* Not in process context, so don't try to reset the controller */ +} + + +/* Handle unlinked interrupt QHs once they are gone from the hardware */ +static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210) +{ + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + fotg210->intr_unlinking = true; + while (fotg210->intr_unlink) { + struct fotg210_qh *qh = fotg210->intr_unlink; + + if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle) + break; + fotg210->intr_unlink = qh->unlink_next; + qh->unlink_next = NULL; + end_unlink_intr(fotg210, qh); + } + + /* Handle remaining entries later */ + if (fotg210->intr_unlink) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, + true); + ++fotg210->intr_unlink_cycle; + } + fotg210->intr_unlinking = false; +} + + +/* Start another free-iTDs/siTDs cycle */ +static void start_free_itds(struct fotg210_hcd *fotg210) +{ + if (!(fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_FREE_ITDS))) { + fotg210->last_itd_to_free = list_entry( + fotg210->cached_itd_list.prev, + struct fotg210_itd, itd_list); + fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true); + } +} + +/* Wait for controller to stop using old iTDs and siTDs */ +static void end_free_itds(struct fotg210_hcd *fotg210) +{ + struct fotg210_itd *itd, *n; + + if (fotg210->rh_state < FOTG210_RH_RUNNING) + fotg210->last_itd_to_free = NULL; + + list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) { + list_del(&itd->itd_list); + dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma); + if (itd == fotg210->last_itd_to_free) + break; + } + + if (!list_empty(&fotg210->cached_itd_list)) + start_free_itds(fotg210); +} + + +/* Handle lost (or very late) IAA interrupts */ +static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210) +{ + if (fotg210->rh_state != FOTG210_RH_RUNNING) + return; + + /* + * Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (fotg210->async_iaa) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = fotg210_readl(fotg210, &fotg210->regs->command); + + /* + * If IAA is set here it either legitimately triggered + * after the watchdog timer expired (_way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = fotg210_readl(fotg210, &fotg210->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { + COUNT(fotg210->stats.lost_iaa); + fotg210_writel(fotg210, STS_IAA, + &fotg210->regs->status); + } + + fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n", + status, cmd); + end_unlink_async(fotg210); + } +} + + +/* Enable the I/O watchdog, if appropriate */ +static void turn_on_io_watchdog(struct fotg210_hcd *fotg210) +{ + /* Not needed if the controller isn't running or it's already enabled */ + if (fotg210->rh_state != FOTG210_RH_RUNNING || + (fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_IO_WATCHDOG))) + return; + + /* + * Isochronous transfers always need the watchdog. + * For other sorts we use it only if the flag is set. + */ + if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog && + fotg210->async_count + fotg210->intr_count > 0)) + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG, + true); +} + + +/* + * Handler functions for the hrtimer event types. + * Keep this array in the same order as the event types indexed by + * enum fotg210_hrtimer_event in fotg210.h. + */ +static void (*event_handlers[])(struct fotg210_hcd *) = { + fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */ + fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */ + fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */ + fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */ + end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */ + unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */ + fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */ + fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */ + fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */ + fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */ +}; + +static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t) +{ + struct fotg210_hcd *fotg210 = + container_of(t, struct fotg210_hcd, hrtimer); + ktime_t now; + unsigned long events; + unsigned long flags; + unsigned e; + + spin_lock_irqsave(&fotg210->lock, flags); + + events = fotg210->enabled_hrtimer_events; + fotg210->enabled_hrtimer_events = 0; + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; + + /* + * Check each pending event. If its time has expired, handle + * the event; otherwise re-enable it. + */ + now = ktime_get(); + for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) { + if (now.tv64 >= fotg210->hr_timeouts[e].tv64) + event_handlers[e](fotg210); + else + fotg210_enable_event(fotg210, e, false); + } + + spin_unlock_irqrestore(&fotg210->lock, flags); + return HRTIMER_NORESTART; +} + +/*-------------------------------------------------------------------------*/ + +#define fotg210_bus_suspend NULL +#define fotg210_bus_resume NULL + +/*-------------------------------------------------------------------------*/ + +static int check_reset_complete( + struct fotg210_hcd *fotg210, + int index, + u32 __iomem *status_reg, + int port_status +) { + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + /* with integrated TT, there's nobody to hand it to! */ + fotg210_dbg(fotg210, + "Failed to enable port %d on root hub TT\n", + index+1); + return port_status; + } else { + fotg210_dbg(fotg210, "port %d reset complete, port enabled\n", + index + 1); + } + + return port_status; +} + +/*-------------------------------------------------------------------------*/ + + +/* build "status change" packet (one or two bytes) from HC registers */ + +static int +fotg210_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp, status; + u32 mask; + int retval = 1; + unsigned long flags; + + /* init status to no-changes */ + buf[0] = 0; + + /* Inform the core about resumes-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = fotg210->resuming_ports; + + mask = PORT_CSC | PORT_PEC; + /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */ + + /* no hub change reports (bit 0) for now (power, ...) */ + + /* port N changes (bit N)? */ + spin_lock_irqsave(&fotg210->lock, flags); + + temp = fotg210_readl(fotg210, &fotg210->regs->port_status); + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) + || (fotg210->reset_done[0] && time_after_eq( + jiffies, fotg210->reset_done[0]))) { + buf[0] |= 1 << 1; + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ + spin_unlock_irqrestore(&fotg210->lock, flags); + return status ? retval : 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +fotg210_hub_descriptor( + struct fotg210_hcd *fotg210, + struct usb_hub_descriptor *desc +) { + int ports = HCS_N_PORTS(fotg210->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */ + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); + + temp = 0x0008; /* per-port overcurrent reporting */ + temp |= 0x0002; /* no power switching */ + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +/*-------------------------------------------------------------------------*/ + +static int fotg210_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + int ports = HCS_N_PORTS(fotg210->hcs_params); + u32 __iomem *status_reg = &fotg210->regs->port_status; + u32 temp, temp1, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave(&fotg210->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fotg210_readl(fotg210, status_reg); + temp &= ~PORT_RWC_BITS; + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_STAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + fotg210_writel(fotg210, temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + fotg210_writel(fotg210, temp | PORT_PEC, status_reg); + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + if (!(temp & PORT_SUSPEND)) + break; + if ((temp & PORT_PE) == 0) + goto error; + + /* resume signaling for 20 msec */ + fotg210_writel(fotg210, temp | PORT_RESUME, status_reg); + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + break; + case USB_PORT_FEAT_C_SUSPEND: + clear_bit(wIndex, &fotg210->port_c_suspend); + break; + case USB_PORT_FEAT_C_CONNECTION: + fotg210_writel(fotg210, temp | PORT_CSC, status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + fotg210_writel(fotg210, temp | OTGISR_OVC, + &fotg210->regs->otgisr); + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + fotg210_readl(fotg210, &fotg210->regs->command); + break; + case GetHubDescriptor: + fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset(buf, 0, 4); + /*cpu_to_le32s ((u32 *) buf); */ + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = fotg210_readl(fotg210, status_reg); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= USB_PORT_STAT_C_CONNECTION << 16; + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); + if (temp1 & OTGISR_OVC) + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + + /* Remote Wakeup received? */ + if (!fotg210->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&fotg210_to_hcd(fotg210)->rh_timer, + fotg210->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + fotg210->reset_done[wIndex])) { + clear_bit(wIndex, &fotg210->suspended_ports); + set_bit(wIndex, &fotg210->port_c_suspend); + fotg210->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = fotg210_readl(fotg210, status_reg); + fotg210_writel(fotg210, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + clear_bit(wIndex, &fotg210->resuming_ports); + retval = handshake(fotg210, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + fotg210_err(fotg210, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + fotg210->reset_done[wIndex])) { + status |= USB_PORT_STAT_C_RESET << 16; + fotg210->reset_done[wIndex] = 0; + clear_bit(wIndex, &fotg210->resuming_ports); + + /* force reset to complete */ + fotg210_writel(fotg210, + temp & ~(PORT_RWC_BITS | PORT_RESET), + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(fotg210, status_reg, + PORT_RESET, 0, 1000); + if (retval != 0) { + fotg210_err(fotg210, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete(fotg210, wIndex, status_reg, + fotg210_readl(fotg210, status_reg)); + } + + if (!(temp & (PORT_RESUME|PORT_RESET))) { + fotg210->reset_done[wIndex] = 0; + clear_bit(wIndex, &fotg210->resuming_ports); + } + + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &fotg210->companion_ports)) { + temp &= ~PORT_RWC_BITS; + fotg210_writel(fotg210, temp, status_reg); + fotg210_dbg(fotg210, "port %d --> companion\n", + wIndex + 1); + temp = fotg210_readl(fotg210, status_reg); + } + + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= fotg210_port_speed(fotg210, temp); + } + if (temp & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + + /* maybe the port was unsuspended without our knowledge */ + if (temp & (PORT_SUSPEND|PORT_RESUME)) { + status |= USB_PORT_STAT_SUSPEND; + } else if (test_bit(wIndex, &fotg210->suspended_ports)) { + clear_bit(wIndex, &fotg210->suspended_ports); + clear_bit(wIndex, &fotg210->resuming_ports); + fotg210->reset_done[wIndex] = 0; + if (temp & PORT_PE) + set_bit(wIndex, &fotg210->port_c_suspend); + } + + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr); + if (temp1 & OTGISR_OVC) + status |= USB_PORT_STAT_OVERCURRENT; + if (temp & PORT_RESET) + status |= USB_PORT_STAT_RESET; + if (test_bit(wIndex, &fotg210->port_c_suspend)) + status |= USB_PORT_STAT_C_SUSPEND << 16; + +#ifndef VERBOSE_DEBUG + if (status & ~0xffff) /* only if wPortChange is interesting */ +#endif + dbg_port(fotg210, "GetStatus", wIndex + 1, temp); + put_unaligned_le32(status, buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = fotg210_readl(fotg210, status_reg); + temp &= ~PORT_RWC_BITS; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + /* After above check the port must be connected. + * Set appropriate bit thus could put phy into low power + * mode if we have hostpc feature + */ + fotg210_writel(fotg210, temp | PORT_SUSPEND, + status_reg); + set_bit(wIndex, &fotg210->suspended_ports); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1); + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + fotg210->reset_done[wIndex] = jiffies + + msecs_to_jiffies(50); + fotg210_writel(fotg210, temp, status_reg); + break; + + /* For downstream facing ports (these): one hub port is put + * into test mode according to USB2 11.24.2.13, then the hub + * must be reset (which for root hub now means rmmod+modprobe, + * or else system reboot). See EHCI 2.3.9 and 4.14 for info + * about the EHCI-specific stuff. + */ + case USB_PORT_FEAT_TEST: + if (!selector || selector > 5) + goto error; + spin_unlock_irqrestore(&fotg210->lock, flags); + fotg210_quiesce(fotg210); + spin_lock_irqsave(&fotg210->lock, flags); + + /* Put all enabled ports into suspend */ + temp = fotg210_readl(fotg210, status_reg) & + ~PORT_RWC_BITS; + if (temp & PORT_PE) + fotg210_writel(fotg210, temp | PORT_SUSPEND, + status_reg); + + spin_unlock_irqrestore(&fotg210->lock, flags); + fotg210_halt(fotg210); + spin_lock_irqsave(&fotg210->lock, flags); + + temp = fotg210_readl(fotg210, status_reg); + temp |= selector << 16; + fotg210_writel(fotg210, temp, status_reg); + break; + + default: + goto error; + } + fotg210_readl(fotg210, &fotg210->regs->command); + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&fotg210->lock, flags); + return retval; +} + +static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd, + int portnum) +{ + return; +} + +static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd, + int portnum) +{ + return 0; +} +/*-------------------------------------------------------------------------*/ +/* + * There's basically three types of memory: + * - data used only by the HCD ... kmalloc is fine + * - async and periodic schedules, shared by HC and HCD ... these + * need to use dma_pool or dma_alloc_coherent + * - driver buffers, read/written by HC ... single shot DMA mapped + * + * There's also "register" data (e.g. PCI or SOC), which is memory mapped. + * No memory seen by this driver is pageable. + */ + +/*-------------------------------------------------------------------------*/ + +/* Allocate the key transfer structures from the previously allocated pool */ + +static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210, + struct fotg210_qtd *qtd, dma_addr_t dma) +{ + memset(qtd, 0, sizeof(*qtd)); + qtd->qtd_dma = dma; + qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); + qtd->hw_next = FOTG210_LIST_END(fotg210); + qtd->hw_alt_next = FOTG210_LIST_END(fotg210); + INIT_LIST_HEAD(&qtd->qtd_list); +} + +static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210, + gfp_t flags) +{ + struct fotg210_qtd *qtd; + dma_addr_t dma; + + qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma); + if (qtd != NULL) + fotg210_qtd_init(fotg210, qtd, dma); + + return qtd; +} + +static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210, + struct fotg210_qtd *qtd) +{ + dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma); +} + + +static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + /* clean qtds first, and know this is not linked */ + if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) { + fotg210_dbg(fotg210, "unused qh not empty!\n"); + BUG(); + } + if (qh->dummy) + fotg210_qtd_free(fotg210, qh->dummy); + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); + kfree(qh); +} + +static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, + gfp_t flags) +{ + struct fotg210_qh *qh; + dma_addr_t dma; + + qh = kzalloc(sizeof(*qh), GFP_ATOMIC); + if (!qh) + goto done; + qh->hw = (struct fotg210_qh_hw *) + dma_pool_alloc(fotg210->qh_pool, flags, &dma); + if (!qh->hw) + goto fail; + memset(qh->hw, 0, sizeof(*qh->hw)); + qh->qh_dma = dma; + INIT_LIST_HEAD(&qh->qtd_list); + + /* dummy td enables safe urb queuing */ + qh->dummy = fotg210_qtd_alloc(fotg210, flags); + if (qh->dummy == NULL) { + fotg210_dbg(fotg210, "no dummy td\n"); + goto fail1; + } +done: + return qh; +fail1: + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma); +fail: + kfree(qh); + return NULL; +} + +/*-------------------------------------------------------------------------*/ + +/* The queue heads and transfer descriptors are managed from pools tied + * to each of the "per device" structures. + * This is the initialisation and cleanup code. + */ + +static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210) +{ + if (fotg210->async) + qh_destroy(fotg210, fotg210->async); + fotg210->async = NULL; + + if (fotg210->dummy) + qh_destroy(fotg210, fotg210->dummy); + fotg210->dummy = NULL; + + /* DMA consistent memory and pools */ + if (fotg210->qtd_pool) + dma_pool_destroy(fotg210->qtd_pool); + fotg210->qtd_pool = NULL; + + if (fotg210->qh_pool) { + dma_pool_destroy(fotg210->qh_pool); + fotg210->qh_pool = NULL; + } + + if (fotg210->itd_pool) + dma_pool_destroy(fotg210->itd_pool); + fotg210->itd_pool = NULL; + + if (fotg210->periodic) + dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller, + fotg210->periodic_size * sizeof(u32), + fotg210->periodic, fotg210->periodic_dma); + fotg210->periodic = NULL; + + /* shadow periodic table */ + kfree(fotg210->pshadow); + fotg210->pshadow = NULL; +} + +/* remember to add cleanup code (above) if you add anything here */ +static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags) +{ + int i; + + /* QTDs for control/bulk/intr transfers */ + fotg210->qtd_pool = dma_pool_create("fotg210_qtd", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_qtd), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->qtd_pool) + goto fail; + + /* QHs for control/bulk/intr transfers */ + fotg210->qh_pool = dma_pool_create("fotg210_qh", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_qh_hw), + 32 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->qh_pool) + goto fail; + + fotg210->async = fotg210_qh_alloc(fotg210, flags); + if (!fotg210->async) + goto fail; + + /* ITD for high speed ISO transfers */ + fotg210->itd_pool = dma_pool_create("fotg210_itd", + fotg210_to_hcd(fotg210)->self.controller, + sizeof(struct fotg210_itd), + 64 /* byte alignment (for hw parts) */, + 4096 /* can't cross 4K */); + if (!fotg210->itd_pool) + goto fail; + + /* Hardware periodic table */ + fotg210->periodic = (__le32 *) + dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller, + fotg210->periodic_size * sizeof(__le32), + &fotg210->periodic_dma, 0); + if (fotg210->periodic == NULL) + goto fail; + + for (i = 0; i < fotg210->periodic_size; i++) + fotg210->periodic[i] = FOTG210_LIST_END(fotg210); + + /* software shadow of hardware table */ + fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *), + flags); + if (fotg210->pshadow != NULL) + return 0; + +fail: + fotg210_dbg(fotg210, "couldn't init memory\n"); + fotg210_mem_cleanup(fotg210); + return -ENOMEM; +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI hardware queue manipulation ... the core. QH/QTD manipulation. + * + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned + * buffers needed for the larger number). We use one QH per endpoint, queue + * multiple urbs (all three types) per endpoint. URBs may need several qtds. + * + * ISO traffic uses "ISO TD" (itd) records, and (along with + * interrupts) needs careful scheduling. Performance improvements can be + * an ongoing challenge. That's in "ehci-sched.c". + * + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using + * (b) special fields in qh entries or (c) split iso entries. TTs will + * buffer low/full speed data so the host collects it at high speed. + */ + +/*-------------------------------------------------------------------------*/ + +/* fill a qtd, returning how much of the buffer we were able to queue up */ + +static int +qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf, + size_t len, int token, int maxpacket) +{ + int i, count; + u64 addr = buf; + + /* one buffer entry per 4K ... first might be short or unaligned */ + qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr); + qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32)); + count = 0x1000 - (buf & 0x0fff); /* rest of that page */ + if (likely(len < count)) /* ... iff needed */ + count = len; + else { + buf += 0x1000; + buf &= ~0x0fff; + + /* per-qtd limit: from 16K to 20K (best alignment) */ + for (i = 1; count < len && i < 5; i++) { + addr = buf; + qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr); + qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210, + (u32)(addr >> 32)); + buf += 0x1000; + if ((count + 0x1000) < len) + count += 0x1000; + else + count = len; + } + + /* short packets may only terminate transfers */ + if (count != len) + count -= (count % maxpacket); + } + qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token); + qtd->length = count; + + return count; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh, + struct fotg210_qtd *qtd) +{ + struct fotg210_qh_hw *hw = qh->hw; + + /* writes to an active overlay are unsafe */ + BUG_ON(qh->qh_state != QH_STATE_IDLE); + + hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma); + hw->hw_alt_next = FOTG210_LIST_END(fotg210); + + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) { + unsigned is_out, epnum; + + is_out = qh->is_out; + epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f; + if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) { + hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE); + usb_settoggle(qh->dev, epnum, is_out, 1); + } + } + + hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING); +} + +/* if it weren't for a common silicon quirk (writing the dummy into the qh + * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault + * recovery (including urb dequeue) would need software changes to a QH... + */ +static void +qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qtd *qtd; + + if (list_empty(&qh->qtd_list)) + qtd = qh->dummy; + else { + qtd = list_entry(qh->qtd_list.next, + struct fotg210_qtd, qtd_list); + /* + * first qtd may already be partially processed. + * If we come here during unlink, the QH overlay region + * might have reference to the just unlinked qtd. The + * qtd is updated in qh_completions(). Update the QH + * overlay here. + */ + if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) { + qh->hw->hw_qtd_next = qtd->hw_next; + qtd = NULL; + } + } + + if (qtd) + qh_update(fotg210, qh, qtd); +} + +/*-------------------------------------------------------------------------*/ + +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh = ep->hcpriv; + unsigned long flags; + + spin_lock_irqsave(&fotg210->lock, flags); + qh->clearing_tt = 0; + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) + && fotg210->rh_state == FOTG210_RH_RUNNING) + qh_link_async(fotg210, qh); + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh, + struct urb *urb, u32 token) +{ + + /* If an async split transaction gets an error or is unlinked, + * the TT buffer may be left in an indeterminate state. We + * have to clear the TT buffer. + * + * Note: this routine is never called for Isochronous transfers. + */ + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { +#ifdef DEBUG + struct usb_device *tt = urb->dev->tt->hub; + dev_dbg(&tt->dev, + "clear tt buffer port %d, a%d ep%d t%08x\n", + urb->dev->ttport, urb->dev->devnum, + usb_pipeendpoint(urb->pipe), token); +#endif /* DEBUG */ + if (urb->dev->tt->hub != + fotg210_to_hcd(fotg210)->self.root_hub) { + if (usb_hub_clear_tt_buffer(urb) == 0) + qh->clearing_tt = 1; + } + } +} + +static int qtd_copy_status( + struct fotg210_hcd *fotg210, + struct urb *urb, + size_t length, + u32 token +) +{ + int status = -EINPROGRESS; + + /* count IN/OUT bytes, not SETUP (even short packets) */ + if (likely(QTD_PID(token) != 2)) + urb->actual_length += length - QTD_LENGTH(token); + + /* don't modify error codes */ + if (unlikely(urb->unlinked)) + return status; + + /* force cleanup after short read; not always an error */ + if (unlikely(IS_SHORT_READ(token))) + status = -EREMOTEIO; + + /* serious "can't proceed" faults reported by the hardware */ + if (token & QTD_STS_HALT) { + if (token & QTD_STS_BABBLE) { + /* FIXME "must" disable babbling device's port too */ + status = -EOVERFLOW; + /* CERR nonzero + halt --> stall */ + } else if (QTD_CERR(token)) { + status = -EPIPE; + + /* In theory, more than one of the following bits can be set + * since they are sticky and the transaction is retried. + * Which to test first is rather arbitrary. + */ + } else if (token & QTD_STS_MMF) { + /* fs/ls interrupt xfer missed the complete-split */ + status = -EPROTO; + } else if (token & QTD_STS_DBE) { + status = (QTD_PID(token) == 1) /* IN ? */ + ? -ENOSR /* hc couldn't read data */ + : -ECOMM; /* hc couldn't write data */ + } else if (token & QTD_STS_XACT) { + /* timeout, bad CRC, wrong PID, etc */ + fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n", + urb->dev->devpath, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out"); + status = -EPROTO; + } else { /* unknown */ + status = -EPROTO; + } + + fotg210_vdbg(fotg210, + "dev%d ep%d%s qtd token %08x --> status %d\n", + usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + token, status); + } + + return status; +} + +static void +fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status) +__releases(fotg210->lock) +__acquires(fotg210->lock) +{ + if (likely(urb->hcpriv != NULL)) { + struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv; + + /* S-mask in a QH means it's an interrupt urb */ + if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) { + + /* ... update hc-wide periodic stats (for usbfs) */ + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--; + } + } + + if (unlikely(urb->unlinked)) { + COUNT(fotg210->stats.unlink); + } else { + /* report non-error and short read status as zero */ + if (status == -EINPROGRESS || status == -EREMOTEIO) + status = 0; + COUNT(fotg210->stats.complete); + } + +#ifdef FOTG210_URB_TRACE + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s status %d len %d/%d\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + status, + urb->actual_length, urb->transfer_buffer_length); +#endif + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + spin_unlock(&fotg210->lock); + usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status); + spin_lock(&fotg210->lock); +} + +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh); + +/* + * Process and free completed qtds for a qh, returning URBs to drivers. + * Chases up to qh->hw_current. Returns number of completions called, + * indicating how much "real" work we did. + */ +static unsigned +qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qtd *last, *end = qh->dummy; + struct list_head *entry, *tmp; + int last_status; + int stopped; + unsigned count = 0; + u8 state; + struct fotg210_qh_hw *hw = qh->hw; + + if (unlikely(list_empty(&qh->qtd_list))) + return count; + + /* completions (or tasks on other cpus) must never clobber HALT + * till we've gone through and cleaned everything up, even when + * they add urbs to this qh's queue or mark them for unlinking. + * + * NOTE: unlinking expects to be done in queue order. + * + * It's a bug for qh->qh_state to be anything other than + * QH_STATE_IDLE, unless our caller is scan_async() or + * scan_intr(). + */ + state = qh->qh_state; + qh->qh_state = QH_STATE_COMPLETING; + stopped = (state == QH_STATE_IDLE); + + rescan: + last = NULL; + last_status = -EINPROGRESS; + qh->needs_rescan = 0; + + /* remove de-activated QTDs from front of queue. + * after faults (including short reads), cleanup this urb + * then let the queue advance. + * if queue is stopped, handles unlinks. + */ + list_for_each_safe(entry, tmp, &qh->qtd_list) { + struct fotg210_qtd *qtd; + struct urb *urb; + u32 token = 0; + + qtd = list_entry(entry, struct fotg210_qtd, qtd_list); + urb = qtd->urb; + + /* clean up any state from previous QTD ...*/ + if (last) { + if (likely(last->urb != urb)) { + fotg210_urb_done(fotg210, last->urb, + last_status); + count++; + last_status = -EINPROGRESS; + } + fotg210_qtd_free(fotg210, last); + last = NULL; + } + + /* ignore urbs submitted during completions we reported */ + if (qtd == end) + break; + + /* hardware copies qtd out of qh overlay */ + rmb(); + token = hc32_to_cpu(fotg210, qtd->hw_token); + + /* always clean up qtds the hc de-activated */ + retry_xacterr: + if ((token & QTD_STS_ACTIVE) == 0) { + + /* Report Data Buffer Error: non-fatal but useful */ + if (token & QTD_STS_DBE) + fotg210_dbg(fotg210, + "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", + urb, + usb_endpoint_num(&urb->ep->desc), + usb_endpoint_dir_in(&urb->ep->desc) + ? "in" : "out", + urb->transfer_buffer_length, + qtd, + qh); + + /* on STALL, error, and short reads this urb must + * complete and all its qtds must be recycled. + */ + if ((token & QTD_STS_HALT) != 0) { + + /* retry transaction errors until we + * reach the software xacterr limit + */ + if ((token & QTD_STS_XACT) && + QTD_CERR(token) == 0 && + ++qh->xacterrs < QH_XACTERR_MAX && + !urb->unlinked) { + fotg210_dbg(fotg210, + "detected XactErr len %zu/%zu retry %d\n", + qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); + + /* reset the token in the qtd and the + * qh overlay (which still contains + * the qtd) so that we pick up from + * where we left off + */ + token &= ~QTD_STS_HALT; + token |= QTD_STS_ACTIVE | + (FOTG210_TUNE_CERR << 10); + qtd->hw_token = cpu_to_hc32(fotg210, + token); + wmb(); + hw->hw_token = cpu_to_hc32(fotg210, + token); + goto retry_xacterr; + } + stopped = 1; + + /* magic dummy for some short reads; qh won't advance. + * that silicon quirk can kick in with this dummy too. + * + * other short reads won't stop the queue, including + * control transfers (status stage handles that) or + * most other single-qtd reads ... the queue stops if + * URB_SHORT_NOT_OK was set so the driver submitting + * the urbs could clean it up. + */ + } else if (IS_SHORT_READ(token) + && !(qtd->hw_alt_next + & FOTG210_LIST_END(fotg210))) { + stopped = 1; + } + + /* stop scanning when we reach qtds the hc is using */ + } else if (likely(!stopped + && fotg210->rh_state >= FOTG210_RH_RUNNING)) { + break; + + /* scan the whole queue for unlinks whenever it stops */ + } else { + stopped = 1; + + /* cancel everything if we halt, suspend, etc */ + if (fotg210->rh_state < FOTG210_RH_RUNNING) + last_status = -ESHUTDOWN; + + /* this qtd is active; skip it unless a previous qtd + * for its urb faulted, or its urb was canceled. + */ + else if (last_status == -EINPROGRESS && !urb->unlinked) + continue; + + /* qh unlinked; token in overlay may be most current */ + if (state == QH_STATE_IDLE + && cpu_to_hc32(fotg210, qtd->qtd_dma) + == hw->hw_current) { + token = hc32_to_cpu(fotg210, hw->hw_token); + + /* An unlink may leave an incomplete + * async transaction in the TT buffer. + * We have to clear it. + */ + fotg210_clear_tt_buffer(fotg210, qh, urb, + token); + } + } + + /* unless we already know the urb's status, collect qtd status + * and update count of bytes transferred. in common short read + * cases with only one data qtd (including control transfers), + * queue processing won't halt. but with two or more qtds (for + * example, with a 32 KB transfer), when the first qtd gets a + * short read the second must be removed by hand. + */ + if (last_status == -EINPROGRESS) { + last_status = qtd_copy_status(fotg210, urb, + qtd->length, token); + if (last_status == -EREMOTEIO + && (qtd->hw_alt_next + & FOTG210_LIST_END(fotg210))) + last_status = -EINPROGRESS; + + /* As part of low/full-speed endpoint-halt processing + * we must clear the TT buffer (11.17.5). + */ + if (unlikely(last_status != -EINPROGRESS && + last_status != -EREMOTEIO)) { + /* The TT's in some hubs malfunction when they + * receive this request following a STALL (they + * stop sending isochronous packets). Since a + * STALL can't leave the TT buffer in a busy + * state (if you believe Figures 11-48 - 11-51 + * in the USB 2.0 spec), we won't clear the TT + * buffer in this case. Strictly speaking this + * is a violation of the spec. + */ + if (last_status != -EPIPE) + fotg210_clear_tt_buffer(fotg210, qh, + urb, token); + } + } + + /* if we're removing something not at the queue head, + * patch the hardware queue pointer. + */ + if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { + last = list_entry(qtd->qtd_list.prev, + struct fotg210_qtd, qtd_list); + last->hw_next = qtd->hw_next; + } + + /* remove qtd; it's recycled after possible urb completion */ + list_del(&qtd->qtd_list); + last = qtd; + + /* reinit the xacterr counter for the next qtd */ + qh->xacterrs = 0; + } + + /* last urb's completion might still need calling */ + if (likely(last != NULL)) { + fotg210_urb_done(fotg210, last->urb, last_status); + count++; + fotg210_qtd_free(fotg210, last); + } + + /* Do we need to rescan for URBs dequeued during a giveback? */ + if (unlikely(qh->needs_rescan)) { + /* If the QH is already unlinked, do the rescan now. */ + if (state == QH_STATE_IDLE) + goto rescan; + + /* Otherwise we have to wait until the QH is fully unlinked. + * Our caller will start an unlink if qh->needs_rescan is + * set. But if an unlink has already started, nothing needs + * to be done. + */ + if (state != QH_STATE_LINKED) + qh->needs_rescan = 0; + } + + /* restore original state; caller must unlink or relink */ + qh->qh_state = state; + + /* be sure the hardware's done with the qh before refreshing + * it after fault cleanup, or recovering from silicon wrongly + * overlaying the dummy qtd (which reduces DMA chatter). + */ + if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) { + switch (state) { + case QH_STATE_IDLE: + qh_refresh(fotg210, qh); + break; + case QH_STATE_LINKED: + /* We won't refresh a QH that's linked (after the HC + * stopped the queue). That avoids a race: + * - HC reads first part of QH; + * - CPU updates that first part and the token; + * - HC reads rest of that QH, including token + * Result: HC gets an inconsistent image, and then + * DMAs to/from the wrong memory (corrupting it). + * + * That should be rare for interrupt transfers, + * except maybe high bandwidth ... + */ + + /* Tell the caller to start an unlink */ + qh->needs_rescan = 1; + break; + /* otherwise, unlink already started */ + } + } + + return count; +} + +/*-------------------------------------------------------------------------*/ + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) +/* ... and packet size, for any kind of endpoint descriptor */ +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) + +/* + * reverse of qh_urb_transaction: free a list of TDs. + * used for cleanup after errors, before HC sees an URB's TDs. + */ +static void qtd_list_free( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list +) { + struct list_head *entry, *temp; + + list_for_each_safe(entry, temp, qtd_list) { + struct fotg210_qtd *qtd; + + qtd = list_entry(entry, struct fotg210_qtd, qtd_list); + list_del(&qtd->qtd_list); + fotg210_qtd_free(fotg210, qtd); + } +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head * +qh_urb_transaction( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *head, + gfp_t flags +) { + struct fotg210_qtd *qtd, *qtd_prev; + dma_addr_t buf; + int len, this_sg_len, maxpacket; + int is_input; + u32 token; + int i; + struct scatterlist *sg; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + return NULL; + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + + token = QTD_STS_ACTIVE; + token |= (FOTG210_TUNE_CERR << 10); + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein(urb->pipe); + if (usb_pipecontrol(urb->pipe)) { + /* SETUP pid */ + qtd_fill(fotg210, qtd, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + token | (2 /* "setup" */ << 8), 8); + + /* ... and always at least one more pid */ + token ^= QTD_TOGGLE; + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= (1 /* "in" */ << 8); + } + + /* + * data transfer stage: buffer setup + */ + i = urb->num_mapped_sgs; + if (len > 0 && i > 0) { + sg = urb->sg; + buf = sg_dma_address(sg); + + /* urb->transfer_buffer_length may be smaller than the + * size of the scatterlist (or vice versa) + */ + this_sg_len = min_t(int, sg_dma_len(sg), len); + } else { + sg = NULL; + buf = urb->transfer_dma; + this_sg_len = len; + } + + if (is_input) + token |= (1 /* "in" */ << 8); + /* else it's already initted to "out" pid (0 << 8) */ + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token, + maxpacket); + this_sg_len -= this_qtd_len; + len -= this_qtd_len; + buf += this_qtd_len; + + /* + * short reads advance to a "magic" dummy instead of the next + * qtd ... that forces the queue to stop, for manual cleanup. + * (this will usually be overridden later.) + */ + if (is_input) + qtd->hw_alt_next = fotg210->async->hw->hw_alt_next; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= QTD_TOGGLE; + + if (likely(this_sg_len <= 0)) { + if (--i <= 0 || len <= 0) + break; + sg = sg_next(sg); + buf = sg_dma_address(sg); + this_sg_len = min_t(int, sg_dma_len(sg), len); + } + + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + } + + /* + * unless the caller requires manual cleanup after short reads, + * have the alt_next mechanism keep the queue running after the + * last data qtd (the only one, for control and most other cases). + */ + if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 + || usb_pipecontrol(urb->pipe))) + qtd->hw_alt_next = FOTG210_LIST_END(fotg210); + + /* + * control requests may need a terminating data "status" ack; + * other OUT ones may need a terminating short packet + * (zero length). + */ + if (likely(urb->transfer_buffer_length != 0)) { + int one_more = 0; + + if (usb_pipecontrol(urb->pipe)) { + one_more = 1; + token ^= 0x0100; /* "in" <--> "out" */ + token |= QTD_TOGGLE; /* force DATA1 */ + } else if (usb_pipeout(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = fotg210_qtd_alloc(fotg210, flags); + if (unlikely(!qtd)) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma); + list_add_tail(&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(fotg210, qtd, 0, 0, token, 0); + } + } + + /* by default, enable interrupt on urb completion */ + if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) + qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC); + return head; + +cleanup: + qtd_list_free(fotg210, urb, head); + return NULL; +} + +/*-------------------------------------------------------------------------*/ +/* + * Would be best to create all qh's from config descriptors, + * when each interface/altsetting is established. Unlink + * any previous qh and cancel its urbs first; endpoints are + * implicitly reset then (data toggle too). + * That'd mean updating how usbcore talks to HCDs. (2.7?) +*/ + + +/* + * Each QH holds a qtd list; a QH is used for everything except iso. + * + * For interrupt urbs, the scheduler must set the microframe scheduling + * mask(s) each time the QH gets scheduled. For highspeed, that's + * just one microframe in the s-mask. For split interrupt transactions + * there are additional complications: c-mask, maybe FSTNs. + */ +static struct fotg210_qh * +qh_make( + struct fotg210_hcd *fotg210, + struct urb *urb, + gfp_t flags +) { + struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags); + u32 info1 = 0, info2 = 0; + int is_input, type; + int maxp = 0; + struct usb_tt *tt = urb->dev->tt; + struct fotg210_qh_hw *hw; + + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + info1 |= usb_pipeendpoint(urb->pipe) << 8; + info1 |= usb_pipedevice(urb->pipe) << 0; + + is_input = usb_pipein(urb->pipe); + type = usb_pipetype(urb->pipe); + maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input); + + /* 1024 byte maxpacket is a hardware ceiling. High bandwidth + * acts like up to 3KB, but is built from smaller packets. + */ + if (max_packet(maxp) > 1024) { + fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", + max_packet(maxp)); + goto done; + } + + /* Compute interrupt scheduling parameters just once, and save. + * - allowing for high bandwidth, how many nsec/uframe are used? + * - split transactions need a second CSPLIT uframe; same question + * - splits also need a schedule gap (for full/low speed I/O) + * - qh has a polling interval + * + * For control/bulk requests, the HC or TT handles these. + */ + if (type == PIPE_INTERRUPT) { + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, + is_input, 0, + hb_mult(maxp) * max_packet(maxp))); + qh->start = NO_FRAME; + + if (urb->dev->speed == USB_SPEED_HIGH) { + qh->c_usecs = 0; + qh->gap_uf = 0; + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + urb->interval = 1; + } else if (qh->period > fotg210->periodic_size) { + qh->period = fotg210->periodic_size; + urb->interval = qh->period << 3; + } + } else { + int think_time; + + /* gap is f(FS/LS transfer times) */ + qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, + is_input, 0, maxp) / (125 * 1000); + + /* FIXME this just approximates SPLIT/CSPLIT times */ + if (is_input) { /* SPLIT, gap, CSPLIT+DATA */ + qh->c_usecs = qh->usecs + HS_USECS(0); + qh->usecs = HS_USECS(1); + } else { /* SPLIT+DATA, gap, CSPLIT */ + qh->usecs += HS_USECS(1); + qh->c_usecs = HS_USECS(0); + } + + think_time = tt ? tt->think_time : 0; + qh->tt_usecs = NS_TO_US(think_time + + usb_calc_bus_time(urb->dev->speed, + is_input, 0, max_packet(maxp))); + qh->period = urb->interval; + if (qh->period > fotg210->periodic_size) { + qh->period = fotg210->periodic_size; + urb->interval = qh->period; + } + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + /* using TT? */ + switch (urb->dev->speed) { + case USB_SPEED_LOW: + info1 |= QH_LOW_SPEED; + /* FALL THROUGH */ + + case USB_SPEED_FULL: + /* EPS 0 means "full" */ + if (type != PIPE_INTERRUPT) + info1 |= (FOTG210_TUNE_RL_TT << 28); + if (type == PIPE_CONTROL) { + info1 |= QH_CONTROL_EP; /* for TT */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + } + info1 |= maxp << 16; + + info2 |= (FOTG210_TUNE_MULT_TT << 30); + + /* Some Freescale processors have an erratum in which the + * port number in the queue head was 0..N-1 instead of 1..N. + */ + if (fotg210_has_fsl_portno_bug(fotg210)) + info2 |= (urb->dev->ttport-1) << 23; + else + info2 |= urb->dev->ttport << 23; + + /* set the address of the TT; for TDI's integrated + * root hub tt, leave it zeroed. + */ + if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub) + info2 |= tt->hub->devnum << 16; + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ + + break; + + case USB_SPEED_HIGH: /* no TT involved */ + info1 |= QH_HIGH_SPEED; + if (type == PIPE_CONTROL) { + info1 |= (FOTG210_TUNE_RL_HS << 28); + info1 |= 64 << 16; /* usb2 fixed maxpacket */ + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */ + info2 |= (FOTG210_TUNE_MULT_HS << 30); + } else if (type == PIPE_BULK) { + info1 |= (FOTG210_TUNE_RL_HS << 28); + /* The USB spec says that high speed bulk endpoints + * always use 512 byte maxpacket. But some device + * vendors decided to ignore that, and MSFT is happy + * to help them do so. So now people expect to use + * such nonconformant devices with Linux too; sigh. + */ + info1 |= max_packet(maxp) << 16; + info2 |= (FOTG210_TUNE_MULT_HS << 30); + } else { /* PIPE_INTERRUPT */ + info1 |= max_packet(maxp) << 16; + info2 |= hb_mult(maxp) << 30; + } + break; + default: + fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev, + urb->dev->speed); +done: + qh_destroy(fotg210, qh); + return NULL; + } + + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ + + /* init as live, toggle clear, advance to dummy */ + qh->qh_state = QH_STATE_IDLE; + hw = qh->hw; + hw->hw_info1 = cpu_to_hc32(fotg210, info1); + hw->hw_info2 = cpu_to_hc32(fotg210, info2); + qh->is_out = !is_input; + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1); + qh_refresh(fotg210, qh); + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_async(struct fotg210_hcd *fotg210) +{ + if (fotg210->async_count++) + return; + + /* Stop waiting to turn off the async schedule */ + fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC); + + /* Don't start the schedule until ASS is 0 */ + fotg210_poll_ASS(fotg210); + turn_on_io_watchdog(fotg210); +} + +static void disable_async(struct fotg210_hcd *fotg210) +{ + if (--fotg210->async_count) + return; + + /* The async schedule and async_unlink list are supposed to be empty */ + WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink); + + /* Don't turn off the schedule until ASS is 1 */ + fotg210_poll_ASS(fotg210); +} + +/* move qh (and its qtds) onto async queue; maybe enable queue. */ + +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + __hc32 dma = QH_NEXT(fotg210, qh->qh_dma); + struct fotg210_qh *head; + + /* Don't link a QH if there's a Clear-TT-Buffer pending */ + if (unlikely(qh->clearing_tt)) + return; + + WARN_ON(qh->qh_state != QH_STATE_IDLE); + + /* clear halt and/or toggle; and maybe recover from silicon quirk */ + qh_refresh(fotg210, qh); + + /* splice right after start */ + head = fotg210->async; + qh->qh_next = head->qh_next; + qh->hw->hw_next = head->hw->hw_next; + wmb(); + + head->qh_next.qh = qh; + head->hw->hw_next = dma; + + qh->xacterrs = 0; + qh->qh_state = QH_STATE_LINKED; + /* qtd completions reported later by interrupt */ + + enable_async(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct fotg210_qh *qh_append_tds( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + int epnum, + void **ptr +) +{ + struct fotg210_qh *qh = NULL; + __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f); + + qh = (struct fotg210_qh *) *ptr; + if (unlikely(qh == NULL)) { + /* can't sleep here, we have fotg210->lock... */ + qh = qh_make(fotg210, urb, GFP_ATOMIC); + *ptr = qh; + } + if (likely(qh != NULL)) { + struct fotg210_qtd *qtd; + + if (unlikely(list_empty(qtd_list))) + qtd = NULL; + else + qtd = list_entry(qtd_list->next, struct fotg210_qtd, + qtd_list); + + /* control qh may need patching ... */ + if (unlikely(epnum == 0)) { + /* usb_reset_device() briefly reverts to address 0 */ + if (usb_pipedevice(urb->pipe) == 0) + qh->hw->hw_info1 &= ~qh_addr_mask; + } + + /* just one way to queue requests: swap with the dummy qtd. + * only hc or qh_refresh() ever modify the overlay. + */ + if (likely(qtd != NULL)) { + struct fotg210_qtd *dummy; + dma_addr_t dma; + __hc32 token; + + /* to avoid racing the HC, use the dummy td instead of + * the first td of our list (becomes new dummy). both + * tds stay deactivated until we're done, when the + * HC is allowed to fetch the old dummy (4.10.2). + */ + token = qtd->hw_token; + qtd->hw_token = HALT_BIT(fotg210); + + dummy = qh->dummy; + + dma = dummy->qtd_dma; + *dummy = *qtd; + dummy->qtd_dma = dma; + + list_del(&qtd->qtd_list); + list_add(&dummy->qtd_list, qtd_list); + list_splice_tail(qtd_list, &qh->qtd_list); + + fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma); + qh->dummy = qtd; + + /* hc must see the new dummy at list end */ + dma = qtd->qtd_dma; + qtd = list_entry(qh->qtd_list.prev, + struct fotg210_qtd, qtd_list); + qtd->hw_next = QTD_NEXT(fotg210, dma); + + /* let the hc process these next qtds */ + wmb(); + dummy->hw_token = token; + + urb->hcpriv = qh; + } + } + return qh; +} + +/*-------------------------------------------------------------------------*/ + +static int +submit_async( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + int epnum; + unsigned long flags; + struct fotg210_qh *qh = NULL; + int rc; + + epnum = urb->ep->desc.bEndpointAddress; + +#ifdef FOTG210_URB_TRACE + { + struct fotg210_qtd *qtd; + qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list); + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", + __func__, urb->dev->devpath, urb, + epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", + urb->transfer_buffer_length, + qtd, urb->ep->hcpriv); + } +#endif + + spin_lock_irqsave(&fotg210->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(rc)) + goto done; + + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (unlikely(qh == NULL)) { + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + rc = -ENOMEM; + goto done; + } + + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely(qh->qh_state == QH_STATE_IDLE)) + qh_link_async(fotg210, qh); + done: + spin_unlock_irqrestore(&fotg210->lock, flags); + if (unlikely(qh == NULL)) + qtd_list_free(fotg210, urb, qtd_list); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +static void single_unlink_async(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + struct fotg210_qh *prev; + + /* Add to the end of the list of QHs waiting for the next IAAD */ + qh->qh_state = QH_STATE_UNLINK; + if (fotg210->async_unlink) + fotg210->async_unlink_last->unlink_next = qh; + else + fotg210->async_unlink = qh; + fotg210->async_unlink_last = qh; + + /* Unlink it from the schedule */ + prev = fotg210->async; + while (prev->qh_next.qh != qh) + prev = prev->qh_next.qh; + + prev->hw->hw_next = qh->hw->hw_next; + prev->qh_next = qh->qh_next; + if (fotg210->qh_scan_next == qh) + fotg210->qh_scan_next = qh->qh_next.qh; +} + +static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested) +{ + /* + * Do nothing if an IAA cycle is already running or + * if one will be started shortly. + */ + if (fotg210->async_iaa || fotg210->async_unlinking) + return; + + /* Do all the waiting QHs at once */ + fotg210->async_iaa = fotg210->async_unlink; + fotg210->async_unlink = NULL; + + /* If the controller isn't running, we don't have to wait for it */ + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) { + if (!nested) /* Avoid recursion */ + end_unlink_async(fotg210); + + /* Otherwise start a new IAA cycle */ + } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) { + /* Make sure the unlinks are all visible to the hardware */ + wmb(); + + fotg210_writel(fotg210, fotg210->command | CMD_IAAD, + &fotg210->regs->command); + fotg210_readl(fotg210, &fotg210->regs->command); + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG, + true); + } +} + +/* the async qh for the qtds being unlinked are now gone from the HC */ + +static void end_unlink_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + + /* Process the idle QHs */ + restart: + fotg210->async_unlinking = true; + while (fotg210->async_iaa) { + qh = fotg210->async_iaa; + fotg210->async_iaa = qh->unlink_next; + qh->unlink_next = NULL; + + qh->qh_state = QH_STATE_IDLE; + qh->qh_next.qh = NULL; + + qh_completions(fotg210, qh); + if (!list_empty(&qh->qtd_list) && + fotg210->rh_state == FOTG210_RH_RUNNING) + qh_link_async(fotg210, qh); + disable_async(fotg210); + } + fotg210->async_unlinking = false; + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fotg210->async_unlink) { + start_iaa_cycle(fotg210, true); + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) + goto restart; + } +} + +static void unlink_empty_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh, *next; + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING); + bool check_unlinks_later = false; + + /* Unlink all the async QHs that have been empty for a timer cycle */ + next = fotg210->async->qh_next.qh; + while (next) { + qh = next; + next = qh->qh_next.qh; + + if (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED) { + if (!stopped && qh->unlink_cycle == + fotg210->async_unlink_cycle) + check_unlinks_later = true; + else + single_unlink_async(fotg210, qh); + } + } + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (fotg210->async_unlink) + start_iaa_cycle(fotg210, false); + + /* QHs that haven't been empty for long enough will be handled later */ + if (check_unlinks_later) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS, + true); + ++fotg210->async_unlink_cycle; + } +} + +/* makes sure the async qh will become idle */ +/* caller must own fotg210->lock */ + +static void start_unlink_async(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + /* + * If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + single_unlink_async(fotg210, qh); + start_iaa_cycle(fotg210, false); +} + +/*-------------------------------------------------------------------------*/ + +static void scan_async(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + bool check_unlinks_later = false; + + fotg210->qh_scan_next = fotg210->async->qh_next.qh; + while (fotg210->qh_scan_next) { + qh = fotg210->qh_scan_next; + fotg210->qh_scan_next = qh->qh_next.qh; + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fotg210->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fotg210->qh_scan_next is adjusted + * in single_unlink_async(). + */ + temp = qh_completions(fotg210, qh); + if (qh->needs_rescan) { + start_unlink_async(fotg210, qh); + } else if (list_empty(&qh->qtd_list) + && qh->qh_state == QH_STATE_LINKED) { + qh->unlink_cycle = fotg210->async_unlink_cycle; + check_unlinks_later = true; + } else if (temp != 0) + goto rescan; + } + } + + /* + * Unlink empty entries, reducing DMA usage as well + * as HCD schedule-scanning costs. Delay for any qh + * we just scanned, there's a not-unusual case that it + * doesn't stay idle for long. + */ + if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING && + !(fotg210->enabled_hrtimer_events & + BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) { + fotg210_enable_event(fotg210, + FOTG210_HRTIMER_ASYNC_UNLINKS, true); + ++fotg210->async_unlink_cycle; + } +} +/*-------------------------------------------------------------------------*/ +/* + * EHCI scheduled transaction support: interrupt, iso, split iso + * These are called "periodic" transactions in the EHCI spec. + * + * Note that for interrupt transfers, the QH/QTD manipulation is shared + * with the "asynchronous" transaction support (control/bulk transfers). + * The only real difference is in how interrupt transfers are scheduled. + * + * For ISO, we make an "iso_stream" head to serve the same role as a QH. + * It keeps track of every ITD (or SITD) that's linked, and holds enough + * pre-calculated schedule data to make appending to the queue be quick. + */ + +static int fotg210_get_frame(struct usb_hcd *hcd); + +/*-------------------------------------------------------------------------*/ + +/* + * periodic_next_shadow - return "next" pointer on shadow list + * @periodic: host pointer to qh/itd + * @tag: hardware tag for type of this record + */ +static union fotg210_shadow * +periodic_next_shadow(struct fotg210_hcd *fotg210, + union fotg210_shadow *periodic, __hc32 tag) +{ + switch (hc32_to_cpu(fotg210, tag)) { + case Q_TYPE_QH: + return &periodic->qh->qh_next; + case Q_TYPE_FSTN: + return &periodic->fstn->fstn_next; + default: + return &periodic->itd->itd_next; + } +} + +static __hc32 * +shadow_next_periodic(struct fotg210_hcd *fotg210, + union fotg210_shadow *periodic, __hc32 tag) +{ + switch (hc32_to_cpu(fotg210, tag)) { + /* our fotg210_shadow.qh is actually software part */ + case Q_TYPE_QH: + return &periodic->qh->hw->hw_next; + /* others are hw parts */ + default: + return periodic->hw_next; + } +} + +/* caller must hold fotg210->lock */ +static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame, + void *ptr) +{ + union fotg210_shadow *prev_p = &fotg210->pshadow[frame]; + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow here = *prev_p; + + /* find predecessor of "ptr"; hw and shadow lists are in sync */ + while (here.ptr && here.ptr != ptr) { + prev_p = periodic_next_shadow(fotg210, prev_p, + Q_NEXT_TYPE(fotg210, *hw_p)); + hw_p = shadow_next_periodic(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); + here = *prev_p; + } + /* an interrupt entry (at list end) could have been shared */ + if (!here.ptr) + return; + + /* update shadow and hardware lists ... the old "next" pointers + * from ptr may still be in use, the caller updates them. + */ + *prev_p = *periodic_next_shadow(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); + + *hw_p = *shadow_next_periodic(fotg210, &here, + Q_NEXT_TYPE(fotg210, *hw_p)); +} + +/* how many of the uframe's 125 usecs are allocated? */ +static unsigned short +periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe) +{ + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow *q = &fotg210->pshadow[frame]; + unsigned usecs = 0; + struct fotg210_qh_hw *hw; + + while (q->ptr) { + switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) { + case Q_TYPE_QH: + hw = q->qh->hw; + /* is it in the S-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe)) + usecs += q->qh->usecs; + /* ... or C-mask? */ + if (hw->hw_info2 & cpu_to_hc32(fotg210, + 1 << (8 + uframe))) + usecs += q->qh->c_usecs; + hw_p = &hw->hw_next; + q = &q->qh->qh_next; + break; + /* case Q_TYPE_FSTN: */ + default: + /* for "save place" FSTNs, count the relevant INTR + * bandwidth from the previous frame + */ + if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210)) + fotg210_dbg(fotg210, "ignoring FSTN cost ...\n"); + + hw_p = &q->fstn->hw_next; + q = &q->fstn->fstn_next; + break; + case Q_TYPE_ITD: + if (q->itd->hw_transaction[uframe]) + usecs += q->itd->stream->usecs; + hw_p = &q->itd->hw_next; + q = &q->itd->itd_next; + break; + } + } +#ifdef DEBUG + if (usecs > fotg210->uframe_periodic_max) + fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n", + frame * 8 + uframe, usecs); +#endif + return usecs; +} + +/*-------------------------------------------------------------------------*/ + +static int same_tt(struct usb_device *dev1, struct usb_device *dev2) +{ + if (!dev1->tt || !dev2->tt) + return 0; + if (dev1->tt != dev2->tt) + return 0; + if (dev1->tt->multi) + return dev1->ttport == dev2->ttport; + else + return 1; +} + +/* return true iff the device's transaction translator is available + * for a periodic transfer starting at the specified frame, using + * all the uframes in the mask. + */ +static int tt_no_collision( + struct fotg210_hcd *fotg210, + unsigned period, + struct usb_device *dev, + unsigned frame, + u32 uf_mask +) +{ + if (period == 0) /* error */ + return 0; + + /* note bandwidth wastage: split never follows csplit + * (different dev or endpoint) until the next uframe. + * calling convention doesn't make that distinction. + */ + for (; frame < fotg210->periodic_size; frame += period) { + union fotg210_shadow here; + __hc32 type; + struct fotg210_qh_hw *hw; + + here = fotg210->pshadow[frame]; + type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]); + while (here.ptr) { + switch (hc32_to_cpu(fotg210, type)) { + case Q_TYPE_ITD: + type = Q_NEXT_TYPE(fotg210, here.itd->hw_next); + here = here.itd->itd_next; + continue; + case Q_TYPE_QH: + hw = here.qh->hw; + if (same_tt(dev, here.qh->dev)) { + u32 mask; + + mask = hc32_to_cpu(fotg210, + hw->hw_info2); + /* "knows" no gap is needed */ + mask |= mask >> 8; + if (mask & uf_mask) + break; + } + type = Q_NEXT_TYPE(fotg210, hw->hw_next); + here = here.qh->qh_next; + continue; + /* case Q_TYPE_FSTN: */ + default: + fotg210_dbg(fotg210, + "periodic frame %d bogus type %d\n", + frame, type); + } + + /* collision or error */ + return 0; + } + } + + /* no collision */ + return 1; +} + +/*-------------------------------------------------------------------------*/ + +static void enable_periodic(struct fotg210_hcd *fotg210) +{ + if (fotg210->periodic_count++) + return; + + /* Stop waiting to turn off the periodic schedule */ + fotg210->enabled_hrtimer_events &= + ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC); + + /* Don't start the schedule until PSS is 0 */ + fotg210_poll_PSS(fotg210); + turn_on_io_watchdog(fotg210); +} + +static void disable_periodic(struct fotg210_hcd *fotg210) +{ + if (--fotg210->periodic_count) + return; + + /* Don't turn off the schedule until PSS is 1 */ + fotg210_poll_PSS(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +/* periodic schedule slots have iso tds (normal or split) first, then a + * sparse tree for active interrupt transfers. + * + * this just links in a qh; caller guarantees uframe masks are set right. + * no FSTN support (yet; fotg210 0.96+) + */ +static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + unsigned i; + unsigned period = qh->period; + + dev_dbg(&qh->dev->dev, + "link qh%d-%04x/%p start %d [%d/%d us]\n", + period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) + & (QH_CMASK | QH_SMASK), + qh, qh->start, qh->usecs, qh->c_usecs); + + /* high bandwidth, or otherwise every microframe */ + if (period == 0) + period = 1; + + for (i = qh->start; i < fotg210->periodic_size; i += period) { + union fotg210_shadow *prev = &fotg210->pshadow[i]; + __hc32 *hw_p = &fotg210->periodic[i]; + union fotg210_shadow here = *prev; + __hc32 type = 0; + + /* skip the iso nodes at list head */ + while (here.ptr) { + type = Q_NEXT_TYPE(fotg210, *hw_p); + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fotg210, prev, type); + hw_p = shadow_next_periodic(fotg210, &here, type); + here = *prev; + } + + /* sorting each branch by period (slow-->fast) + * enables sharing interior tree nodes + */ + while (here.ptr && qh != here.qh) { + if (qh->period > here.qh->period) + break; + prev = &here.qh->qh_next; + hw_p = &here.qh->hw->hw_next; + here = *prev; + } + /* link in this qh, unless some earlier pass did that */ + if (qh != here.qh) { + qh->qh_next = here; + if (here.qh) + qh->hw->hw_next = *hw_p; + wmb(); + prev->qh = qh; + *hw_p = QH_NEXT(fotg210, qh->qh_dma); + } + } + qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; + + /* update per-qh bandwidth for usbfs */ + fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + list_add(&qh->intr_node, &fotg210->intr_qh_list); + + /* maybe enable periodic schedule processing */ + ++fotg210->intr_count; + enable_periodic(fotg210); +} + +static void qh_unlink_periodic(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + unsigned i; + unsigned period; + + /* + * If qh is for a low/full-speed device, simply unlinking it + * could interfere with an ongoing split transaction. To unlink + * it safely would require setting the QH_INACTIVATE bit and + * waiting at least one frame, as described in EHCI 4.12.2.5. + * + * We won't bother with any of this. Instead, we assume that the + * only reason for unlinking an interrupt QH while the current URB + * is still active is to dequeue all the URBs (flush the whole + * endpoint queue). + * + * If rebalancing the periodic schedule is ever implemented, this + * approach will no longer be valid. + */ + + /* high bandwidth, or otherwise part of every microframe */ + period = qh->period; + if (!period) + period = 1; + + for (i = qh->start; i < fotg210->periodic_size; i += period) + periodic_unlink(fotg210, i, qh); + + /* update per-qh bandwidth for usbfs */ + fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period + ? ((qh->usecs + qh->c_usecs) / qh->period) + : (qh->usecs * 8); + + dev_dbg(&qh->dev->dev, + "unlink qh%d-%04x/%p start %d [%d/%d us]\n", + qh->period, + hc32_to_cpup(fotg210, &qh->hw->hw_info2) & + (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs); + + /* qh->qh_next still "live" to HC */ + qh->qh_state = QH_STATE_UNLINK; + qh->qh_next.ptr = NULL; + + if (fotg210->qh_scan_next == qh) + fotg210->qh_scan_next = list_entry(qh->intr_node.next, + struct fotg210_qh, intr_node); + list_del(&qh->intr_node); +} + +static void start_unlink_intr(struct fotg210_hcd *fotg210, + struct fotg210_qh *qh) +{ + /* If the QH isn't linked then there's nothing we can do + * unless we were called during a giveback, in which case + * qh_completions() has to deal with it. + */ + if (qh->qh_state != QH_STATE_LINKED) { + if (qh->qh_state == QH_STATE_COMPLETING) + qh->needs_rescan = 1; + return; + } + + qh_unlink_periodic(fotg210, qh); + + /* Make sure the unlinks are visible before starting the timer */ + wmb(); + + /* + * The EHCI spec doesn't say how long it takes the controller to + * stop accessing an unlinked interrupt QH. The timer delay is + * 9 uframes; presumably that will be long enough. + */ + qh->unlink_cycle = fotg210->intr_unlink_cycle; + + /* New entries go at the end of the intr_unlink list */ + if (fotg210->intr_unlink) + fotg210->intr_unlink_last->unlink_next = qh; + else + fotg210->intr_unlink = qh; + fotg210->intr_unlink_last = qh; + + if (fotg210->intr_unlinking) + ; /* Avoid recursive calls */ + else if (fotg210->rh_state < FOTG210_RH_RUNNING) + fotg210_handle_intr_unlinks(fotg210); + else if (fotg210->intr_unlink == qh) { + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR, + true); + ++fotg210->intr_unlink_cycle; + } +} + +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + struct fotg210_qh_hw *hw = qh->hw; + int rc; + + qh->qh_state = QH_STATE_IDLE; + hw->hw_next = FOTG210_LIST_END(fotg210); + + qh_completions(fotg210, qh); + + /* reschedule QH iff another request is queued */ + if (!list_empty(&qh->qtd_list) && + fotg210->rh_state == FOTG210_RH_RUNNING) { + rc = qh_schedule(fotg210, qh); + + /* An error here likely indicates handshake failure + * or no space left in the schedule. Neither fault + * should happen often ... + * + * FIXME kill the now-dysfunctional queued urbs + */ + if (rc != 0) + fotg210_err(fotg210, "can't reschedule qh %p, err %d\n", + qh, rc); + } + + /* maybe turn off periodic schedule */ + --fotg210->intr_count; + disable_periodic(fotg210); +} + +/*-------------------------------------------------------------------------*/ + +static int check_period( + struct fotg210_hcd *fotg210, + unsigned frame, + unsigned uframe, + unsigned period, + unsigned usecs +) { + int claimed; + + /* complete split running into next frame? + * given FSTN support, we could sometimes check... + */ + if (uframe >= 8) + return 0; + + /* convert "usecs we need" to "max already claimed" */ + usecs = fotg210->uframe_periodic_max - usecs; + + /* we "know" 2 and 4 uframe intervals were rejected; so + * for period 0, check _every_ microframe in the schedule. + */ + if (unlikely(period == 0)) { + do { + for (uframe = 0; uframe < 7; uframe++) { + claimed = periodic_usecs(fotg210, frame, + uframe); + if (claimed > usecs) + return 0; + } + } while ((frame += 1) < fotg210->periodic_size); + + /* just check the specified uframe, at that period */ + } else { + do { + claimed = periodic_usecs(fotg210, frame, uframe); + if (claimed > usecs) + return 0; + } while ((frame += period) < fotg210->periodic_size); + } + + /* success! */ + return 1; +} + +static int check_intr_schedule( + struct fotg210_hcd *fotg210, + unsigned frame, + unsigned uframe, + const struct fotg210_qh *qh, + __hc32 *c_maskp +) +{ + int retval = -ENOSPC; + u8 mask = 0; + + if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ + goto done; + + if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs)) + goto done; + if (!qh->c_usecs) { + retval = 0; + *c_maskp = 0; + goto done; + } + + /* Make sure this tt's buffer is also available for CSPLITs. + * We pessimize a bit; probably the typical full speed case + * doesn't need the second CSPLIT. + * + * NOTE: both SPLIT and CSPLIT could be checked in just + * one smart pass... + */ + mask = 0x03 << (uframe + qh->gap_uf); + *c_maskp = cpu_to_hc32(fotg210, mask << 8); + + mask |= 1 << uframe; + if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) { + if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1, + qh->period, qh->c_usecs)) + goto done; + if (!check_period(fotg210, frame, uframe + qh->gap_uf, + qh->period, qh->c_usecs)) + goto done; + retval = 0; + } +done: + return retval; +} + +/* "first fit" scheduling policy used the first time through, + * or when the previous schedule slot can't be re-used. + */ +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh) +{ + int status; + unsigned uframe; + __hc32 c_mask; + unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + struct fotg210_qh_hw *hw = qh->hw; + + qh_refresh(fotg210, qh); + hw->hw_next = FOTG210_LIST_END(fotg210); + frame = qh->start; + + /* reuse the previous schedule slots, if we can */ + if (frame < qh->period) { + uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK); + status = check_intr_schedule(fotg210, frame, --uframe, + qh, &c_mask); + } else { + uframe = 0; + c_mask = 0; + status = -ENOSPC; + } + + /* else scan the schedule to find a group of slots such that all + * uframes have enough periodic bandwidth available. + */ + if (status) { + /* "normal" case, uframing flexible except with splits */ + if (qh->period) { + int i; + + for (i = qh->period; status && i > 0; --i) { + frame = ++fotg210->random_frame % qh->period; + for (uframe = 0; uframe < 8; uframe++) { + status = check_intr_schedule(fotg210, + frame, uframe, qh, + &c_mask); + if (status == 0) + break; + } + } + + /* qh->period == 0 means every uframe */ + } else { + frame = 0; + status = check_intr_schedule(fotg210, 0, 0, qh, + &c_mask); + } + if (status) + goto done; + qh->start = frame; + + /* reset S-frame and (maybe) C-frame masks */ + hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK)); + hw->hw_info2 |= qh->period + ? cpu_to_hc32(fotg210, 1 << uframe) + : cpu_to_hc32(fotg210, QH_SMASK); + hw->hw_info2 |= c_mask; + } else + fotg210_dbg(fotg210, "reused qh %p schedule\n", qh); + + /* stuff into the periodic schedule */ + qh_link_periodic(fotg210, qh); +done: + return status; +} + +static int intr_submit( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct list_head *qtd_list, + gfp_t mem_flags +) { + unsigned epnum; + unsigned long flags; + struct fotg210_qh *qh; + int status; + struct list_head empty; + + /* get endpoint and transfer/schedule data */ + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave(&fotg210->lock, flags); + + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(status)) + goto done_not_linked; + + /* get qh and force any scheduling errors */ + INIT_LIST_HEAD(&empty); + qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv); + if (qh == NULL) { + status = -ENOMEM; + goto done; + } + if (qh->qh_state == QH_STATE_IDLE) { + status = qh_schedule(fotg210, qh); + if (status) + goto done; + } + + /* then queue the urb's tds to the qh */ + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv); + BUG_ON(qh == NULL); + + /* ... update usbfs periodic stats */ + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++; + +done: + if (unlikely(status)) + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); +done_not_linked: + spin_unlock_irqrestore(&fotg210->lock, flags); + if (status) + qtd_list_free(fotg210, urb, qtd_list); + + return status; +} + +static void scan_intr(struct fotg210_hcd *fotg210) +{ + struct fotg210_qh *qh; + + list_for_each_entry_safe(qh, fotg210->qh_scan_next, + &fotg210->intr_qh_list, intr_node) { + rescan: + /* clean any finished work for this qh */ + if (!list_empty(&qh->qtd_list)) { + int temp; + + /* + * Unlinks could happen here; completion reporting + * drops the lock. That's why fotg210->qh_scan_next + * always holds the next qh to scan; if the next qh + * gets unlinked then fotg210->qh_scan_next is adjusted + * in qh_unlink_periodic(). + */ + temp = qh_completions(fotg210, qh); + if (unlikely(qh->needs_rescan || + (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED))) + start_unlink_intr(fotg210, qh); + else if (temp != 0) + goto rescan; + } + } +} + +/*-------------------------------------------------------------------------*/ + +/* fotg210_iso_stream ops work with both ITD and SITD */ + +static struct fotg210_iso_stream * +iso_stream_alloc(gfp_t mem_flags) +{ + struct fotg210_iso_stream *stream; + + stream = kzalloc(sizeof(*stream), mem_flags); + if (likely(stream != NULL)) { + INIT_LIST_HEAD(&stream->td_list); + INIT_LIST_HEAD(&stream->free_list); + stream->next_uframe = -1; + } + return stream; +} + +static void +iso_stream_init( + struct fotg210_hcd *fotg210, + struct fotg210_iso_stream *stream, + struct usb_device *dev, + int pipe, + unsigned interval +) +{ + u32 buf1; + unsigned epnum, maxp; + int is_input; + long bandwidth; + unsigned multi; + + /* + * this might be a "high bandwidth" highspeed endpoint, + * as encoded in the ep descriptor's wMaxPacket field + */ + epnum = usb_pipeendpoint(pipe); + is_input = usb_pipein(pipe) ? USB_DIR_IN : 0; + maxp = usb_maxpacket(dev, pipe, !is_input); + if (is_input) + buf1 = (1 << 11); + else + buf1 = 0; + + maxp = max_packet(maxp); + multi = hb_mult(maxp); + buf1 |= maxp; + maxp *= multi; + + stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum); + stream->buf1 = cpu_to_hc32(fotg210, buf1); + stream->buf2 = cpu_to_hc32(fotg210, multi); + + /* usbfs wants to report the average usecs per frame tied up + * when transfers on this endpoint are scheduled ... + */ + if (dev->speed == USB_SPEED_FULL) { + interval <<= 3; + stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed, + is_input, 1, maxp)); + stream->usecs /= 8; + } else { + stream->highspeed = 1; + stream->usecs = HS_USECS_ISO(maxp); + } + bandwidth = stream->usecs * 8; + bandwidth /= interval; + + stream->bandwidth = bandwidth; + stream->udev = dev; + stream->bEndpointAddress = is_input | epnum; + stream->interval = interval; + stream->maxp = maxp; +} + +static struct fotg210_iso_stream * +iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb) +{ + unsigned epnum; + struct fotg210_iso_stream *stream; + struct usb_host_endpoint *ep; + unsigned long flags; + + epnum = usb_pipeendpoint(urb->pipe); + if (usb_pipein(urb->pipe)) + ep = urb->dev->ep_in[epnum]; + else + ep = urb->dev->ep_out[epnum]; + + spin_lock_irqsave(&fotg210->lock, flags); + stream = ep->hcpriv; + + if (unlikely(stream == NULL)) { + stream = iso_stream_alloc(GFP_ATOMIC); + if (likely(stream != NULL)) { + ep->hcpriv = stream; + stream->ep = ep; + iso_stream_init(fotg210, stream, urb->dev, urb->pipe, + urb->interval); + } + + /* if dev->ep[epnum] is a QH, hw is set */ + } else if (unlikely(stream->hw != NULL)) { + fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n", + urb->dev->devpath, epnum, + usb_pipein(urb->pipe) ? "in" : "out"); + stream = NULL; + } + + spin_unlock_irqrestore(&fotg210->lock, flags); + return stream; +} + +/*-------------------------------------------------------------------------*/ + +/* fotg210_iso_sched ops can be ITD-only or SITD-only */ + +static struct fotg210_iso_sched * +iso_sched_alloc(unsigned packets, gfp_t mem_flags) +{ + struct fotg210_iso_sched *iso_sched; + int size = sizeof(*iso_sched); + + size += packets * sizeof(struct fotg210_iso_packet); + iso_sched = kzalloc(size, mem_flags); + if (likely(iso_sched != NULL)) + INIT_LIST_HEAD(&iso_sched->td_list); + + return iso_sched; +} + +static inline void +itd_sched_init( + struct fotg210_hcd *fotg210, + struct fotg210_iso_sched *iso_sched, + struct fotg210_iso_stream *stream, + struct urb *urb +) +{ + unsigned i; + dma_addr_t dma = urb->transfer_dma; + + /* how many uframes are needed for these transfers */ + iso_sched->span = urb->number_of_packets * stream->interval; + + /* figure out per-uframe itd fields that we'll need later + * when we fit new itds into the schedule. + */ + for (i = 0; i < urb->number_of_packets; i++) { + struct fotg210_iso_packet *uframe = &iso_sched->packet[i]; + unsigned length; + dma_addr_t buf; + u32 trans; + + length = urb->iso_frame_desc[i].length; + buf = dma + urb->iso_frame_desc[i].offset; + + trans = FOTG210_ISOC_ACTIVE; + trans |= buf & 0x0fff; + if (unlikely(((i + 1) == urb->number_of_packets)) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) + trans |= FOTG210_ITD_IOC; + trans |= length << 16; + uframe->transaction = cpu_to_hc32(fotg210, trans); + + /* might need to cross a buffer page within a uframe */ + uframe->bufp = (buf & ~(u64)0x0fff); + buf += length; + if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff)))) + uframe->cross = 1; + } +} + +static void +iso_sched_free( + struct fotg210_iso_stream *stream, + struct fotg210_iso_sched *iso_sched +) +{ + if (!iso_sched) + return; + /* caller must hold fotg210->lock!*/ + list_splice(&iso_sched->td_list, &stream->free_list); + kfree(iso_sched); +} + +static int +itd_urb_transaction( + struct fotg210_iso_stream *stream, + struct fotg210_hcd *fotg210, + struct urb *urb, + gfp_t mem_flags +) +{ + struct fotg210_itd *itd; + dma_addr_t itd_dma; + int i; + unsigned num_itds; + struct fotg210_iso_sched *sched; + unsigned long flags; + + sched = iso_sched_alloc(urb->number_of_packets, mem_flags); + if (unlikely(sched == NULL)) + return -ENOMEM; + + itd_sched_init(fotg210, sched, stream, urb); + + if (urb->interval < 8) + num_itds = 1 + (sched->span + 7) / 8; + else + num_itds = urb->number_of_packets; + + /* allocate/init ITDs */ + spin_lock_irqsave(&fotg210->lock, flags); + for (i = 0; i < num_itds; i++) { + + /* + * Use iTDs from the free list, but not iTDs that may + * still be in use by the hardware. + */ + if (likely(!list_empty(&stream->free_list))) { + itd = list_first_entry(&stream->free_list, + struct fotg210_itd, itd_list); + if (itd->frame == fotg210->now_frame) + goto alloc_itd; + list_del(&itd->itd_list); + itd_dma = itd->itd_dma; + } else { + alloc_itd: + spin_unlock_irqrestore(&fotg210->lock, flags); + itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, + &itd_dma); + spin_lock_irqsave(&fotg210->lock, flags); + if (!itd) { + iso_sched_free(stream, sched); + spin_unlock_irqrestore(&fotg210->lock, flags); + return -ENOMEM; + } + } + + memset(itd, 0, sizeof(*itd)); + itd->itd_dma = itd_dma; + list_add(&itd->itd_list, &sched->td_list); + } + spin_unlock_irqrestore(&fotg210->lock, flags); + + /* temporarily store schedule info in hcpriv */ + urb->hcpriv = sched; + urb->error_count = 0; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static inline int +itd_slot_ok( + struct fotg210_hcd *fotg210, + u32 mod, + u32 uframe, + u8 usecs, + u32 period +) +{ + uframe %= period; + do { + /* can't commit more than uframe_periodic_max usec */ + if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7) + > (fotg210->uframe_periodic_max - usecs)) + return 0; + + /* we know urb->interval is 2^N uframes */ + uframe += period; + } while (uframe < mod); + return 1; +} + +/* + * This scheduler plans almost as far into the future as it has actual + * periodic schedule slots. (Affected by TUNE_FLS, which defaults to + * "as small as possible" to be cache-friendlier.) That limits the size + * transfers you can stream reliably; avoid more than 64 msec per urb. + * Also avoid queue depths of less than fotg210's worst irq latency (affected + * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, + * and other factors); or more than about 230 msec total (for portability, + * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler! + */ + +#define SCHEDULE_SLOP 80 /* microframes */ + +static int +iso_stream_schedule( + struct fotg210_hcd *fotg210, + struct urb *urb, + struct fotg210_iso_stream *stream +) +{ + u32 now, next, start, period, span; + int status; + unsigned mod = fotg210->periodic_size << 3; + struct fotg210_iso_sched *sched = urb->hcpriv; + + period = urb->interval; + span = sched->span; + + if (span > mod - SCHEDULE_SLOP) { + fotg210_dbg(fotg210, "iso request %p too long\n", urb); + status = -EFBIG; + goto fail; + } + + now = fotg210_read_frame_index(fotg210) & (mod - 1); + + /* Typical case: reuse current schedule, stream is still active. + * Hopefully there are no gaps from the host falling behind + * (irq delays etc), but if there are we'll take the next + * slot in the schedule, implicitly assuming URB_ISO_ASAP. + */ + if (likely(!list_empty(&stream->td_list))) { + u32 excess; + + /* For high speed devices, allow scheduling within the + * isochronous scheduling threshold. For full speed devices + * and Intel PCI-based controllers, don't (work around for + * Intel ICH9 bug). + */ + if (!stream->highspeed && fotg210->fs_i_thresh) + next = now + fotg210->i_thresh; + else + next = now; + + /* Fell behind (by up to twice the slop amount)? + * We decide based on the time of the last currently-scheduled + * slot, not the time of the next available slot. + */ + excess = (stream->next_uframe - period - next) & (mod - 1); + if (excess >= mod - 2 * SCHEDULE_SLOP) + start = next + excess - mod + period * + DIV_ROUND_UP(mod - excess, period); + else + start = next + excess + period; + if (start - now >= mod) { + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now - period, period, + mod); + status = -EFBIG; + goto fail; + } + } + + /* need to schedule; when's the next (u)frame we could start? + * this is bigger than fotg210->i_thresh allows; scheduling itself + * isn't free, the slop should handle reasonably slow cpus. it + * can also help high bandwidth if the dma and irq loads don't + * jump until after the queue is primed. + */ + else { + int done = 0; + start = SCHEDULE_SLOP + (now & ~0x07); + + /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ + + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; + /* check schedule: enough space? */ + if (itd_slot_ok(fotg210, mod, start, + stream->usecs, period)) + done = 1; + } while (start > next && !done); + + /* no room in the schedule */ + if (!done) { + fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n", + urb, now, now + mod); + status = -ENOSPC; + goto fail; + } + } + + /* Tried to schedule too far into the future? */ + if (unlikely(start - now + span - period + >= mod - 2 * SCHEDULE_SLOP)) { + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n", + urb, start - now, span - period, + mod - 2 * SCHEDULE_SLOP); + status = -EFBIG; + goto fail; + } + + stream->next_uframe = start & (mod - 1); + + /* report high speed start in uframes; full speed, in frames */ + urb->start_frame = stream->next_uframe; + if (!stream->highspeed) + urb->start_frame >>= 3; + + /* Make sure scan_isoc() sees these */ + if (fotg210->isoc_count == 0) + fotg210->next_frame = now >> 3; + return 0; + + fail: + iso_sched_free(stream, sched); + urb->hcpriv = NULL; + return status; +} + +/*-------------------------------------------------------------------------*/ + +static inline void +itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream, + struct fotg210_itd *itd) +{ + int i; + + /* it's been recently zeroed */ + itd->hw_next = FOTG210_LIST_END(fotg210); + itd->hw_bufp[0] = stream->buf0; + itd->hw_bufp[1] = stream->buf1; + itd->hw_bufp[2] = stream->buf2; + + for (i = 0; i < 8; i++) + itd->index[i] = -1; + + /* All other fields are filled when scheduling */ +} + +static inline void +itd_patch( + struct fotg210_hcd *fotg210, + struct fotg210_itd *itd, + struct fotg210_iso_sched *iso_sched, + unsigned index, + u16 uframe +) +{ + struct fotg210_iso_packet *uf = &iso_sched->packet[index]; + unsigned pg = itd->pg; + + uframe &= 0x07; + itd->index[uframe] = index; + + itd->hw_transaction[uframe] = uf->transaction; + itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12); + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32)); + + /* iso_frame_desc[].offset must be strictly increasing */ + if (unlikely(uf->cross)) { + u64 bufp = uf->bufp + 4096; + + itd->pg = ++pg; + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0); + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32)); + } +} + +static inline void +itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd) +{ + union fotg210_shadow *prev = &fotg210->pshadow[frame]; + __hc32 *hw_p = &fotg210->periodic[frame]; + union fotg210_shadow here = *prev; + __hc32 type = 0; + + /* skip any iso nodes which might belong to previous microframes */ + while (here.ptr) { + type = Q_NEXT_TYPE(fotg210, *hw_p); + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(fotg210, prev, type); + hw_p = shadow_next_periodic(fotg210, &here, type); + here = *prev; + } + + itd->itd_next = here; + itd->hw_next = *hw_p; + prev->itd = itd; + itd->frame = frame; + wmb(); + *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD); +} + +/* fit urb's itds into the selected schedule slot; activate as needed */ +static void itd_link_urb( + struct fotg210_hcd *fotg210, + struct urb *urb, + unsigned mod, + struct fotg210_iso_stream *stream +) +{ + int packet; + unsigned next_uframe, uframe, frame; + struct fotg210_iso_sched *iso_sched = urb->hcpriv; + struct fotg210_itd *itd; + + next_uframe = stream->next_uframe & (mod - 1); + + if (unlikely(list_empty(&stream->td_list))) { + fotg210_to_hcd(fotg210)->self.bandwidth_allocated + += stream->bandwidth; + fotg210_vdbg(fotg210, + "schedule devp %s ep%d%s-iso period %d start %d.%d\n", + urb->dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + urb->interval, + next_uframe >> 3, next_uframe & 0x7); + } + + /* fill iTDs uframe by uframe */ + for (packet = 0, itd = NULL; packet < urb->number_of_packets;) { + if (itd == NULL) { + /* ASSERT: we have all necessary itds */ + + /* ASSERT: no itds for this endpoint in this uframe */ + + itd = list_entry(iso_sched->td_list.next, + struct fotg210_itd, itd_list); + list_move_tail(&itd->itd_list, &stream->td_list); + itd->stream = stream; + itd->urb = urb; + itd_init(fotg210, stream, itd); + } + + uframe = next_uframe & 0x07; + frame = next_uframe >> 3; + + itd_patch(fotg210, itd, iso_sched, packet, uframe); + + next_uframe += stream->interval; + next_uframe &= mod - 1; + packet++; + + /* link completed itds into the schedule */ + if (((next_uframe >> 3) != frame) + || packet == urb->number_of_packets) { + itd_link(fotg210, frame & (fotg210->periodic_size - 1), + itd); + itd = NULL; + } + } + stream->next_uframe = next_uframe; + + /* don't need that schedule data any more */ + iso_sched_free(stream, iso_sched); + urb->hcpriv = NULL; + + ++fotg210->isoc_count; + enable_periodic(fotg210); +} + +#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\ + FOTG210_ISOC_XACTERR) + +/* Process and recycle a completed ITD. Return true iff its urb completed, + * and hence its completion callback probably added things to the hardware + * schedule. + * + * Note that we carefully avoid recycling this descriptor until after any + * completion callback runs, so that it won't be reused quickly. That is, + * assuming (a) no more than two urbs per frame on this endpoint, and also + * (b) only this endpoint's completions submit URBs. It seems some silicon + * corrupts things if you reuse completed descriptors very quickly... + */ +static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd) +{ + struct urb *urb = itd->urb; + struct usb_iso_packet_descriptor *desc; + u32 t; + unsigned uframe; + int urb_index = -1; + struct fotg210_iso_stream *stream = itd->stream; + struct usb_device *dev; + bool retval = false; + + /* for each uframe with a packet */ + for (uframe = 0; uframe < 8; uframe++) { + if (likely(itd->index[uframe] == -1)) + continue; + urb_index = itd->index[uframe]; + desc = &urb->iso_frame_desc[urb_index]; + + t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]); + itd->hw_transaction[uframe] = 0; + + /* report transfer status */ + if (unlikely(t & ISO_ERRS)) { + urb->error_count++; + if (t & FOTG210_ISOC_BUF_ERR) + desc->status = usb_pipein(urb->pipe) + ? -ENOSR /* hc couldn't read */ + : -ECOMM; /* hc couldn't write */ + else if (t & FOTG210_ISOC_BABBLE) + desc->status = -EOVERFLOW; + else /* (t & FOTG210_ISOC_XACTERR) */ + desc->status = -EPROTO; + + /* HC need not update length with this error */ + if (!(t & FOTG210_ISOC_BABBLE)) { + desc->actual_length = + fotg210_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } + } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) { + desc->status = 0; + desc->actual_length = fotg210_itdlen(urb, desc, t); + urb->actual_length += desc->actual_length; + } else { + /* URB was too late */ + desc->status = -EXDEV; + } + } + + /* handle completion now? */ + if (likely((urb_index + 1) != urb->number_of_packets)) + goto done; + + /* ASSERT: it's really the last itd for this urb + list_for_each_entry (itd, &stream->td_list, itd_list) + BUG_ON (itd->urb == urb); + */ + + /* give urb back to the driver; completion often (re)submits */ + dev = urb->dev; + fotg210_urb_done(fotg210, urb, 0); + retval = true; + urb = NULL; + + --fotg210->isoc_count; + disable_periodic(fotg210); + + if (unlikely(list_is_singular(&stream->td_list))) { + fotg210_to_hcd(fotg210)->self.bandwidth_allocated + -= stream->bandwidth; + fotg210_vdbg(fotg210, + "deschedule devp %s ep%d%s-iso\n", + dev->devpath, stream->bEndpointAddress & 0x0f, + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); + } + +done: + itd->urb = NULL; + + /* Add to the end of the free list for later reuse */ + list_move_tail(&itd->itd_list, &stream->free_list); + + /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */ + if (list_empty(&stream->td_list)) { + list_splice_tail_init(&stream->free_list, + &fotg210->cached_itd_list); + start_free_itds(fotg210); + } + + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb, + gfp_t mem_flags) +{ + int status = -EINVAL; + unsigned long flags; + struct fotg210_iso_stream *stream; + + /* Get iso_stream head */ + stream = iso_stream_find(fotg210, urb); + if (unlikely(stream == NULL)) { + fotg210_dbg(fotg210, "can't get iso stream\n"); + return -ENOMEM; + } + if (unlikely(urb->interval != stream->interval && + fotg210_port_speed(fotg210, 0) == + USB_PORT_STAT_HIGH_SPEED)) { + fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n", + stream->interval, urb->interval); + goto done; + } + +#ifdef FOTG210_URB_TRACE + fotg210_dbg(fotg210, + "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n", + __func__, urb->dev->devpath, urb, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->transfer_buffer_length, + urb->number_of_packets, urb->interval, + stream); +#endif + + /* allocate ITDs w/o locking anything */ + status = itd_urb_transaction(stream, fotg210, urb, mem_flags); + if (unlikely(status < 0)) { + fotg210_dbg(fotg210, "can't init itds\n"); + goto done; + } + + /* schedule ... need to lock */ + spin_lock_irqsave(&fotg210->lock, flags); + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) { + status = -ESHUTDOWN; + goto done_not_linked; + } + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb); + if (unlikely(status)) + goto done_not_linked; + status = iso_stream_schedule(fotg210, urb, stream); + if (likely(status == 0)) + itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream); + else + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb); + done_not_linked: + spin_unlock_irqrestore(&fotg210->lock, flags); + done: + return status; +} + +/*-------------------------------------------------------------------------*/ + +static void scan_isoc(struct fotg210_hcd *fotg210) +{ + unsigned uf, now_frame, frame; + unsigned fmask = fotg210->periodic_size - 1; + bool modified, live; + + /* + * When running, scan from last scan point up to "now" + * else clean up by scanning everything that's left. + * Touches as few pages as possible: cache-friendly. + */ + if (fotg210->rh_state >= FOTG210_RH_RUNNING) { + uf = fotg210_read_frame_index(fotg210); + now_frame = (uf >> 3) & fmask; + live = true; + } else { + now_frame = (fotg210->next_frame - 1) & fmask; + live = false; + } + fotg210->now_frame = now_frame; + + frame = fotg210->next_frame; + for (;;) { + union fotg210_shadow q, *q_p; + __hc32 type, *hw_p; + +restart: + /* scan each element in frame's queue for completions */ + q_p = &fotg210->pshadow[frame]; + hw_p = &fotg210->periodic[frame]; + q.ptr = q_p->ptr; + type = Q_NEXT_TYPE(fotg210, *hw_p); + modified = false; + + while (q.ptr != NULL) { + switch (hc32_to_cpu(fotg210, type)) { + case Q_TYPE_ITD: + /* If this ITD is still active, leave it for + * later processing ... check the next entry. + * No need to check for activity unless the + * frame is current. + */ + if (frame == now_frame && live) { + rmb(); + for (uf = 0; uf < 8; uf++) { + if (q.itd->hw_transaction[uf] & + ITD_ACTIVE(fotg210)) + break; + } + if (uf < 8) { + q_p = &q.itd->itd_next; + hw_p = &q.itd->hw_next; + type = Q_NEXT_TYPE(fotg210, + q.itd->hw_next); + q = *q_p; + break; + } + } + + /* Take finished ITDs out of the schedule + * and process them: recycle, maybe report + * URB completion. HC won't cache the + * pointer for much longer, if at all. + */ + *q_p = q.itd->itd_next; + *hw_p = q.itd->hw_next; + type = Q_NEXT_TYPE(fotg210, q.itd->hw_next); + wmb(); + modified = itd_complete(fotg210, q.itd); + q = *q_p; + break; + default: + fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n", + type, frame, q.ptr); + /* FALL THROUGH */ + case Q_TYPE_QH: + case Q_TYPE_FSTN: + /* End of the iTDs and siTDs */ + q.ptr = NULL; + break; + } + + /* assume completion callbacks modify the queue */ + if (unlikely(modified && fotg210->isoc_count > 0)) + goto restart; + } + + /* Stop when we have reached the current frame */ + if (frame == now_frame) + break; + frame = (frame + 1) & fmask; + } + fotg210->next_frame = now_frame; +} +/*-------------------------------------------------------------------------*/ +/* + * Display / Set uframe_periodic_max + */ +static ssize_t show_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fotg210_hcd *fotg210; + int n; + + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); + n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max); + return n; +} + + +static ssize_t store_uframe_periodic_max(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fotg210_hcd *fotg210; + unsigned uframe_periodic_max; + unsigned frame, uframe; + unsigned short allocated_max; + unsigned long flags; + ssize_t ret; + + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev))); + if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) + return -EINVAL; + + if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { + fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n", + uframe_periodic_max); + return -EINVAL; + } + + ret = -EINVAL; + + /* + * lock, so that our checking does not race with possible periodic + * bandwidth allocation through submitting new urbs. + */ + spin_lock_irqsave(&fotg210->lock, flags); + + /* + * for request to decrease max periodic bandwidth, we have to check + * every microframe in the schedule to see whether the decrease is + * possible. + */ + if (uframe_periodic_max < fotg210->uframe_periodic_max) { + allocated_max = 0; + + for (frame = 0; frame < fotg210->periodic_size; ++frame) + for (uframe = 0; uframe < 7; ++uframe) + allocated_max = max(allocated_max, + periodic_usecs(fotg210, frame, uframe)); + + if (allocated_max > uframe_periodic_max) { + fotg210_info(fotg210, + "cannot decrease uframe_periodic_max becase " + "periodic bandwidth is already allocated " + "(%u > %u)\n", + allocated_max, uframe_periodic_max); + goto out_unlock; + } + } + + /* increasing is always ok */ + + fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n", + 100 * uframe_periodic_max/125, uframe_periodic_max); + + if (uframe_periodic_max != 100) + fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n"); + + fotg210->uframe_periodic_max = uframe_periodic_max; + ret = count; + +out_unlock: + spin_unlock_irqrestore(&fotg210->lock, flags); + return ret; +} + +static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, + store_uframe_periodic_max); + +static inline int create_sysfs_files(struct fotg210_hcd *fotg210) +{ + struct device *controller = fotg210_to_hcd(fotg210)->self.controller; + int i = 0; + + if (i) + goto out; + + i = device_create_file(controller, &dev_attr_uframe_periodic_max); +out: + return i; +} + +static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) +{ + struct device *controller = fotg210_to_hcd(fotg210)->self.controller; + + device_remove_file(controller, &dev_attr_uframe_periodic_max); +} +/*-------------------------------------------------------------------------*/ + +/* On some systems, leaving remote wakeup enabled prevents system shutdown. + * The firmware seems to think that powering off is a wakeup event! + * This routine turns off remote wakeup and everything else, on all ports. + */ +static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210) +{ + u32 __iomem *status_reg = &fotg210->regs->port_status; + + fotg210_writel(fotg210, PORT_RWC_BITS, status_reg); +} + +/* + * Halt HC, turn off all ports, and let the BIOS use the companion controllers. + * Must be called with interrupts enabled and the lock not held. + */ +static void fotg210_silence_controller(struct fotg210_hcd *fotg210) +{ + fotg210_halt(fotg210); + + spin_lock_irq(&fotg210->lock); + fotg210->rh_state = FOTG210_RH_HALTED; + fotg210_turn_off_all_ports(fotg210); + spin_unlock_irq(&fotg210->lock); +} + +/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. + */ +static void fotg210_shutdown(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + + spin_lock_irq(&fotg210->lock); + fotg210->shutdown = true; + fotg210->rh_state = FOTG210_RH_STOPPING; + fotg210->enabled_hrtimer_events = 0; + spin_unlock_irq(&fotg210->lock); + + fotg210_silence_controller(fotg210); + + hrtimer_cancel(&fotg210->hrtimer); +} + +/*-------------------------------------------------------------------------*/ + +/* + * fotg210_work is called from some interrupts, timers, and so on. + * it calls driver completion functions, after dropping fotg210->lock. + */ +static void fotg210_work(struct fotg210_hcd *fotg210) +{ + /* another CPU may drop fotg210->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (fotg210->scanning) { + fotg210->need_rescan = true; + return; + } + fotg210->scanning = true; + + rescan: + fotg210->need_rescan = false; + if (fotg210->async_count) + scan_async(fotg210); + if (fotg210->intr_count > 0) + scan_intr(fotg210); + if (fotg210->isoc_count > 0) + scan_isoc(fotg210); + if (fotg210->need_rescan) + goto rescan; + fotg210->scanning = false; + + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + * such lossage has been observed on both VT6202 and VT8235. + */ + turn_on_io_watchdog(fotg210); +} + +/* + * Called when the fotg210_hcd module is removed. + */ +static void fotg210_stop(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + + fotg210_dbg(fotg210, "stop\n"); + + /* no more interrupts ... */ + + spin_lock_irq(&fotg210->lock); + fotg210->enabled_hrtimer_events = 0; + spin_unlock_irq(&fotg210->lock); + + fotg210_quiesce(fotg210); + fotg210_silence_controller(fotg210); + fotg210_reset(fotg210); + + hrtimer_cancel(&fotg210->hrtimer); + remove_sysfs_files(fotg210); + remove_debug_files(fotg210); + + /* root hub is shut down separately (first, when possible) */ + spin_lock_irq(&fotg210->lock); + end_free_itds(fotg210); + spin_unlock_irq(&fotg210->lock); + fotg210_mem_cleanup(fotg210); + +#ifdef FOTG210_STATS + fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n", + fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa, + fotg210->stats.lost_iaa); + fotg210_dbg(fotg210, "complete %ld unlink %ld\n", + fotg210->stats.complete, fotg210->stats.unlink); +#endif + + dbg_status(fotg210, "fotg210_stop completed", + fotg210_readl(fotg210, &fotg210->regs->status)); +} + +/* one-time init, only for memory state */ +static int hcd_fotg210_init(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp; + int retval; + u32 hcc_params; + struct fotg210_qh_hw *hw; + + spin_lock_init(&fotg210->lock); + + /* + * keep io watchdog by default, those good HCDs could turn off it later + */ + fotg210->need_io_watchdog = 1; + + hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + fotg210->hrtimer.function = fotg210_hrtimer_func; + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT; + + hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + /* + * by default set standard 80% (== 100 usec/uframe) max periodic + * bandwidth as required by USB 2.0 + */ + fotg210->uframe_periodic_max = 100; + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + fotg210->periodic_size = DEFAULT_I_TDPS; + INIT_LIST_HEAD(&fotg210->intr_qh_list); + INIT_LIST_HEAD(&fotg210->cached_itd_list); + + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + switch (FOTG210_TUNE_FLS) { + case 0: + fotg210->periodic_size = 1024; + break; + case 1: + fotg210->periodic_size = 512; + break; + case 2: + fotg210->periodic_size = 256; + break; + default: + BUG(); + } + } + retval = fotg210_mem_init(fotg210, GFP_KERNEL); + if (retval < 0) + return retval; + + /* controllers may cache some of the periodic schedule ... */ + fotg210->i_thresh = 2; + + /* + * dedicate a qh for the async ring head, since we couldn't unlink + * a 'real' qh without stopping the async schedule [4.8]. use it + * as the 'reclamation list head' too. + * its dummy is used in hw_alt_next of many tds, to prevent the qh + * from automatically advancing to the next td after short reads. + */ + fotg210->async->qh_next.qh = NULL; + hw = fotg210->async->hw; + hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma); + hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD); + hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT); + hw->hw_qtd_next = FOTG210_LIST_END(fotg210); + fotg210->async->qh_state = QH_STATE_LINKED; + hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma); + + /* clear interrupt enables, set irq latency */ + if (log2_irq_thresh < 0 || log2_irq_thresh > 6) + log2_irq_thresh = 0; + temp = 1 << (16 + log2_irq_thresh); + if (HCC_CANPARK(hcc_params)) { + /* HW default park == 3, on hardware that supports it (like + * NVidia and ALI silicon), maximizes throughput on the async + * schedule by avoiding QH fetches between transfers. + * + * With fast usb storage devices and NForce2, "park" seems to + * make problems: throughput reduction (!), data errors... + */ + if (park) { + park = min_t(unsigned, park, 3); + temp |= CMD_PARK; + temp |= park << 8; + } + fotg210_dbg(fotg210, "park %d\n", park); + } + if (HCC_PGM_FRAMELISTLEN(hcc_params)) { + /* periodic schedule size can be smaller than default */ + temp &= ~(3 << 2); + temp |= (FOTG210_TUNE_FLS << 2); + } + fotg210->command = temp; + + /* Accept arbitrarily long scatter-gather lists */ + if (!(hcd->driver->flags & HCD_LOCAL_MEM)) + hcd->self.sg_tablesize = ~0; + return 0; +} + +/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */ +static int fotg210_run(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 temp; + u32 hcc_params; + + hcd->uses_new_polling = 1; + + /* EHCI spec section 4.1 */ + + fotg210_writel(fotg210, fotg210->periodic_dma, + &fotg210->regs->frame_list); + fotg210_writel(fotg210, (u32)fotg210->async->qh_dma, + &fotg210->regs->async_next); + + /* + * hcc_params controls whether fotg210->regs->segment must (!!!) + * be used; it constrains QH/ITD/SITD and QTD locations. + * pci_pool consistent memory always uses segment zero. + * streaming mappings for I/O buffers, like pci_map_single(), + * can return segments above 4GB, if the device allows. + * + * NOTE: the dma mask is visible through dma_supported(), so + * drivers can pass this info along ... like NETIF_F_HIGHDMA, + * Scsi_Host.highmem_io, and so forth. It's readonly to all + * host side drivers though. + */ + hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + + /* + * Philips, Intel, and maybe others need CMD_RUN before the + * root hub will detect new devices (why?); NEC doesn't + */ + fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); + fotg210->command |= CMD_RUN; + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command); + dbg_cmd(fotg210, "init", fotg210->command); + + /* + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices + * are explicitly handed to companion controller(s), so no TT is + * involved with the root hub. (Except where one is integrated, + * and there's no companion controller unless maybe for USB OTG.) + * + * Turning on the CF flag will transfer ownership of all ports + * from the companions to the EHCI controller. If any of the + * companions are in the middle of a port reset at the time, it + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem + * guarantees that no resets are in progress. After we set CF, + * a short delay lets the hardware catch up; new resets shouldn't + * be started before the port switching actions could complete. + */ + down_write(&ehci_cf_port_reset_rwsem); + fotg210->rh_state = FOTG210_RH_RUNNING; + /* unblock posted writes */ + fotg210_readl(fotg210, &fotg210->regs->command); + msleep(5); + up_write(&ehci_cf_port_reset_rwsem); + fotg210->last_periodic_enable = ktime_get_real(); + + temp = HC_VERSION(fotg210, + fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); + fotg210_info(fotg210, + "USB %x.%x started, EHCI %x.%02x\n", + ((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f), + temp >> 8, temp & 0xff); + + fotg210_writel(fotg210, INTR_MASK, + &fotg210->regs->intr_enable); /* Turn On Interrupts */ + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + create_debug_files(fotg210); + create_sysfs_files(fotg210); + + return 0; +} + +static int fotg210_setup(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + int retval; + + fotg210->regs = (void __iomem *)fotg210->caps + + HC_LENGTH(fotg210, + fotg210_readl(fotg210, &fotg210->caps->hc_capbase)); + dbg_hcs_params(fotg210, "reset"); + dbg_hcc_params(fotg210, "reset"); + + /* cache this readonly data; minimize chip reads */ + fotg210->hcs_params = fotg210_readl(fotg210, + &fotg210->caps->hcs_params); + + fotg210->sbrn = HCD_USB2; + + /* data structure init */ + retval = hcd_fotg210_init(hcd); + if (retval) + return retval; + + retval = fotg210_halt(fotg210); + if (retval) + return retval; + + fotg210_reset(fotg210); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static irqreturn_t fotg210_irq(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + u32 status, masked_status, pcd_status = 0, cmd; + int bh; + + spin_lock(&fotg210->lock); + + status = fotg210_readl(fotg210, &fotg210->regs->status); + + /* e.g. cardbus physical eject */ + if (status == ~(u32) 0) { + fotg210_dbg(fotg210, "device removed\n"); + goto dead; + } + + /* + * We don't use STS_FLR, but some controllers don't like it to + * remain on, so mask it out along with the other status bits. + */ + masked_status = status & (INTR_MASK | STS_FLR); + + /* Shared IRQ? */ + if (!masked_status || + unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) { + spin_unlock(&fotg210->lock); + return IRQ_NONE; + } + + /* clear (just) interrupts */ + fotg210_writel(fotg210, masked_status, &fotg210->regs->status); + cmd = fotg210_readl(fotg210, &fotg210->regs->command); + bh = 0; + +#ifdef VERBOSE_DEBUG + /* unrequested/ignored: Frame List Rollover */ + dbg_status(fotg210, "irq", status); +#endif + + /* INT, ERR, and IAA interrupt rates can be throttled */ + + /* normal [4.15.1.2] or error [4.15.1.1] completion */ + if (likely((status & (STS_INT|STS_ERR)) != 0)) { + if (likely((status & STS_ERR) == 0)) + COUNT(fotg210->stats.normal); + else + COUNT(fotg210->stats.error); + bh = 1; + } + + /* complete the unlinking of some qh [4.15.2.3] */ + if (status & STS_IAA) { + + /* Turn off the IAA watchdog */ + fotg210->enabled_hrtimer_events &= + ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG); + + /* + * Mild optimization: Allow another IAAD to reset the + * hrtimer, if one occurs before the next expiration. + * In theory we could always cancel the hrtimer, but + * tests show that about half the time it will be reset + * for some other event anyway. + */ + if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG) + ++fotg210->next_hrtimer_event; + + /* guard against (alleged) silicon errata */ + if (cmd & CMD_IAAD) + fotg210_dbg(fotg210, "IAA with IAAD still set?\n"); + if (fotg210->async_iaa) { + COUNT(fotg210->stats.iaa); + end_unlink_async(fotg210); + } else + fotg210_dbg(fotg210, "IAA with nothing unlinked?\n"); + } + + /* remote wakeup [4.3.1] */ + if (status & STS_PCD) { + int pstatus; + u32 __iomem *status_reg = &fotg210->regs->port_status; + + /* kick root hub later */ + pcd_status = status; + + /* resume root hub? */ + if (fotg210->rh_state == FOTG210_RH_SUSPENDED) + usb_hcd_resume_root_hub(hcd); + + pstatus = fotg210_readl(fotg210, status_reg); + + if (test_bit(0, &fotg210->suspended_ports) && + ((pstatus & PORT_RESUME) || + !(pstatus & PORT_SUSPEND)) && + (pstatus & PORT_PE) && + fotg210->reset_done[0] == 0) { + + /* start 20 msec resume signaling from this port, + * and make khubd collect PORT_STAT_C_SUSPEND to + * stop that signaling. Use 5 ms extra for safety, + * like usb_port_resume() does. + */ + fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25); + set_bit(0, &fotg210->resuming_ports); + fotg210_dbg(fotg210, "port 1 remote wakeup\n"); + mod_timer(&hcd->rh_timer, fotg210->reset_done[0]); + } + } + + /* PCI errors [4.15.2.4] */ + if (unlikely((status & STS_FATAL) != 0)) { + fotg210_err(fotg210, "fatal error\n"); + dbg_cmd(fotg210, "fatal", cmd); + dbg_status(fotg210, "fatal", status); +dead: + usb_hc_died(hcd); + + /* Don't let the controller do anything more */ + fotg210->shutdown = true; + fotg210->rh_state = FOTG210_RH_STOPPING; + fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); + fotg210_writel(fotg210, fotg210->command, + &fotg210->regs->command); + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable); + fotg210_handle_controller_death(fotg210); + + /* Handle completions when the controller stops */ + bh = 0; + } + + if (bh) + fotg210_work(fotg210); + spin_unlock(&fotg210->lock); + if (pcd_status) + usb_hcd_poll_rh_status(hcd); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + * + * urb + dev is in hcd.self.controller.urb_list + * we're queueing TDs onto software and hardware lists + * + * hcd-specific init for hcpriv hasn't been done yet + * + * NOTE: control, bulk, and interrupt share the same code to append TDs + * to a (possibly active) QH, and the same QH scanning code. + */ +static int fotg210_urb_enqueue( + struct usb_hcd *hcd, + struct urb *urb, + gfp_t mem_flags +) { + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct list_head qtd_list; + + INIT_LIST_HEAD(&qtd_list); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + /* qh_completions() code doesn't handle all the fault cases + * in multi-TD control transfers. Even 1KB is rare anyway. + */ + if (urb->transfer_buffer_length > (16 * 1024)) + return -EMSGSIZE; + /* FALLTHROUGH */ + /* case PIPE_BULK: */ + default: + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return submit_async(fotg210, urb, &qtd_list, mem_flags); + + case PIPE_INTERRUPT: + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags)) + return -ENOMEM; + return intr_submit(fotg210, urb, &qtd_list, mem_flags); + + case PIPE_ISOCHRONOUS: + return itd_submit(fotg210, urb, mem_flags); + } +} + +/* remove from hardware lists + * completions normally happen asynchronously + */ + +static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh; + unsigned long flags; + int rc; + + spin_lock_irqsave(&fotg210->lock, flags); + rc = usb_hcd_check_unlink_urb(hcd, urb, status); + if (rc) + goto done; + + switch (usb_pipetype(urb->pipe)) { + /* case PIPE_CONTROL: */ + /* case PIPE_BULK:*/ + default: + qh = (struct fotg210_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_async(fotg210, qh); + break; + case QH_STATE_UNLINK: + case QH_STATE_UNLINK_WAIT: + /* already started */ + break; + case QH_STATE_IDLE: + /* QH might be waiting for a Clear-TT-Buffer */ + qh_completions(fotg210, qh); + break; + } + break; + + case PIPE_INTERRUPT: + qh = (struct fotg210_qh *) urb->hcpriv; + if (!qh) + break; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + start_unlink_intr(fotg210, qh); + break; + case QH_STATE_IDLE: + qh_completions(fotg210, qh); + break; + default: + fotg210_dbg(fotg210, "bogus qh %p state %d\n", + qh, qh->qh_state); + goto done; + } + break; + + case PIPE_ISOCHRONOUS: + /* itd... */ + + /* wait till next completion, do it then. */ + /* completion irqs can wait up to 1024 msec, */ + break; + } +done: + spin_unlock_irqrestore(&fotg210->lock, flags); + return rc; +} + +/*-------------------------------------------------------------------------*/ + +/* bulk qh holds the data toggle */ + +static void +fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + unsigned long flags; + struct fotg210_qh *qh, *tmp; + + /* ASSERT: any requests/urbs are being unlinked */ + /* ASSERT: nobody can be submitting urbs for this any more */ + +rescan: + spin_lock_irqsave(&fotg210->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto done; + + /* endpoints can be iso streams. for now, we don't + * accelerate iso completions ... so spin a while. + */ + if (qh->hw == NULL) { + struct fotg210_iso_stream *stream = ep->hcpriv; + + if (!list_empty(&stream->td_list)) + goto idle_timeout; + + /* BUG_ON(!list_empty(&stream->free_list)); */ + kfree(stream); + goto done; + } + + if (fotg210->rh_state < FOTG210_RH_RUNNING) + qh->qh_state = QH_STATE_IDLE; + switch (qh->qh_state) { + case QH_STATE_LINKED: + case QH_STATE_COMPLETING: + for (tmp = fotg210->async->qh_next.qh; + tmp && tmp != qh; + tmp = tmp->qh_next.qh) + continue; + /* periodic qh self-unlinks on empty, and a COMPLETING qh + * may already be unlinked. + */ + if (tmp) + start_unlink_async(fotg210, qh); + /* FALL THROUGH */ + case QH_STATE_UNLINK: /* wait for hw to finish? */ + case QH_STATE_UNLINK_WAIT: +idle_timeout: + spin_unlock_irqrestore(&fotg210->lock, flags); + schedule_timeout_uninterruptible(1); + goto rescan; + case QH_STATE_IDLE: /* fully unlinked */ + if (qh->clearing_tt) + goto idle_timeout; + if (list_empty(&qh->qtd_list)) { + qh_destroy(fotg210, qh); + break; + } + /* else FALL THROUGH */ + default: + /* caller was supposed to have unlinked any requests; + * that's not our job. just leak this memory. + */ + fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n", + qh, ep->desc.bEndpointAddress, qh->qh_state, + list_empty(&qh->qtd_list) ? "" : "(has tds)"); + break; + } + done: + ep->hcpriv = NULL; + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static void +fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + struct fotg210_qh *qh; + int eptype = usb_endpoint_type(&ep->desc); + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + unsigned long flags; + + if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) + return; + + spin_lock_irqsave(&fotg210->lock, flags); + qh = ep->hcpriv; + + /* For Bulk and Interrupt endpoints we maintain the toggle state + * in the hardware; the toggle bits in udev aren't used at all. + * When an endpoint is reset by usb_clear_halt() we must reset + * the toggle bit in the QH. + */ + if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); + if (!list_empty(&qh->qtd_list)) { + WARN_ONCE(1, "clear_halt for a busy endpoint\n"); + } else if (qh->qh_state == QH_STATE_LINKED || + qh->qh_state == QH_STATE_COMPLETING) { + + /* The toggle value in the QH can't be updated + * while the QH is active. Unlink it now; + * re-linking will call qh_refresh(). + */ + if (eptype == USB_ENDPOINT_XFER_BULK) + start_unlink_async(fotg210, qh); + else + start_unlink_intr(fotg210, qh); + } + } + spin_unlock_irqrestore(&fotg210->lock, flags); +} + +static int fotg210_get_frame(struct usb_hcd *hcd) +{ + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); + return (fotg210_read_frame_index(fotg210) >> 3) % + fotg210->periodic_size; +} + +/*-------------------------------------------------------------------------*/ + +/* + * The EHCI in ChipIdea HDRC cannot be a separate module or device, + * because its registers (and irq) are shared between host/gadget/otg + * functions and in order to facilitate role switching we cannot + * give the fotg210 driver exclusive access to those. + */ +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +static const struct hc_driver fotg210_fotg210_hc_driver = { + .description = hcd_name, + .product_desc = "Faraday USB2.0 Host Controller", + .hcd_priv_size = sizeof(struct fotg210_hcd), + + /* + * generic hardware linkage + */ + .irq = fotg210_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = hcd_fotg210_init, + .start = fotg210_run, + .stop = fotg210_stop, + .shutdown = fotg210_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = fotg210_urb_enqueue, + .urb_dequeue = fotg210_urb_dequeue, + .endpoint_disable = fotg210_endpoint_disable, + .endpoint_reset = fotg210_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = fotg210_get_frame, + + /* + * root hub support + */ + .hub_status_data = fotg210_hub_status_data, + .hub_control = fotg210_hub_control, + .bus_suspend = fotg210_bus_suspend, + .bus_resume = fotg210_bus_resume, + + .relinquish_port = fotg210_relinquish_port, + .port_handed_over = fotg210_port_handed_over, + + .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete, +}; + +static void fotg210_init(struct fotg210_hcd *fotg210) +{ + u32 value; + + iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY, + &fotg210->regs->gmir); + + value = ioread32(&fotg210->regs->otgcsr); + value &= ~OTGCSR_A_BUS_DROP; + value |= OTGCSR_A_BUS_REQ; + iowrite32(value, &fotg210->regs->otgcsr); +} + +/** + * fotg210_hcd_probe - initialize faraday FOTG210 HCDs + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + */ +static int fotg210_hcd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd; + struct resource *res; + int irq; + int retval = -ENODEV; + struct fotg210_hcd *fotg210; + + if (usb_disabled()) + return -ENODEV; + + pdev->dev.power.power_state = PMSG_ON; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(dev)); + return -ENODEV; + } + + irq = res->start; + + hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev, + dev_name(dev)); + if (!hcd) { + dev_err(dev, "failed to create hcd with err %d\n", retval); + retval = -ENOMEM; + goto fail_create_hcd; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->has_tt = 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + fotg210_fotg210_hc_driver.description)) { + dev_dbg(dev, "controller already in use\n"); + retval = -EBUSY; + goto fail_request_resource; + } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(dev, + "Found HC with no register addr. Check %s setup!\n", + dev_name(dev)); + retval = -ENODEV; + goto fail_request_resource; + } + + hcd->regs = ioremap_nocache(res->start, resource_size(res)); + if (hcd->regs == NULL) { + dev_dbg(dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail_ioremap; + } + + fotg210 = hcd_to_fotg210(hcd); + + fotg210->caps = hcd->regs; + + retval = fotg210_setup(hcd); + if (retval) + goto fail_add_hcd; + + fotg210_init(fotg210); + + retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (retval) { + dev_err(dev, "failed to add hcd with err %d\n", retval); + goto fail_add_hcd; + } + + return retval; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +fail_request_resource: + usb_put_hcd(hcd); +fail_create_hcd: + dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); + return retval; +} + +/** + * fotg210_hcd_remove - shutdown processing for EHCI HCDs + * @dev: USB Host Controller being removed + * + */ +static int fotg210_hcd_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_hcd *hcd = dev_get_drvdata(dev); + + if (!hcd) + return 0; + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + return 0; +} + +static struct platform_driver fotg210_hcd_driver = { + .driver = { + .name = "fotg210-hcd", + }, + .probe = fotg210_hcd_probe, + .remove = fotg210_hcd_remove, +}; + +static int __init fotg210_hcd_init(void) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || + test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) + pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n"); + + pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n", + hcd_name, + sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd), + sizeof(struct fotg210_itd)); + +#ifdef DEBUG + fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root); + if (!fotg210_debug_root) { + retval = -ENOENT; + goto err_debug; + } +#endif + + retval = platform_driver_register(&fotg210_hcd_driver); + if (retval < 0) + goto clean; + return retval; + + platform_driver_unregister(&fotg210_hcd_driver); +clean: +#ifdef DEBUG + debugfs_remove(fotg210_debug_root); + fotg210_debug_root = NULL; +err_debug: +#endif + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + return retval; +} +module_init(fotg210_hcd_init); + +static void __exit fotg210_hcd_cleanup(void) +{ + platform_driver_unregister(&fotg210_hcd_driver); +#ifdef DEBUG + debugfs_remove(fotg210_debug_root); +#endif + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); +} +module_exit(fotg210_hcd_cleanup); diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h new file mode 100644 index 00000000000..8920f9d3256 --- /dev/null +++ b/drivers/usb/host/fotg210.h @@ -0,0 +1,750 @@ +#ifndef __LINUX_FOTG210_H +#define __LINUX_FOTG210_H + +/* definitions used for the EHCI driver */ + +/* + * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to + * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on + * the host controller implementation. + * + * To facilitate the strongest possible byte-order checking from "sparse" + * and so on, we use __leXX unless that's not practical. + */ +#define __hc32 __le32 +#define __hc16 __le16 + +/* statistics can be kept for tuning/monitoring */ +struct fotg210_stats { + /* irq usage */ + unsigned long normal; + unsigned long error; + unsigned long iaa; + unsigned long lost_iaa; + + /* termination of urbs from core */ + unsigned long complete; + unsigned long unlink; +}; + +/* fotg210_hcd->lock guards shared data against other CPUs: + * fotg210_hcd: async, unlink, periodic (and shadow), ... + * usb_host_endpoint: hcpriv + * fotg210_qh: qh_next, qtd_list + * fotg210_qtd: qtd_list + * + * Also, hold this lock when talking to HC registers or + * when updating hw_* fields in shared qh/qtd/... structures. + */ + +#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */ + +/* + * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the + * controller may be doing DMA. Lower values mean there's no DMA. + */ +enum fotg210_rh_state { + FOTG210_RH_HALTED, + FOTG210_RH_SUSPENDED, + FOTG210_RH_RUNNING, + FOTG210_RH_STOPPING +}; + +/* + * Timer events, ordered by increasing delay length. + * Always update event_delays_ns[] and event_handlers[] (defined in + * ehci-timer.c) in parallel with this list. + */ +enum fotg210_hrtimer_event { + FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */ + FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ + FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ + FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ + FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ + FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */ + FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ + FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ + FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ + FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */ + FOTG210_HRTIMER_NUM_EVENTS /* Must come last */ +}; +#define FOTG210_HRTIMER_NO_EVENT 99 + +struct fotg210_hcd { /* one per controller */ + /* timing support */ + enum fotg210_hrtimer_event next_hrtimer_event; + unsigned enabled_hrtimer_events; + ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS]; + struct hrtimer hrtimer; + + int PSS_poll_count; + int ASS_poll_count; + int died_poll_count; + + /* glue to PCI and HCD framework */ + struct fotg210_caps __iomem *caps; + struct fotg210_regs __iomem *regs; + struct fotg210_dbg_port __iomem *debug; + + __u32 hcs_params; /* cached register copy */ + spinlock_t lock; + enum fotg210_rh_state rh_state; + + /* general schedule support */ + bool scanning:1; + bool need_rescan:1; + bool intr_unlinking:1; + bool async_unlinking:1; + bool shutdown:1; + struct fotg210_qh *qh_scan_next; + + /* async schedule support */ + struct fotg210_qh *async; + struct fotg210_qh *dummy; /* For AMD quirk use */ + struct fotg210_qh *async_unlink; + struct fotg210_qh *async_unlink_last; + struct fotg210_qh *async_iaa; + unsigned async_unlink_cycle; + unsigned async_count; /* async activity count */ + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ + unsigned periodic_size; + __hc32 *periodic; /* hw periodic table */ + dma_addr_t periodic_dma; + struct list_head intr_qh_list; + unsigned i_thresh; /* uframes HC might cache */ + + union fotg210_shadow *pshadow; /* mirror hw periodic table */ + struct fotg210_qh *intr_unlink; + struct fotg210_qh *intr_unlink_last; + unsigned intr_unlink_cycle; + unsigned now_frame; /* frame from HC hardware */ + unsigned next_frame; /* scan periodic, start here */ + unsigned intr_count; /* intr activity count */ + unsigned isoc_count; /* isoc activity count */ + unsigned periodic_count; /* periodic activity count */ + /* max periodic time per uframe */ + unsigned uframe_periodic_max; + + + /* list of itds completed while now_frame was still active */ + struct list_head cached_itd_list; + struct fotg210_itd *last_itd_to_free; + + /* per root hub port */ + unsigned long reset_done[FOTG210_MAX_ROOT_PORTS]; + + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ + unsigned long owned_ports; /* which ports are + owned by the companion during a bus suspend */ + unsigned long port_c_suspend; /* which ports have + the change-suspend feature turned on */ + unsigned long suspended_ports; /* which ports are + suspended */ + unsigned long resuming_ports; /* which ports have + started to resume */ + + /* per-HC memory pools (could be per-bus, but ...) */ + struct dma_pool *qh_pool; /* qh per active urb */ + struct dma_pool *qtd_pool; /* one or more per qh */ + struct dma_pool *itd_pool; /* itd per iso urb */ + + unsigned random_frame; + unsigned long next_statechange; + ktime_t last_periodic_enable; + u32 command; + + /* SILICON QUIRKS */ + unsigned need_io_watchdog:1; + unsigned fs_i_thresh:1; /* Intel iso scheduling */ + + u8 sbrn; /* packed release number */ + + /* irq statistics */ +#ifdef FOTG210_STATS + struct fotg210_stats stats; +# define COUNT(x) ((x)++) +#else +# define COUNT(x) +#endif + + /* debug files */ +#ifdef DEBUG + struct dentry *debug_dir; +#endif +}; + +/* convert between an HCD pointer and the corresponding FOTG210_HCD */ +static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd) +{ + return (struct fotg210_hcd *)(hcd->hcd_priv); +} +static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210) +{ + return container_of((void *) fotg210, struct usb_hcd, hcd_priv); +} + +/*-------------------------------------------------------------------------*/ + +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ + +/* Section 2.2 Host Controller Capability Registers */ +struct fotg210_caps { + /* these fields are specified as 8 and 16 bit registers, + * but some hosts can't perform 8 or 16 bit PCI accesses. + * some hosts treat caplength and hciversion as parts of a 32-bit + * register, others treat them as two separate registers, this + * affects the memory map for big endian controllers. + */ + u32 hc_capbase; +#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \ + (fotg210_big_endian_capbase(fotg210) ? 24 : 0))) +#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \ + (fotg210_big_endian_capbase(fotg210) ? 0 : 16))) + u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ + + u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ + u8 portroute[8]; /* nibbles for routing - offset 0xC */ +}; + + +/* Section 2.3 Host Controller Operational Registers */ +struct fotg210_regs { + + /* USBCMD: offset 0x00 */ + u32 command; + +/* EHCI 1.1 addendum */ +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +#define CMD_PARK (1<<11) /* enable "park" on async qh */ +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +#define CMD_ASE (1<<5) /* async schedule enable */ +#define CMD_PSE (1<<4) /* periodic schedule enable */ +/* 3:2 is periodic frame list size */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ + + /* USBSTS: offset 0x04 */ + u32 status; +#define STS_ASS (1<<15) /* Async Schedule Status */ +#define STS_PSS (1<<14) /* Periodic Schedule Status */ +#define STS_RECL (1<<13) /* Reclamation */ +#define STS_HALT (1<<12) /* Not running (any reason) */ +/* some bits reserved */ + /* these STS_* flags are also intr_enable bits (USBINTR) */ +#define STS_IAA (1<<5) /* Interrupted on async advance */ +#define STS_FATAL (1<<4) /* such as some PCI access errors */ +#define STS_FLR (1<<3) /* frame list rolled over */ +#define STS_PCD (1<<2) /* port change detect */ +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +#define STS_INT (1<<0) /* "normal" completion (short, ...) */ + + /* USBINTR: offset 0x08 */ + u32 intr_enable; + + /* FRINDEX: offset 0x0C */ + u32 frame_index; /* current microframe number */ + /* CTRLDSSEGMENT: offset 0x10 */ + u32 segment; /* address bits 63:32 if needed */ + /* PERIODICLISTBASE: offset 0x14 */ + u32 frame_list; /* points to periodic list */ + /* ASYNCLISTADDR: offset 0x18 */ + u32 async_next; /* address of next async queue head */ + + u32 reserved1; + /* PORTSC: offset 0x20 */ + u32 port_status; +/* 31:23 reserved */ +#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PEC (1<<3) /* port enable change */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC) + u32 reserved2[19]; + + /* OTGCSR: offet 0x70 */ + u32 otgcsr; +#define OTGCSR_HOST_SPD_TYP (3 << 22) +#define OTGCSR_A_BUS_DROP (1 << 5) +#define OTGCSR_A_BUS_REQ (1 << 4) + + /* OTGISR: offset 0x74 */ + u32 otgisr; +#define OTGISR_OVC (1 << 10) + + u32 reserved3[15]; + + /* GMIR: offset 0xB4 */ + u32 gmir; +#define GMIR_INT_POLARITY (1 << 3) /*Active High*/ +#define GMIR_MHC_INT (1 << 2) +#define GMIR_MOTG_INT (1 << 1) +#define GMIR_MDEV_INT (1 << 0) +}; + +/* Appendix C, Debug port ... intended for use with special "debug devices" + * that can help if there's no serial console. (nonstandard enumeration.) + */ +struct fotg210_dbg_port { + u32 control; +#define DBGP_OWNER (1<<30) +#define DBGP_ENABLED (1<<28) +#define DBGP_DONE (1<<16) +#define DBGP_INUSE (1<<10) +#define DBGP_ERRCODE(x) (((x)>>7)&0x07) +# define DBGP_ERR_BAD 1 +# define DBGP_ERR_SIGNAL 2 +#define DBGP_ERROR (1<<6) +#define DBGP_GO (1<<5) +#define DBGP_OUT (1<<4) +#define DBGP_LEN(x) (((x)>>0)&0x0f) + u32 pids; +#define DBGP_PID_GET(x) (((x)>>16)&0xff) +#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) + u32 data03; + u32 data47; + u32 address; +#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) +}; + +#ifdef CONFIG_EARLY_PRINTK_DBGP +#include <linux/init.h> +extern int __init early_dbgp_init(char *s); +extern struct console early_dbgp_console; +#endif /* CONFIG_EARLY_PRINTK_DBGP */ + +struct usb_hcd; + +static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd) +{ + return 1; /* Shouldn't this be 0? */ +} + +static inline int xen_dbgp_external_startup(struct usb_hcd *hcd) +{ + return -1; +} + +#ifdef CONFIG_EARLY_PRINTK_DBGP +/* Call backs from fotg210 host driver to fotg210 debug driver */ +extern int dbgp_external_startup(struct usb_hcd *); +extern int dbgp_reset_prep(struct usb_hcd *hcd); +#else +static inline int dbgp_reset_prep(struct usb_hcd *hcd) +{ + return xen_dbgp_reset_prep(hcd); +} +static inline int dbgp_external_startup(struct usb_hcd *hcd) +{ + return xen_dbgp_external_startup(hcd); +} +#endif + +/*-------------------------------------------------------------------------*/ + +#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma) + +/* + * EHCI Specification 0.95 Section 3.5 + * QTD: describe data transfer components (buffer, direction, ...) + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". + * + * These are associated only with "QH" (Queue Head) structures, + * used with control, bulk, and interrupt transfers. + */ +struct fotg210_qtd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.5.1 */ + __hc32 hw_alt_next; /* see EHCI 3.5.2 */ + __hc32 hw_token; /* see EHCI 3.5.3 */ +#define QTD_TOGGLE (1 << 31) /* data toggle */ +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) +#define QTD_IOC (1 << 15) /* interrupt on complete */ +#define QTD_CERR(tok) (((tok)>>10) & 0x3) +#define QTD_PID(tok) (((tok)>>8) & 0x3) +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ +#define QTD_STS_HALT (1 << 6) /* halted on error */ +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ +#define QTD_STS_STS (1 << 1) /* split transaction state */ +#define QTD_STS_PING (1 << 0) /* issue PING? */ + +#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE) +#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT) +#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS) + + __hc32 hw_buf[5]; /* see EHCI 3.5.4 */ + __hc32 hw_buf_hi[5]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t qtd_dma; /* qtd address */ + struct list_head qtd_list; /* sw qtd list */ + struct urb *urb; /* qtd's urb */ + size_t length; /* length of buffer */ +} __aligned(32); + +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) + +/*-------------------------------------------------------------------------*/ + +/* type tag from {qh,itd,fstn}->hw_next */ +#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1)) + +/* + * Now the following defines are not converted using the + * cpu_to_le32() macro anymore, since we have to support + * "dynamic" switching between be and le support, so that the driver + * can be used on one system with SoC EHCI controller using big-endian + * descriptors as well as a normal little-endian PCI EHCI controller. + */ +/* values for that type tag */ +#define Q_TYPE_ITD (0 << 1) +#define Q_TYPE_QH (1 << 1) +#define Q_TYPE_SITD (2 << 1) +#define Q_TYPE_FSTN (3 << 1) + +/* next async queue entry, or pointer to interrupt/periodic QH */ +#define QH_NEXT(fotg210, dma) \ + (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH)) + +/* for periodic/async schedules and qtd lists, mark end of list */ +#define FOTG210_LIST_END(fotg210) \ + cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */ + +/* + * Entries in periodic shadow table are pointers to one of four kinds + * of data structure. That's dictated by the hardware; a type tag is + * encoded in the low bits of the hardware's periodic schedule. Use + * Q_NEXT_TYPE to get the tag. + * + * For entries in the async schedule, the type tag always says "qh". + */ +union fotg210_shadow { + struct fotg210_qh *qh; /* Q_TYPE_QH */ + struct fotg210_itd *itd; /* Q_TYPE_ITD */ + struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */ + __hc32 *hw_next; /* (all types) */ + void *ptr; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.6 + * QH: describes control/bulk/interrupt endpoints + * See Fig 3-7 "Queue Head Structure Layout". + * + * These appear in both the async and (for interrupt) periodic schedules. + */ + +/* first part defined by EHCI spec */ +struct fotg210_qh_hw { + __hc32 hw_next; /* see EHCI 3.6.1 */ + __hc32 hw_info1; /* see EHCI 3.6.2 */ +#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */ +#define QH_HEAD (1 << 15) /* Head of async reclamation list */ +#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */ +#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */ +#define QH_LOW_SPEED (1 << 12) +#define QH_FULL_SPEED (0 << 12) +#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */ + __hc32 hw_info2; /* see EHCI 3.6.2 */ +#define QH_SMASK 0x000000ff +#define QH_CMASK 0x0000ff00 +#define QH_HUBADDR 0x007f0000 +#define QH_HUBPORT 0x3f800000 +#define QH_MULT 0xc0000000 + __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ + + /* qtd overlay (hardware parts of a struct fotg210_qtd) */ + __hc32 hw_qtd_next; + __hc32 hw_alt_next; + __hc32 hw_token; + __hc32 hw_buf[5]; + __hc32 hw_buf_hi[5]; +} __aligned(32); + +struct fotg210_qh { + struct fotg210_qh_hw *hw; /* Must come first */ + /* the rest is HCD-private */ + dma_addr_t qh_dma; /* address of qh */ + union fotg210_shadow qh_next; /* ptr to qh; or periodic */ + struct list_head qtd_list; /* sw qtd list */ + struct list_head intr_node; /* list of intr QHs */ + struct fotg210_qtd *dummy; + struct fotg210_qh *unlink_next; /* next on unlink list */ + + unsigned unlink_cycle; + + u8 needs_rescan; /* Dequeue during giveback */ + u8 qh_state; +#define QH_STATE_LINKED 1 /* HC sees this */ +#define QH_STATE_UNLINK 2 /* HC may still see this */ +#define QH_STATE_IDLE 3 /* HC doesn't see this */ +#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */ +#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ + + u8 xacterrs; /* XactErr retry counter */ +#define QH_XACTERR_MAX 32 /* XactErr retry limit */ + + /* periodic schedule info */ + u8 usecs; /* intr bandwidth */ + u8 gap_uf; /* uframes split/csplit gap */ + u8 c_usecs; /* ... split completion bw */ + u16 tt_usecs; /* tt downstream bandwidth */ + unsigned short period; /* polling interval */ + unsigned short start; /* where polling starts */ +#define NO_FRAME ((unsigned short)~0) /* pick new start */ + + struct usb_device *dev; /* access to TT */ + unsigned is_out:1; /* bulk or intr OUT */ + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ +}; + +/*-------------------------------------------------------------------------*/ + +/* description of one iso transaction (up to 3 KB data if highspeed) */ +struct fotg210_iso_packet { + /* These will be copied to iTD when scheduling */ + u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ + __hc32 transaction; /* itd->hw_transaction[i] |= */ + u8 cross; /* buf crosses pages */ + /* for full speed OUT splits */ + u32 buf1; +}; + +/* temporary schedule data for packets from iso urbs (both speeds) + * each packet is one logical usb transaction to the device (not TT), + * beginning at stream->next_uframe + */ +struct fotg210_iso_sched { + struct list_head td_list; + unsigned span; + struct fotg210_iso_packet packet[0]; +}; + +/* + * fotg210_iso_stream - groups all (s)itds for this endpoint. + * acts like a qh would, if EHCI had them for ISO. + */ +struct fotg210_iso_stream { + /* first field matches fotg210_hq, but is NULL */ + struct fotg210_qh_hw *hw; + + u8 bEndpointAddress; + u8 highspeed; + struct list_head td_list; /* queued itds */ + struct list_head free_list; /* list of unused itds */ + struct usb_device *udev; + struct usb_host_endpoint *ep; + + /* output of (re)scheduling */ + int next_uframe; + __hc32 splits; + + /* the rest is derived from the endpoint descriptor, + * trusting urb->interval == f(epdesc->bInterval) and + * including the extra info for hw_bufp[0..2] + */ + u8 usecs, c_usecs; + u16 interval; + u16 tt_usecs; + u16 maxp; + u16 raw_mask; + unsigned bandwidth; + + /* This is used to initialize iTD's hw_bufp fields */ + __hc32 buf0; + __hc32 buf1; + __hc32 buf2; + + /* this is used to initialize sITD's tt info */ + __hc32 address; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.95 Section 3.3 + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" + * + * Schedule records for high speed iso xfers + */ +struct fotg210_itd { + /* first part defined by EHCI spec */ + __hc32 hw_next; /* see EHCI 3.3.1 */ + __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */ +#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ +#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */ +#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */ +#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ +#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) +#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */ + +#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE) + + __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */ + __hc32 hw_bufp_hi[7]; /* Appendix B */ + + /* the rest is HCD-private */ + dma_addr_t itd_dma; /* for this itd */ + union fotg210_shadow itd_next; /* ptr to periodic q entry */ + + struct urb *urb; + struct fotg210_iso_stream *stream; /* endpoint's queue */ + struct list_head itd_list; /* list of stream's itds */ + + /* any/all hw_transactions here may be used by that urb */ + unsigned frame; /* where scheduled */ + unsigned pg; + unsigned index[8]; /* in urb->iso_frame_desc */ +} __aligned(32); + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI Specification 0.96 Section 3.7 + * Periodic Frame Span Traversal Node (FSTN) + * + * Manages split interrupt transactions (using TT) that span frame boundaries + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. + */ +struct fotg210_fstn { + __hc32 hw_next; /* any periodic q entry */ + __hc32 hw_prev; /* qh or FOTG210_LIST_END */ + + /* the rest is HCD-private */ + dma_addr_t fstn_dma; + union fotg210_shadow fstn_next; /* ptr to periodic q entry */ +} __aligned(32); + +/*-------------------------------------------------------------------------*/ + +/* Prepare the PORTSC wakeup flags during controller suspend/resume */ + +#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \ + fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup); + +#define fotg210_prepare_ports_for_controller_resume(fotg210) \ + fotg210_adjust_port_wakeup_flags(fotg210, false, false); + +/*-------------------------------------------------------------------------*/ + +/* + * Some EHCI controllers have a Transaction Translator built into the + * root hub. This is a non-standard feature. Each controller will need + * to add code to the following inline functions, and call them as + * needed (mostly in root hub code). + */ + +static inline unsigned int +fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc) +{ + return (readl(&fotg210->regs->otgcsr) + & OTGCSR_HOST_SPD_TYP) >> 22; +} + +/* Returns the speed of a device attached to a port on the root hub. */ +static inline unsigned int +fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc) +{ + switch (fotg210_get_speed(fotg210, portsc)) { + case 0: + return 0; + case 1: + return USB_PORT_STAT_LOW_SPEED; + case 2: + default: + return USB_PORT_STAT_HIGH_SPEED; + } +} + +/*-------------------------------------------------------------------------*/ + +#define fotg210_has_fsl_portno_bug(e) (0) + +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + * + */ + +#define fotg210_big_endian_mmio(e) 0 +#define fotg210_big_endian_capbase(e) 0 + +static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210, + __u32 __iomem *regs) +{ + return readl(regs); +} + +static inline void fotg210_writel(const struct fotg210_hcd *fotg210, + const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* cpu to fotg210 */ +static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x) +{ + return cpu_to_le32(x); +} + +/* fotg210 to cpu */ +static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x) +{ + return le32_to_cpu(x); +} + +static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210, + const __hc32 *x) +{ + return le32_to_cpup(x); +} + +/*-------------------------------------------------------------------------*/ + +static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210) +{ + return fotg210_readl(fotg210, &fotg210->regs->frame_index); +} + +#define fotg210_itdlen(urb, desc, t) ({ \ + usb_pipein((urb)->pipe) ? \ + (desc)->length - FOTG210_ITD_LENGTH(t) : \ + FOTG210_ITD_LENGTH(t); \ +}) +/*-------------------------------------------------------------------------*/ + +#ifndef DEBUG +#define STUB_DEBUG_FILES +#endif /* DEBUG */ + +/*-------------------------------------------------------------------------*/ + +#endif /* __LINUX_FOTG210_H */ diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 11e0b79ff9d..cfbff716182 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -258,7 +258,7 @@ static int fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev) int fsl_usb2_mpc5121_init(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); struct clk *clk; char clk_name[10]; int base, clk_num; @@ -298,7 +298,7 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev) static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) { - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); pdata->regs = NULL; diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 483990c716a..5b86ffb88f1 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -161,6 +161,13 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) usb_hcd->uses_new_polling = 1; set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags); usb_hcd->state = HC_STATE_RUNNING; + + /* + * prevent USB core from suspending the root hub since + * bus_suspend and bus_resume are not yet supported. + */ + pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev); + result = 0; out: mutex_unlock(&wusbhc->mutex); diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 03dc4d9cbec..60a5de505ca 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1860,7 +1860,7 @@ static int imx21_probe(struct platform_device *pdev) imx21 = hcd_to_imx21(hcd); imx21->hcd = hcd; imx21->dev = &pdev->dev; - imx21->pdata = pdev->dev.platform_data; + imx21->pdata = dev_get_platdata(&pdev->dev); if (!imx21->pdata) imx21->pdata = &default_pdata; diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index b64e661618b..c7d0f8f231b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1626,7 +1626,7 @@ static int isp116x_probe(struct platform_device *pdev) isp116x->addr_reg = addr_reg; spin_lock_init(&isp116x->lock); INIT_LIST_HEAD(&isp116x->async); - isp116x->board = pdev->dev.platform_data; + isp116x->board = dev_get_platdata(&pdev->dev); if (!isp116x->board) { ERR("Platform data structure not initialized\n"); diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index 9a2c400e609..dd34b7a3396 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -325,11 +325,7 @@ struct isp116x_ep { /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif +#define DBG(stuff...) pr_debug("116x: " stuff) #ifdef VERBOSE # define VDBG DBG @@ -358,15 +354,8 @@ struct isp116x_ep { #define isp116x_check_platform_delay(h) 0 #endif -#if defined(DEBUG) -#define IRQ_TEST() BUG_ON(!irqs_disabled()) -#else -#define IRQ_TEST() do{}while(0) -#endif - static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) { - IRQ_TEST(); writew(reg & 0xff, isp116x->addr_reg); isp116x_delay(isp116x, 300); } diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index b04e8ece4d3..6f29abad681 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -37,11 +37,7 @@ * recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz. */ -#ifdef CONFIG_USB_DEBUG -# define ISP1362_DEBUG -#else -# undef ISP1362_DEBUG -#endif +#undef ISP1362_DEBUG /* * The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and @@ -82,6 +78,8 @@ #include <linux/io.h> #include <linux/bitmap.h> #include <linux/prefetch.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <asm/irq.h> #include <asm/byteorder.h> @@ -92,7 +90,6 @@ static int dbg_level; module_param(dbg_level, int, 0644); #else module_param(dbg_level, int, 0); -#define STUB_DEBUG_FILE #endif #include "../core/usb.h" @@ -350,8 +347,6 @@ static void isp1362_write_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep struct ptd *ptd = &ep->ptd; int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length; - _BUG_ON(ep->ptd_offset < 0); - prefetch(ptd); isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE); if (len) @@ -1575,12 +1570,12 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, DBG(0, "ClearHubFeature: "); switch (wValue) { case C_HUB_OVER_CURRENT: - _DBG(0, "C_HUB_OVER_CURRENT\n"); + DBG(0, "C_HUB_OVER_CURRENT\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC); spin_unlock_irqrestore(&isp1362_hcd->lock, flags); case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_LOCAL_POWER\n"); + DBG(0, "C_HUB_LOCAL_POWER\n"); break; default: goto error; @@ -1591,7 +1586,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); + DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); break; default: goto error; @@ -1622,36 +1617,36 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_ENABLE: - _DBG(0, "USB_PORT_FEAT_ENABLE\n"); + DBG(0, "USB_PORT_FEAT_ENABLE\n"); tmp = RH_PS_CCS; break; case USB_PORT_FEAT_C_ENABLE: - _DBG(0, "USB_PORT_FEAT_C_ENABLE\n"); + DBG(0, "USB_PORT_FEAT_C_ENABLE\n"); tmp = RH_PS_PESC; break; case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_SUSPEND\n"); tmp = RH_PS_POCI; break; case USB_PORT_FEAT_C_SUSPEND: - _DBG(0, "USB_PORT_FEAT_C_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_C_SUSPEND\n"); tmp = RH_PS_PSSC; break; case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); + DBG(0, "USB_PORT_FEAT_POWER\n"); tmp = RH_PS_LSDA; break; case USB_PORT_FEAT_C_CONNECTION: - _DBG(0, "USB_PORT_FEAT_C_CONNECTION\n"); + DBG(0, "USB_PORT_FEAT_C_CONNECTION\n"); tmp = RH_PS_CSC; break; case USB_PORT_FEAT_C_OVER_CURRENT: - _DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n"); + DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n"); tmp = RH_PS_OCIC; break; case USB_PORT_FEAT_C_RESET: - _DBG(0, "USB_PORT_FEAT_C_RESET\n"); + DBG(0, "USB_PORT_FEAT_C_RESET\n"); tmp = RH_PS_PRSC; break; default: @@ -1671,7 +1666,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); + DBG(0, "USB_PORT_FEAT_SUSPEND\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS); isp1362_hcd->rhport[wIndex] = @@ -1679,7 +1674,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&isp1362_hcd->lock, flags); break; case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); + DBG(0, "USB_PORT_FEAT_POWER\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS); isp1362_hcd->rhport[wIndex] = @@ -1687,7 +1682,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&isp1362_hcd->lock, flags); break; case USB_PORT_FEAT_RESET: - _DBG(0, "USB_PORT_FEAT_RESET\n"); + DBG(0, "USB_PORT_FEAT_RESET\n"); spin_lock_irqsave(&isp1362_hcd->lock, flags); t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH); @@ -1721,7 +1716,7 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: error: /* "protocol stall" on error */ - _DBG(0, "PROTOCOL STALL\n"); + DBG(0, "PROTOCOL STALL\n"); retval = -EPIPE; } @@ -1913,20 +1908,6 @@ static int isp1362_bus_resume(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} -static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} - -#else - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - static void dump_irq(struct seq_file *s, char *label, u16 mask) { seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask, @@ -2069,7 +2050,7 @@ static void dump_regs(struct seq_file *s, struct isp1362_hcd *isp1362_hcd) isp1362_read_reg16(isp1362_hcd, HCATLDTCTO)); } -static int proc_isp1362_show(struct seq_file *s, void *unused) +static int isp1362_show(struct seq_file *s, void *unused) { struct isp1362_hcd *isp1362_hcd = s->private; struct isp1362_ep *ep; @@ -2173,41 +2154,31 @@ static int proc_isp1362_show(struct seq_file *s, void *unused) return 0; } -static int proc_isp1362_open(struct inode *inode, struct file *file) +static int isp1362_open(struct inode *inode, struct file *file) { - return single_open(file, proc_isp1362_show, PDE_DATA(inode)); + return single_open(file, isp1362_show, inode); } -static const struct file_operations proc_ops = { - .open = proc_isp1362_open, +static const struct file_operations debug_ops = { + .open = isp1362_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* expect just one isp1362_hcd per system */ -static const char proc_filename[] = "driver/isp1362"; - static void create_debug_file(struct isp1362_hcd *isp1362_hcd) { - struct proc_dir_entry *pde; - - pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, isp1362_hcd); - if (pde == NULL) { - pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename); - return; - } - isp1362_hcd->pde = pde; + isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO, + usb_debug_root, + isp1362_hcd, &debug_ops); } static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) { - if (isp1362_hcd->pde) - remove_proc_entry(proc_filename, NULL); + debugfs_remove(isp1362_hcd->debug_file); } -#endif - /*-------------------------------------------------------------------------*/ static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) @@ -2754,7 +2725,7 @@ static int isp1362_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isp1362_hcd->periodic); INIT_LIST_HEAD(&isp1362_hcd->isoc); INIT_LIST_HEAD(&isp1362_hcd->remove_list); - isp1362_hcd->board = pdev->dev.platform_data; + isp1362_hcd->board = dev_get_platdata(&pdev->dev); #if USE_PLATFORM_DELAY if (!isp1362_hcd->board->delay) { dev_err(hcd->self.controller, "No platform delay function given\n"); diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 0f97820e65b..3b0b4847c3a 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -76,14 +76,14 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len) #define ISP1362_REG_WRITE_OFFSET 0x80 -#ifdef ISP1362_DEBUG -typedef const unsigned int isp1362_reg_t; - #define REG_WIDTH_16 0x000 #define REG_WIDTH_32 0x100 #define REG_WIDTH_MASK 0x100 #define REG_NO_MASK 0x0ff +#ifdef ISP1362_DEBUG +typedef const unsigned int isp1362_reg_t; + #define REG_ACCESS_R 0x200 #define REG_ACCESS_W 0x400 #define REG_ACCESS_RW 0x600 @@ -91,9 +91,6 @@ typedef const unsigned int isp1362_reg_t; #define ISP1362_REG_NO(r) ((r) & REG_NO_MASK) -#define _BUG_ON(x) BUG_ON(x) -#define _WARN_ON(x) WARN_ON(x) - #define ISP1362_REG(name, addr, width, rw) \ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw)) @@ -102,8 +99,6 @@ static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw)) #else typedef const unsigned char isp1362_reg_t; #define ISP1362_REG_NO(r) (r) -#define _BUG_ON(x) do {} while (0) -#define _WARN_ON(x) do {} while (0) #define ISP1362_REG(name, addr, width, rw) \ static isp1362_reg_t ISP1362_REG_##name = addr @@ -485,7 +480,7 @@ struct isp1362_hcd { struct isp1362_platform_data *board; - struct proc_dir_entry *pde; + struct dentry *debug_file; unsigned long stat1, stat2, stat4, stat8, stat16; /* HC registers */ @@ -587,21 +582,11 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd * ISP1362 HW Interface */ -#ifdef ISP1362_DEBUG #define DBG(level, fmt...) \ do { \ if (dbg_level > level) \ pr_debug(fmt); \ } while (0) -#define _DBG(level, fmt...) \ - do { \ - if (dbg_level > level) \ - printk(fmt); \ - } while (0) -#else -#define DBG(fmt...) do {} while (0) -#define _DBG DBG -#endif #ifdef VERBOSE # define VDBG(fmt...) DBG(3, fmt) @@ -645,9 +630,7 @@ static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd */ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg) { - /*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/ REG_ACCESS_TEST(reg); - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg); DUMMY_DELAY_ACCESS; @@ -656,7 +639,6 @@ static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t re static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val) { - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; writew(val, isp1362_hcd->data_reg); } @@ -665,7 +647,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd) { u16 val; - _BUG_ON(!irqs_disabled()); DUMMY_DELAY_ACCESS; val = readw(isp1362_hcd->data_reg); @@ -674,7 +655,6 @@ static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd) static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val) { - _BUG_ON(!irqs_disabled()); #if USE_32BIT DUMMY_DELAY_ACCESS; writel(val, isp1362_hcd->data_reg); @@ -690,7 +670,6 @@ static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd) { u32 val; - _BUG_ON(!irqs_disabled()); #if USE_32BIT DUMMY_DELAY_ACCESS; val = readl(isp1362_hcd->data_reg); @@ -713,8 +692,6 @@ static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 le if (!len) return; - _BUG_ON(!irqs_disabled()); - RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf); #if USE_32BIT if (len >= 4) { @@ -760,8 +737,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l return; } - _BUG_ON(!irqs_disabled()); - RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf); #if USE_32BIT if (len >= 4) { @@ -854,7 +829,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l isp1362_write_reg32(d, r, __v & ~m); \ } -#ifdef ISP1362_DEBUG #define isp1362_show_reg(d, r) { \ if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32) \ DBG(0, "%-12s[%02x]: %08x\n", #r, \ @@ -863,9 +837,6 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l DBG(0, "%-12s[%02x]: %04x\n", #r, \ ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \ } -#else -#define isp1362_show_reg(d, r) do {} while (0) -#endif static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd) { @@ -923,10 +894,6 @@ static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *is static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len) { - _BUG_ON(offset & 1); - _BUG_ON(offset >= ISP1362_BUF_SIZE); - _BUG_ON(len > ISP1362_BUF_SIZE); - _BUG_ON(offset + len > ISP1362_BUF_SIZE); len = (len + 1) & ~1; isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE); @@ -936,42 +903,32 @@ static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) { - _BUG_ON(offset & 1); - isp1362_write_diraddr(isp1362_hcd, offset, len); DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n", __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA); isp1362_read_fifo(isp1362_hcd, buf, len); - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); } static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) { - _BUG_ON(offset & 1); - isp1362_write_diraddr(isp1362_hcd, offset, len); DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n", __func__, len, offset, buf); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET); isp1362_write_fifo(isp1362_hcd, buf, len); - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); } static void __attribute__((unused)) dump_data(char *buf, int len) @@ -1002,7 +959,7 @@ static void __attribute__((unused)) dump_data(char *buf, int len) } } -#if defined(ISP1362_DEBUG) && defined(PTD_TRACE) +#if defined(PTD_TRACE) static void dump_ptd(struct ptd *ptd) { diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 3df49b169b5..df931e9ba5b 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -351,7 +351,7 @@ static int isp1760_plat_probe(struct platform_device *pdev) struct resource *mem_res; struct resource *irq_res; resource_size_t mem_size; - struct isp1760_platform_data *priv = pdev->dev.platform_data; + struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev); unsigned int devflags = 0; unsigned long irqflags = IRQF_SHARED; diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 9677f683120..b3cdd146752 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -31,8 +31,8 @@ #define at91_for_each_port(index) \ for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) -/* interface and function clocks; sometimes also an AHB clock */ -static struct clk *iclk, *fclk, *hclk; +/* interface, function and usb clocks; sometimes also an AHB clock */ +static struct clk *iclk, *fclk, *uclk, *hclk; static int clocked; extern int usb_disabled(void); @@ -41,6 +41,10 @@ extern int usb_disabled(void); static void at91_start_clock(void) { + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + clk_set_rate(uclk, 48000000); + clk_prepare_enable(uclk); + } clk_prepare_enable(hclk); clk_prepare_enable(iclk); clk_prepare_enable(fclk); @@ -52,6 +56,8 @@ static void at91_stop_clock(void) clk_disable_unprepare(fclk); clk_disable_unprepare(iclk); clk_disable_unprepare(hclk); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_disable_unprepare(uclk); clocked = 0; } @@ -162,6 +168,14 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, retval = PTR_ERR(hclk); goto err5; } + if (IS_ENABLED(CONFIG_COMMON_CLK)) { + uclk = clk_get(&pdev->dev, "usb_clk"); + if (IS_ERR(uclk)) { + dev_err(&pdev->dev, "failed to get uclk\n"); + retval = PTR_ERR(uclk); + goto err6; + } + } at91_start_hc(pdev); ohci_hcd_init(hcd_to_ohci(hcd)); @@ -173,6 +187,9 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* Error handling */ at91_stop_hc(pdev); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_put(uclk); + err6: clk_put(hclk); err5: clk_put(fclk); @@ -212,6 +229,8 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + if (IS_ENABLED(CONFIG_COMMON_CLK)) + clk_put(uclk); clk_put(hclk); clk_put(fclk); clk_put(iclk); @@ -225,7 +244,7 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd, static int ohci_at91_reset (struct usb_hcd *hcd) { - struct at91_usbh_data *board = hcd->self.controller->platform_data; + struct at91_usbh_data *board = dev_get_platdata(hcd->self.controller); struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; @@ -280,7 +299,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) */ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) { - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); int length = ohci_hub_status_data(hcd, buf); int port; @@ -301,7 +320,7 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); struct usb_hub_descriptor *desc; int ret = -EINVAL; u32 *data = (u32 *)buf; @@ -461,7 +480,7 @@ static const struct hc_driver ohci_at91_hc_driver = { static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) { struct platform_device *pdev = data; - struct at91_usbh_data *pdata = pdev->dev.platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); int val, gpio, port; /* From the GPIO notifying the over-current situation, find @@ -567,7 +586,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) if (ret) return ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (pdata) { at91_for_each_port(i) { @@ -643,7 +662,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) { - struct at91_usbh_data *pdata = pdev->dev.platform_data; + struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev); int i; if (pdata) { diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 6aaa9c9c8eb..9be59f11e05 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -85,7 +85,7 @@ static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, static int ohci_da8xx_init(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); int result; u32 rh_a; @@ -171,7 +171,7 @@ static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(dev); int temp; switch (typeReq) { @@ -292,7 +292,7 @@ static const struct hc_driver ohci_da8xx_hc_driver = { static int usb_hcd_da8xx_probe(const struct hc_driver *driver, struct platform_device *pdev) { - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev); struct usb_hcd *hcd; struct resource *mem; int error, irq; @@ -380,7 +380,7 @@ err0: static inline void usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev) { - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; + struct da8xx_ohci_root_hub *hub = dev_get_platdata(&pdev->dev); hub->ocic_notify(NULL); usb_remove_hcd(hcd); diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 8704e9fa5a8..84a20d5223b 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -30,83 +30,6 @@ static struct clk *usb_host_clock; -static void ep93xx_start_hc(struct device *dev) -{ - clk_enable(usb_host_clock); -} - -static void ep93xx_stop_hc(struct device *dev) -{ - clk_disable(usb_host_clock); -} - -static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); - if (hcd == NULL) - return -ENOMEM; - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - usb_put_hcd(hcd); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto err2; - } - - usb_host_clock = clk_get(&pdev->dev, NULL); - if (IS_ERR(usb_host_clock)) { - dev_dbg(&pdev->dev, "clk_get failed\n"); - retval = PTR_ERR(usb_host_clock); - goto err3; - } - - ep93xx_start_hc(&pdev->dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, pdev->resource[1].start, 0); - if (retval == 0) - return retval; - - ep93xx_stop_hc(&pdev->dev); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - - return retval; -} - -static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - ep93xx_stop_hc(&pdev->dev); - clk_put(usb_host_clock); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - static int ohci_ep93xx_start(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -147,15 +70,57 @@ static struct hc_driver ohci_ep93xx_hc_driver = { .start_port_reset = ohci_start_port_reset, }; -extern int usb_disabled(void); - static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) { + struct usb_hcd *hcd; + struct resource *res; + int irq; int ret; - ret = -ENODEV; - if (!usb_disabled()) - ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + hcd->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hcd->regs)) { + ret = PTR_ERR(hcd->regs); + goto err_put_hcd; + } + + usb_host_clock = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(usb_host_clock)) { + ret = PTR_ERR(usb_host_clock); + goto err_put_hcd; + } + + clk_enable(usb_host_clock); + + ohci_hcd_init(hcd_to_ohci(hcd)); + + ret = usb_add_hcd(hcd, irq, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable(usb_host_clock); +err_put_hcd: + usb_put_hcd(hcd); return ret; } @@ -164,7 +129,9 @@ static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - usb_hcd_ep93xx_remove(hcd, pdev); + usb_remove_hcd(hcd); + clk_disable(usb_host_clock); + usb_put_hcd(hcd); return 0; } @@ -179,7 +146,7 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_ msleep(5); ohci->next_statechange = jiffies; - ep93xx_stop_hc(&pdev->dev); + clk_disable(usb_host_clock); return 0; } @@ -192,7 +159,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) msleep(5); ohci->next_statechange = jiffies; - ep93xx_start_hc(&pdev->dev); + clk_enable(usb_host_clock); ohci_resume(hcd, false); return 0; diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index b0b542c14e3..dc6ee9adacf 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -100,7 +100,7 @@ static const struct hc_driver exynos_ohci_hc_driver = { static int exynos_ohci_probe(struct platform_device *pdev) { - struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; + struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev); struct exynos_ohci_hcd *exynos_ohci; struct usb_hcd *hcd; struct ohci_hcd *ohci; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index a9d3437da22..8f6b695af6a 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -938,8 +938,8 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(&ohci->nec_work); - ohci_usb_reset (ohci); ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + ohci_usb_reset(ohci); free_irq(hcd->irq, hcd); hcd->irq = 0; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 8747fa6a51b..31d3a12eb48 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -191,7 +191,7 @@ static void start_hnp(struct ohci_hcd *ohci) static int ohci_omap_init(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct omap_usb_config *config = hcd->self.controller->platform_data; + struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); int need_transceiver = (config->otg != 0); int ret; @@ -427,7 +427,7 @@ ohci_omap_start (struct usb_hcd *hcd) if (!host_enabled) return 0; - config = hcd->self.controller->platform_data; + config = dev_get_platdata(hcd->self.controller); if (config->otg || config->rwc) { ohci->hc_control = OHCI_CTRL_RWC; writel(OHCI_CTRL_RWC, &ohci->regs->control); diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index 8f713571a0b..a09af26f69e 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -231,14 +231,6 @@ static int ohci_hcd_omap3_remove(struct platform_device *pdev) return 0; } -static void ohci_hcd_omap3_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - static const struct of_device_id omap_ohci_dt_ids[] = { { .compatible = "ti,ohci-omap3" }, { } @@ -249,7 +241,7 @@ MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids); static struct platform_driver ohci_hcd_omap3_driver = { .probe = ohci_hcd_omap3_probe, .remove = ohci_hcd_omap3_remove, - .shutdown = ohci_hcd_omap3_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ohci-omap3", .of_match_table = omap_ohci_dt_ids, diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index bc30475c3a2..a4c6410f0ed 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -33,7 +33,7 @@ static const char hcd_name[] = "ohci-platform"; static int ohci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ohci_pdata *pdata = pdev->dev.platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (pdata->big_endian_desc) @@ -59,7 +59,7 @@ static int ohci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; - struct usb_ohci_pdata *pdata = dev->dev.platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); int irq; int err = -ENOMEM; @@ -124,7 +124,7 @@ err_power: static int ohci_platform_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); - struct usb_ohci_pdata *pdata = dev->dev.platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); @@ -139,7 +139,7 @@ static int ohci_platform_remove(struct platform_device *dev) static int ohci_platform_suspend(struct device *dev) { - struct usb_ohci_pdata *pdata = dev->platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); @@ -152,7 +152,7 @@ static int ohci_platform_suspend(struct device *dev) static int ohci_platform_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); - struct usb_ohci_pdata *pdata = dev->platform_data; + struct usb_ohci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 8294e2fcc2f..75f5a1e2f01 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -200,15 +200,6 @@ static int ohci_hcd_ppc_of_remove(struct platform_device *op) return 0; } -static void ohci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = platform_get_drvdata(op); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - static const struct of_device_id ohci_hcd_ppc_of_match[] = { #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE { @@ -243,7 +234,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); static struct platform_driver ohci_hcd_ppc_of_driver = { .probe = ohci_hcd_ppc_of_probe, .remove = ohci_hcd_ppc_of_remove, - .shutdown = ohci_hcd_ppc_of_shutdown, + .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ohci", .owner = THIS_MODULE, diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 3a9c01d8b79..93371a235e8 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -219,7 +219,7 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) struct pxaohci_platform_data *inf; uint32_t uhchr; - inf = dev->platform_data; + inf = dev_get_platdata(dev); clk_prepare_enable(ohci->clk); @@ -256,7 +256,7 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) struct pxaohci_platform_data *inf; uint32_t uhccoms; - inf = dev->platform_data; + inf = dev_get_platdata(dev); if (cpu_is_pxa3xx()) pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); @@ -364,7 +364,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device if (retval) return retval; - inf = pdev->dev.platform_data; + inf = dev_get_platdata(&pdev->dev); if (!inf) return -ENODEV; @@ -577,7 +577,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - struct pxaohci_platform_data *inf = dev->platform_data; + struct pxaohci_platform_data *inf = dev_get_platdata(dev); int status; if (time_before(jiffies, ohci->ohci.next_statechange)) diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index e125770b893..4919afa4125 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -38,12 +38,12 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) { - return hcd->self.controller->platform_data; + return dev_get_platdata(hcd->self.controller); } static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) { - struct s3c2410_hcd_info *info = dev->dev.platform_data; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); @@ -63,7 +63,7 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) static void s3c2410_stop_hc(struct platform_device *dev) { - struct s3c2410_hcd_info *info = dev->dev.platform_data; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); dev_dbg(&dev->dev, "s3c2410_stop_hc:\n"); @@ -339,10 +339,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, struct platform_device *dev) { struct usb_hcd *hcd = NULL; + struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev); int retval; - s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); - s3c2410_usb_set_power(dev->dev.platform_data, 2, 1); + s3c2410_usb_set_power(info, 1, 1); + s3c2410_usb_set_power(info, 2, 1); hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); if (hcd == NULL) diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c index 197d514fe0d..22540ab71f5 100644 --- a/drivers/usb/host/ohci-tilegx.c +++ b/drivers/usb/host/ohci-tilegx.c @@ -95,7 +95,7 @@ static const struct hc_driver ohci_tilegx_hc_driver = { static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; - struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); pte_t pte = { 0 }; int my_cpu = smp_processor_id(); int ret; @@ -175,7 +175,7 @@ err_hcd: static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data; + struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index b9848e4d3d4..2c76ef1320e 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -735,32 +735,6 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, return -ETIMEDOUT; } -#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 -#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31 - -bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; -} - -/* The Intel Lynx Point chipset also has switchable ports. */ -bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - (pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI); -} - -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) -{ - return usb_is_intel_ppt_switchable_xhci(pdev) || - usb_is_intel_lpt_switchable_xhci(pdev); -} -EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); - /* * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that * share some number of ports. These ports can be switched between either @@ -779,9 +753,23 @@ EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); * terminations before switching the USB 2.0 wires over, so that USB 3.0 * devices connect at SuperSpeed, rather than at USB 2.0 speeds. */ -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) +void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) { u32 ports_available; + bool ehci_found = false; + struct pci_dev *companion = NULL; + + /* make sure an intel EHCI controller exists */ + for_each_pci_dev(companion) { + if (companion->class == PCI_CLASS_SERIAL_USB_EHCI && + companion->vendor == PCI_VENDOR_ID_INTEL) { + ehci_found = true; + break; + } + } + + if (!ehci_found) + return; /* Don't switchover the ports if the user hasn't compiled the xHCI * driver. Otherwise they will see "dead" USB ports that don't power @@ -840,7 +828,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over " "to xHCI: 0x%x\n", ports_available); } -EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); +EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) { @@ -921,8 +909,8 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev) writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); hc_init: - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); op_reg_base = base + XHCI_HC_LENGTH(readl(base)); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 978c849f9c9..ed6700d00fe 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -8,8 +8,7 @@ int usb_amd_find_chipset_info(void); void usb_amd_dev_put(void); void usb_amd_quirk_pll_disable(void); void usb_amd_quirk_pll_enable(void); -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); +void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); #else diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index a6fd8f5371d..a9eef6822a2 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2467,7 +2467,7 @@ static int r8a66597_probe(struct platform_device *pdev) r8a66597 = hcd_to_r8a66597(hcd); memset(r8a66597, 0, sizeof(struct r8a66597)); dev_set_drvdata(&pdev->dev, r8a66597); - r8a66597->pdata = pdev->dev.platform_data; + r8a66597->pdata = dev_get_platdata(&pdev->dev); r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; if (r8a66597->pdata->on_chip) { diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index b2ec7fe758d..5477bf5df21 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -48,6 +48,8 @@ #include <linux/usb/hcd.h> #include <linux/platform_device.h> #include <linux/prefetch.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <asm/io.h> #include <asm/irq.h> @@ -63,11 +65,6 @@ MODULE_ALIAS("platform:sl811-hcd"); #define DRIVER_VERSION "19 May 2005" - -#ifndef DEBUG -# define STUB_DEBUG_FILE -#endif - /* for now, use only one transfer register bank */ #undef USE_B @@ -100,7 +97,8 @@ static void port_power(struct sl811 *sl811, int is_on) if (sl811->board && sl811->board->port_power) { /* switch VBUS, at 500mA unless hub power budget gets set */ - DBG("power %s\n", is_on ? "on" : "off"); + dev_dbg(hcd->self.controller, "power %s\n", + is_on ? "on" : "off"); sl811->board->port_power(hcd->self.controller, is_on); } @@ -282,7 +280,7 @@ static inline void sofirq_on(struct sl811 *sl811) { if (sl811->irq_enable & SL11H_INTMASK_SOFINTR) return; - VDBG("sof irq on\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq on\n"); sl811->irq_enable |= SL11H_INTMASK_SOFINTR; } @@ -290,7 +288,7 @@ static inline void sofirq_off(struct sl811 *sl811) { if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR)) return; - VDBG("sof irq off\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq off\n"); sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR; } @@ -338,7 +336,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) } if (unlikely(list_empty(&ep->hep->urb_list))) { - DBG("empty %p queue?\n", ep); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "empty %p queue?\n", ep); return NULL; } @@ -391,7 +390,8 @@ static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) status_packet(sl811, ep, urb, bank, control); break; default: - DBG("bad ep%p pid %02x\n", ep, ep->nextpid); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "bad ep%p pid %02x\n", ep, ep->nextpid); ep = NULL; } return ep; @@ -447,7 +447,8 @@ static void finish_request( } /* periodic deschedule */ - DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { struct sl811h_ep *temp; struct sl811h_ep **prev = &sl811->periodic[i]; @@ -593,7 +594,8 @@ static inline u8 checkdone(struct sl811 *sl811) ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)); if (ctl & SL11H_HCTLMASK_ARM) sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_A: ctrl %02x sts %02x\n", + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "%s DONE_A: ctrl %02x sts %02x\n", (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", ctl, sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); @@ -604,7 +606,8 @@ static inline u8 checkdone(struct sl811 *sl811) ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)); if (ctl & SL11H_HCTLMASK_ARM) sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_B: ctrl %02x sts %02x\n", + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "%s DONE_B: ctrl %02x sts %02x\n", (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", ctl, sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); @@ -665,7 +668,7 @@ retry: * this one has nothing scheduled. */ if (sl811->next_periodic) { - // ERR("overrun to slot %d\n", index); + // dev_err(hcd->self.controller, "overrun to slot %d\n", index); sl811->stat_overrun++; } if (sl811->periodic[index]) @@ -723,7 +726,7 @@ retry: } else if (irqstat & SL11H_INTMASK_RD) { if (sl811->port1 & USB_PORT_STAT_SUSPEND) { - DBG("wakeup\n"); + dev_dbg(hcd->self.controller, "wakeup\n"); sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16; sl811->stat_wake++; } else @@ -852,8 +855,9 @@ static int sl811h_urb_enqueue( if (ep->maxpacket > H_MAXPACKET) { /* iso packets up to 240 bytes could work... */ - DBG("dev %d ep%d maxpacket %d\n", - udev->devnum, epnum, ep->maxpacket); + dev_dbg(hcd->self.controller, + "dev %d ep%d maxpacket %d\n", udev->devnum, + epnum, ep->maxpacket); retval = -EINVAL; kfree(ep); goto fail; @@ -917,7 +921,8 @@ static int sl811h_urb_enqueue( * to share the faster parts of the tree without needing * dummy/placeholder nodes */ - DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + dev_dbg(hcd->self.controller, "schedule qh%d/%p branch %d\n", + ep->period, ep, ep->branch); for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { struct sl811h_ep **prev = &sl811->periodic[i]; struct sl811h_ep *here = *prev; @@ -976,7 +981,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } else if (sl811->active_a == ep) { if (time_before_eq(sl811->jiffies_a, jiffies)) { /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_A: ctrl %02x sts %02x\n", + dev_dbg(hcd->self.controller, + "giveup on DONE_A: ctrl %02x sts %02x\n", sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)), sl811_read(sl811, @@ -990,7 +996,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } else if (sl811->active_b == ep) { if (time_before_eq(sl811->jiffies_a, jiffies)) { /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_B: ctrl %02x sts %02x\n", + dev_dbg(hcd->self.controller, + "giveup on DONE_B: ctrl %02x sts %02x\n", sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)), sl811_read(sl811, @@ -1008,7 +1015,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (urb) finish_request(sl811, ep, urb, 0); else - VDBG("dequeue, urb %p active %s; wait4irq\n", urb, + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else retval = -EINVAL; @@ -1029,7 +1037,7 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) if (!list_empty(&hep->urb_list)) msleep(3); if (!list_empty(&hep->urb_list)) - WARNING("ep %p not empty?\n", ep); + dev_warn(hcd->self.controller, "ep %p not empty?\n", ep); kfree(ep); hep->hcpriv = NULL; @@ -1132,7 +1140,7 @@ sl811h_timer(unsigned long _sl811) switch (signaling) { case SL11H_CTL1MASK_SE0: - DBG("end reset\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "end reset\n"); sl811->port1 = (USB_PORT_STAT_C_RESET << 16) | USB_PORT_STAT_POWER; sl811->ctrl1 = 0; @@ -1141,11 +1149,12 @@ sl811h_timer(unsigned long _sl811) irqstat &= ~SL11H_INTMASK_RD; break; case SL11H_CTL1MASK_K: - DBG("end resume\n"); + dev_dbg(sl811_to_hcd(sl811)->self.controller, "end resume\n"); sl811->port1 &= ~USB_PORT_STAT_SUSPEND; break; default: - DBG("odd timer signaling: %02x\n", signaling); + dev_dbg(sl811_to_hcd(sl811)->self.controller, + "odd timer signaling: %02x\n", signaling); break; } sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); @@ -1243,7 +1252,7 @@ sl811h_hub_control( break; /* 20 msec of resume/K signaling, other irqs blocked */ - DBG("start resume...\n"); + dev_dbg(hcd->self.controller, "start resume...\n"); sl811->irq_enable = 0; sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); @@ -1281,7 +1290,8 @@ sl811h_hub_control( #ifndef VERBOSE if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ #endif - DBG("GetPortStatus %08x\n", sl811->port1); + dev_dbg(hcd->self.controller, "GetPortStatus %08x\n", + sl811->port1); break; case SetPortFeature: if (wIndex != 1 || wLength != 0) @@ -1293,7 +1303,7 @@ sl811h_hub_control( if (!(sl811->port1 & USB_PORT_STAT_ENABLE)) goto error; - DBG("suspend...\n"); + dev_dbg(hcd->self.controller,"suspend...\n"); sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA; sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); break; @@ -1338,7 +1348,7 @@ static int sl811h_bus_suspend(struct usb_hcd *hcd) { // SOFs off - DBG("%s\n", __func__); + dev_dbg(hcd->self.controller, "%s\n", __func__); return 0; } @@ -1346,7 +1356,7 @@ static int sl811h_bus_resume(struct usb_hcd *hcd) { // SOFs on - DBG("%s\n", __func__); + dev_dbg(hcd->self.controller, "%s\n", __func__); return 0; } @@ -1360,16 +1370,6 @@ sl811h_bus_resume(struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct sl811 *sl811) { } -static inline void remove_debug_file(struct sl811 *sl811) { } - -#else - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - static void dump_irq(struct seq_file *s, char *label, u8 mask) { seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask, @@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask) (mask & SL11H_INTMASK_DP) ? " dp" : ""); } -static int proc_sl811h_show(struct seq_file *s, void *unused) +static int sl811h_show(struct seq_file *s, void *unused) { struct sl811 *sl811 = s->private; struct sl811h_ep *ep; @@ -1492,34 +1492,31 @@ static int proc_sl811h_show(struct seq_file *s, void *unused) return 0; } -static int proc_sl811h_open(struct inode *inode, struct file *file) +static int sl811h_open(struct inode *inode, struct file *file) { - return single_open(file, proc_sl811h_show, PDE_DATA(inode)); + return single_open(file, sl811h_show, inode->i_private); } -static const struct file_operations proc_ops = { - .open = proc_sl811h_open, +static const struct file_operations debug_ops = { + .open = sl811h_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; /* expect just one sl811 per system */ -static const char proc_filename[] = "driver/sl811h"; - static void create_debug_file(struct sl811 *sl811) { - sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); + sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO, + usb_debug_root, sl811, + &debug_ops); } static void remove_debug_file(struct sl811 *sl811) { - if (sl811->pde) - remove_proc_entry(proc_filename, NULL); + debugfs_remove(sl811->debug_file); } -#endif - /*-------------------------------------------------------------------------*/ static void @@ -1648,7 +1645,7 @@ sl811h_probe(struct platform_device *dev) /* refuse to confuse usbcore */ if (dev->dev.dma_mask) { - DBG("no we won't dma\n"); + dev_dbg(&dev->dev, "no we won't dma\n"); return -EINVAL; } @@ -1694,7 +1691,7 @@ sl811h_probe(struct platform_device *dev) spin_lock_init(&sl811->lock); INIT_LIST_HEAD(&sl811->async); - sl811->board = dev->dev.platform_data; + sl811->board = dev_get_platdata(&dev->dev); init_timer(&sl811->timer); sl811->timer.function = sl811h_timer; sl811->timer.data = (unsigned long) sl811; @@ -1716,7 +1713,7 @@ sl811h_probe(struct platform_device *dev) break; default: /* reject case 0, SL11S is less functional */ - DBG("chiprev %02x\n", tmp); + dev_dbg(&dev->dev, "chiprev %02x\n", tmp); retval = -ENXIO; goto err6; } @@ -1747,7 +1744,7 @@ sl811h_probe(struct platform_device *dev) if (!ioaddr) iounmap(addr_reg); err2: - DBG("init error, %d\n", retval); + dev_dbg(&dev->dev, "init error, %d\n", retval); return retval; } diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h index b6b8c1f233d..1e23ef49bec 100644 --- a/drivers/usb/host/sl811.h +++ b/drivers/usb/host/sl811.h @@ -122,7 +122,7 @@ struct sl811 { void __iomem *addr_reg; void __iomem *data_reg; struct sl811_platform_data *board; - struct proc_dir_entry *pde; + struct dentry *debug_file; unsigned long stat_insrmv; unsigned long stat_wake; @@ -242,25 +242,8 @@ sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count) /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "sl811: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - #ifdef PACKET_TRACE -# define PACKET VDBG +# define PACKET pr_debug("sl811: "stuff) #else # define PACKET(stuff...) do{}while(0) #endif - -#define ERR(stuff...) printk(KERN_ERR "sl811: " stuff) -#define WARNING(stuff...) printk(KERN_WARNING "sl811: " stuff) -#define INFO(stuff...) printk(KERN_INFO "sl811: " stuff) - diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5c124bf5d01..e402beb5a06 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -1809,9 +1809,9 @@ static int u132_hcd_start(struct usb_hcd *hcd) struct platform_device *pdev = to_platform_device(hcd->self.controller); u16 vendor = ((struct u132_platform_data *) - (pdev->dev.platform_data))->vendor; + dev_get_platdata(&pdev->dev))->vendor; u16 device = ((struct u132_platform_data *) - (pdev->dev.platform_data))->device; + dev_get_platdata(&pdev->dev))->device; mutex_lock(&u132->sw_lock); msleep(10); if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { @@ -3034,7 +3034,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) int addrs = MAX_U132_ADDRS; int udevs = MAX_U132_UDEVS; int endps = MAX_U132_ENDPS; - u132->board = pdev->dev.platform_data; + u132->board = dev_get_platdata(&pdev->dev); u132->platform_dev = pdev; u132->power = 0; u132->reset = 0; diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1d3545943c5..93f3fdf0ff0 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -461,8 +461,15 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, } } +/* Updates Link Status for USB 2.1 port */ +static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg) +{ + if ((status_reg & PORT_PLS_MASK) == XDEV_U2) + *status |= USB_PORT_STAT_L1; +} + /* Updates Link Status for super Speed port */ -static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg) { u32 pls = status_reg & PORT_PLS_MASK; @@ -534,6 +541,120 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) } } +/* + * Converts a raw xHCI port status into the format that external USB 2.0 or USB + * 3.0 hubs use. + * + * Possible side effects: + * - Mark a port as being done with device resume, + * and ring the endpoint doorbells. + * - Stop the Synopsys redriver Compliance Mode polling. + */ +static u32 xhci_get_port_status(struct usb_hcd *hcd, + struct xhci_bus_state *bus_state, + __le32 __iomem **port_array, + u16 wIndex, u32 raw_port_status) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + u32 status = 0; + int slot_id; + + /* wPortChange bits */ + if (raw_port_status & PORT_CSC) + status |= USB_PORT_STAT_C_CONNECTION << 16; + if (raw_port_status & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + if ((raw_port_status & PORT_OCC)) + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + if ((raw_port_status & PORT_RC)) + status |= USB_PORT_STAT_C_RESET << 16; + /* USB3.0 only */ + if (hcd->speed == HCD_USB3) { + if ((raw_port_status & PORT_PLC)) + status |= USB_PORT_STAT_C_LINK_STATE << 16; + if ((raw_port_status & PORT_WRC)) + status |= USB_PORT_STAT_C_BH_RESET << 16; + } + + if (hcd->speed != HCD_USB3) { + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3 + && (raw_port_status & PORT_POWER)) + status |= USB_PORT_STAT_SUSPEND; + } + if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME && + !DEV_SUPERSPEED(raw_port_status)) { + if ((raw_port_status & PORT_RESET) || + !(raw_port_status & PORT_PE)) + return 0xffffffff; + if (time_after_eq(jiffies, + bus_state->resume_done[wIndex])) { + xhci_dbg(xhci, "Resume USB2 port %d\n", + wIndex + 1); + bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); + xhci_set_link_state(xhci, port_array, wIndex, + XDEV_U0); + xhci_dbg(xhci, "set port %d resume\n", + wIndex + 1); + slot_id = xhci_find_slot_id_by_port(hcd, xhci, + wIndex + 1); + if (!slot_id) { + xhci_dbg(xhci, "slot_id is zero\n"); + return 0xffffffff; + } + xhci_ring_device(xhci, slot_id); + bus_state->port_c_suspend |= 1 << wIndex; + bus_state->suspended_ports &= ~(1 << wIndex); + } else { + /* + * The resume has been signaling for less than + * 20ms. Report the port status as SUSPEND, + * let the usbcore check port status again + * and clear resume signaling later. + */ + status |= USB_PORT_STAT_SUSPEND; + } + } + if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 + && (raw_port_status & PORT_POWER) + && (bus_state->suspended_ports & (1 << wIndex))) { + bus_state->suspended_ports &= ~(1 << wIndex); + if (hcd->speed != HCD_USB3) + bus_state->port_c_suspend |= 1 << wIndex; + } + if (raw_port_status & PORT_CONNECT) { + status |= USB_PORT_STAT_CONNECTION; + status |= xhci_port_speed(raw_port_status); + } + if (raw_port_status & PORT_PE) + status |= USB_PORT_STAT_ENABLE; + if (raw_port_status & PORT_OC) + status |= USB_PORT_STAT_OVERCURRENT; + if (raw_port_status & PORT_RESET) + status |= USB_PORT_STAT_RESET; + if (raw_port_status & PORT_POWER) { + if (hcd->speed == HCD_USB3) + status |= USB_SS_PORT_STAT_POWER; + else + status |= USB_PORT_STAT_POWER; + } + /* Update Port Link State */ + if (hcd->speed == HCD_USB3) { + xhci_hub_report_usb3_link_state(&status, raw_port_status); + /* + * Verify if all USB3 Ports Have entered U0 already. + * Delete Compliance Mode Timer if so. + */ + xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex); + } else { + xhci_hub_report_usb2_link_state(&status, raw_port_status); + } + if (bus_state->port_c_suspend & (1 << wIndex)) + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + + return status; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -598,104 +719,20 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (!wIndex || wIndex > max_ports) goto error; wIndex--; - status = 0; temp = xhci_readl(xhci, port_array[wIndex]); if (temp == 0xffffffff) { retval = -ENODEV; break; } - xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); - - /* wPortChange bits */ - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - if (temp & PORT_PEC) - status |= USB_PORT_STAT_C_ENABLE << 16; - if ((temp & PORT_OCC)) - status |= USB_PORT_STAT_C_OVERCURRENT << 16; - if ((temp & PORT_RC)) - status |= USB_PORT_STAT_C_RESET << 16; - /* USB3.0 only */ - if (hcd->speed == HCD_USB3) { - if ((temp & PORT_PLC)) - status |= USB_PORT_STAT_C_LINK_STATE << 16; - if ((temp & PORT_WRC)) - status |= USB_PORT_STAT_C_BH_RESET << 16; - } + status = xhci_get_port_status(hcd, bus_state, port_array, + wIndex, temp); + if (status == 0xffffffff) + goto error; - if (hcd->speed != HCD_USB3) { - if ((temp & PORT_PLS_MASK) == XDEV_U3 - && (temp & PORT_POWER)) - status |= USB_PORT_STAT_SUSPEND; - } - if ((temp & PORT_PLS_MASK) == XDEV_RESUME && - !DEV_SUPERSPEED(temp)) { - if ((temp & PORT_RESET) || !(temp & PORT_PE)) - goto error; - if (time_after_eq(jiffies, - bus_state->resume_done[wIndex])) { - xhci_dbg(xhci, "Resume USB2 port %d\n", - wIndex + 1); - bus_state->resume_done[wIndex] = 0; - clear_bit(wIndex, &bus_state->resuming_ports); - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_U0); - xhci_dbg(xhci, "set port %d resume\n", - wIndex + 1); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - goto error; - } - xhci_ring_device(xhci, slot_id); - bus_state->port_c_suspend |= 1 << wIndex; - bus_state->suspended_ports &= ~(1 << wIndex); - } else { - /* - * The resume has been signaling for less than - * 20ms. Report the port status as SUSPEND, - * let the usbcore check port status again - * and clear resume signaling later. - */ - status |= USB_PORT_STAT_SUSPEND; - } - } - if ((temp & PORT_PLS_MASK) == XDEV_U0 - && (temp & PORT_POWER) - && (bus_state->suspended_ports & (1 << wIndex))) { - bus_state->suspended_ports &= ~(1 << wIndex); - if (hcd->speed != HCD_USB3) - bus_state->port_c_suspend |= 1 << wIndex; - } - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - status |= xhci_port_speed(temp); - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (temp & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) { - if (hcd->speed == HCD_USB3) - status |= USB_SS_PORT_STAT_POWER; - else - status |= USB_PORT_STAT_POWER; - } - /* Update Port Link State for super speed ports*/ - if (hcd->speed == HCD_USB3) { - xhci_hub_report_link_state(&status, temp); - /* - * Verify if all USB3 Ports Have entered U0 already. - * Delete Compliance Mode Timer if so. - */ - xhci_del_comp_mod_timer(xhci, temp, wIndex); - } - if (bus_state->port_c_suspend & (1 << wIndex)) - status |= 1 << USB_PORT_FEAT_C_SUSPEND; + xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", + wIndex, temp); xhci_dbg(xhci, "Get port status returned 0x%x\n", status); + put_unaligned(cpu_to_le32(status), (__le32 *) buf); break; case SetPortFeature: diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index f00cb203fae..72960684a94 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -249,13 +249,15 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) * writers. * * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. + * It should not matter whether the EHCI or xHCI controller is + * resumed first. It's enough to do the switchover in xHCI because + * USB core won't notice anything as the hub driver doesn't start + * running again until after all the devices (including both EHCI and + * xHCI host controllers) have been resumed. */ - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); + + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); retval = xhci_resume(xhci, hibernated); return retval; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 51e22bf8950..412fe8d167c 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -186,11 +186,37 @@ static int xhci_plat_remove(struct platform_device *dev) return 0; } +#ifdef CONFIG_PM +static int xhci_plat_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_suspend(xhci); +} + +static int xhci_plat_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + return xhci_resume(xhci, 0); +} + +static const struct dev_pm_ops xhci_plat_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume) +}; +#define DEV_PM_OPS (&xhci_plat_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, .driver = { .name = "xhci-hcd", + .pm = DEV_PM_OPS, }, }; MODULE_ALIAS("platform:xhci-hcd"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 41eb4fc3345..246de8905db 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3075,8 +3075,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, /* Are streams already being freed for the endpoint? */ if (ep_state & EP_GETTING_NO_STREAMS) { xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are being disabled already.", + "endpoint 0x%x, " + "streams are being disabled already\n", eps[i]->desc.bEndpointAddress); return 0; } @@ -3084,8 +3084,8 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, if (!(ep_state & EP_HAS_STREAMS) && !(ep_state & EP_GETTING_STREAMS)) { xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are already disabled!", + "endpoint 0x%x, " + "streams are already disabled!\n", eps[i]->desc.bEndpointAddress); xhci_warn(xhci, "WARN xhci_free_streams() called " "with non-streams endpoint\n"); @@ -4353,7 +4353,7 @@ static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, state_name, sel); else dev_dbg(&udev->dev, "Device-initiated %s disabled " - "due to long PEL %llu\n ms", + "due to long PEL %llu ms\n", state_name, pel); return USB3_LPM_DISABLED; } @@ -4841,6 +4841,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) /* Accept arbitrarily long scatter-gather lists */ hcd->self.sg_tablesize = ~0; + + /* support to build packet from discontinuous buffers */ + hcd->self.no_sg_constraint = 1; + /* XHCI controllers don't stop the ep queue on short packets :| */ hcd->self.no_stop_on_short = 1; diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a51e7d6afda..e2b21c1d9c4 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -200,6 +200,19 @@ config USB_TEST See <http://www.linux-usb.org/usbtest/> for more information, including sample test device firmware and "how to use it". +config USB_EHSET_TEST_FIXTURE + tristate "USB EHSET Test Fixture driver" + help + Say Y here if you want to support the special test fixture device + used for the USB-IF Embedded Host High-Speed Electrical Test procedure. + + When the test fixture is connected, it can enumerate as one of several + VID/PID pairs. This driver then initiates a corresponding test mode on + the downstream port to which the test fixture is attached. + + See <http://www.usb.org/developers/onthego/EHSET_v1.01.pdf> for more + information. + config USB_ISIGHTFW tristate "iSight firmware loading support" select FW_LOADER @@ -233,5 +246,6 @@ config USB_EZUSB_FX2 config USB_HSIC_USB3503 tristate "USB3503 HSIC to USB20 Driver" depends on I2C + select REGMAP help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 3e1bd70b06e..e748fd5dbe9 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -2,9 +2,6 @@ # Makefile for the rest of the USB drivers # (the ones that don't fit into any other categories) # - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - obj-$(CONFIG_USB_ADUTUX) += adutux.o obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o obj-$(CONFIG_USB_CYPRESS_CY7C63) += cypress_cy7c63.o @@ -22,6 +19,7 @@ obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o +obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index eb3c8c142fa..7078e9bf0fc 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -18,6 +18,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -27,30 +29,11 @@ #include <linux/mutex.h> #include <linux/uaccess.h> -#ifdef CONFIG_USB_DEBUG -static int debug = 5; -#else -static int debug = 1; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(lvl, format, arg...) \ -do { \ - if (debug >= lvl) \ - printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ -} while (0) - - /* Version Information */ #define DRIVER_VERSION "v0.0.13" #define DRIVER_AUTHOR "John Homppi" #define DRIVER_DESC "adutux (see www.ontrak.net)" -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - /* Define these values to match your device */ #define ADU_VENDOR_ID 0x0a07 #define ADU_PRODUCT_ID 0x0064 @@ -124,19 +107,11 @@ static DEFINE_MUTEX(adutux_mutex); static struct usb_driver adu_driver; -static void adu_debug_data(int level, const char *function, int size, - const unsigned char *data) +static inline void adu_debug_data(struct device *dev, const char *function, + int size, const unsigned char *data) { - int i; - - if (debug < level) - return; - - printk(KERN_DEBUG "%s: %s - length = %d, data = ", - __FILE__, function, size); - for (i = 0; i < size; ++i) - printk("%.2x ", data[i]); - printk("\n"); + dev_dbg(dev, "%s - length = %d, data = %*ph\n", + function, size, size, data); } /** @@ -147,12 +122,8 @@ static void adu_abort_transfers(struct adu_device *dev) { unsigned long flags; - dbg(2, " %s : enter", __func__); - - if (dev->udev == NULL) { - dbg(1, " %s : udev is null", __func__); - goto exit; - } + if (dev->udev == NULL) + return; /* shutdown transfer */ @@ -170,15 +141,10 @@ static void adu_abort_transfers(struct adu_device *dev) usb_kill_urb(dev->interrupt_out_urb); } else spin_unlock_irqrestore(&dev->buflock, flags); - -exit: - dbg(2, " %s : leave", __func__); } static void adu_delete(struct adu_device *dev) { - dbg(2, "%s enter", __func__); - /* free data structures */ usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_out_urb); @@ -187,8 +153,6 @@ static void adu_delete(struct adu_device *dev) kfree(dev->interrupt_in_buffer); kfree(dev->interrupt_out_buffer); kfree(dev); - - dbg(2, "%s : leave", __func__); } static void adu_interrupt_in_callback(struct urb *urb) @@ -196,17 +160,17 @@ static void adu_interrupt_in_callback(struct urb *urb) struct adu_device *dev = urb->context; int status = urb->status; - dbg(4, " %s : enter, status %d", __func__, status); - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); + adu_debug_data(&dev->udev->dev, __func__, + urb->actual_length, urb->transfer_buffer); spin_lock(&dev->buflock); if (status != 0) { if ((status != -ENOENT) && (status != -ECONNRESET) && (status != -ESHUTDOWN)) { - dbg(1, " %s : nonzero status received: %d", - __func__, status); + dev_dbg(&dev->udev->dev, + "%s : nonzero status received: %d\n", + __func__, status); } goto exit; } @@ -220,10 +184,11 @@ static void adu_interrupt_in_callback(struct urb *urb) dev->interrupt_in_buffer, urb->actual_length); dev->read_buffer_length += urb->actual_length; - dbg(2, " %s reading %d ", __func__, - urb->actual_length); + dev_dbg(&dev->udev->dev,"%s reading %d\n", __func__, + urb->actual_length); } else { - dbg(1, " %s : read_buffer overflow", __func__); + dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n", + __func__); } } @@ -232,9 +197,6 @@ exit: spin_unlock(&dev->buflock); /* always wake up so we recover from errors */ wake_up_interruptible(&dev->read_wait); - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); - dbg(4, " %s : leave, status %d", __func__, status); } static void adu_interrupt_out_callback(struct urb *urb) @@ -242,27 +204,23 @@ static void adu_interrupt_out_callback(struct urb *urb) struct adu_device *dev = urb->context; int status = urb->status; - dbg(4, " %s : enter, status %d", __func__, status); - adu_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); + adu_debug_data(&dev->udev->dev, __func__, + urb->actual_length, urb->transfer_buffer); if (status != 0) { if ((status != -ENOENT) && (status != -ECONNRESET)) { - dbg(1, " %s :nonzero status received: %d", - __func__, status); + dev_dbg(&dev->udev->dev, + "%s :nonzero status received: %d\n", __func__, + status); } - goto exit; + return; } spin_lock(&dev->buflock); dev->out_urb_finished = 1; wake_up(&dev->write_wait); spin_unlock(&dev->buflock); -exit: - - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); - dbg(4, " %s : leave, status %d", __func__, status); } static int adu_open(struct inode *inode, struct file *file) @@ -272,20 +230,16 @@ static int adu_open(struct inode *inode, struct file *file) int subminor; int retval; - dbg(2, "%s : enter", __func__); - subminor = iminor(inode); retval = mutex_lock_interruptible(&adutux_mutex); - if (retval) { - dbg(2, "%s : mutex lock failed", __func__); + if (retval) goto exit_no_lock; - } interface = usb_find_interface(&adu_driver, subminor); if (!interface) { - printk(KERN_ERR "adutux: %s - error, can't find device for " - "minor %d\n", __func__, subminor); + pr_err("%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit_no_device; } @@ -303,7 +257,8 @@ static int adu_open(struct inode *inode, struct file *file) } ++dev->open_count; - dbg(2, "%s : open count %d", __func__, dev->open_count); + dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__, + dev->open_count); /* save device in the file's private structure */ file->private_data = dev; @@ -333,23 +288,19 @@ static int adu_open(struct inode *inode, struct file *file) exit_no_device: mutex_unlock(&adutux_mutex); exit_no_lock: - dbg(2, "%s : leave, return value %d ", __func__, retval); return retval; } static void adu_release_internal(struct adu_device *dev) { - dbg(2, " %s : enter", __func__); - /* decrement our usage count for the device */ --dev->open_count; - dbg(2, " %s : open count %d", __func__, dev->open_count); + dev_dbg(&dev->udev->dev, "%s : open count %d\n", __func__, + dev->open_count); if (dev->open_count <= 0) { adu_abort_transfers(dev); dev->open_count = 0; } - - dbg(2, " %s : leave", __func__); } static int adu_release(struct inode *inode, struct file *file) @@ -357,17 +308,13 @@ static int adu_release(struct inode *inode, struct file *file) struct adu_device *dev; int retval = 0; - dbg(2, " %s : enter", __func__); - if (file == NULL) { - dbg(1, " %s : file is NULL", __func__); retval = -ENODEV; goto exit; } dev = file->private_data; if (dev == NULL) { - dbg(1, " %s : object is NULL", __func__); retval = -ENODEV; goto exit; } @@ -375,7 +322,7 @@ static int adu_release(struct inode *inode, struct file *file) mutex_lock(&adutux_mutex); /* not interruptible */ if (dev->open_count <= 0) { - dbg(1, " %s : device not opened", __func__); + dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__); retval = -ENODEV; goto unlock; } @@ -389,7 +336,6 @@ static int adu_release(struct inode *inode, struct file *file) unlock: mutex_unlock(&adutux_mutex); exit: - dbg(2, " %s : leave, return value %d", __func__, retval); return retval; } @@ -406,35 +352,32 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, unsigned long flags; DECLARE_WAITQUEUE(wait, current); - dbg(2, " %s : enter, count = %Zd, file=%p", __func__, count, file); - dev = file->private_data; - dbg(2, " %s : dev=%p", __func__, dev); - if (mutex_lock_interruptible(&dev->mtx)) return -ERESTARTSYS; /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - printk(KERN_ERR "adutux: No device or device unplugged %d\n", - retval); + pr_err("No device or device unplugged %d\n", retval); goto exit; } /* verify that some data was requested */ if (count == 0) { - dbg(1, " %s : read request of 0 bytes", __func__); + dev_dbg(&dev->udev->dev, "%s : read request of 0 bytes\n", + __func__); goto exit; } timeout = COMMAND_TIMEOUT; - dbg(2, " %s : about to start looping", __func__); + dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__); while (bytes_to_read) { int data_in_secondary = dev->secondary_tail - dev->secondary_head; - dbg(2, " %s : while, data_in_secondary=%d, status=%d", - __func__, data_in_secondary, - dev->interrupt_in_urb->status); + dev_dbg(&dev->udev->dev, + "%s : while, data_in_secondary=%d, status=%d\n", + __func__, data_in_secondary, + dev->interrupt_in_urb->status); if (data_in_secondary) { /* drain secondary buffer */ @@ -457,8 +400,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, if (dev->read_buffer_length) { /* we secure access to the primary */ char *tmp; - dbg(2, " %s : swap, read_buffer_length = %d", - __func__, dev->read_buffer_length); + dev_dbg(&dev->udev->dev, + "%s : swap, read_buffer_length = %d\n", + __func__, dev->read_buffer_length); tmp = dev->read_buffer_secondary; dev->read_buffer_secondary = dev->read_buffer_primary; dev->read_buffer_primary = tmp; @@ -473,10 +417,14 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, if (!dev->read_urb_finished) { /* somebody is doing IO */ spin_unlock_irqrestore(&dev->buflock, flags); - dbg(2, " %s : submitted already", __func__); + dev_dbg(&dev->udev->dev, + "%s : submitted already\n", + __func__); } else { /* we must initiate input */ - dbg(2, " %s : initiate input", __func__); + dev_dbg(&dev->udev->dev, + "%s : initiate input\n", + __func__); dev->read_urb_finished = 0; spin_unlock_irqrestore(&dev->buflock, flags); @@ -494,7 +442,9 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, if (retval == -ENOMEM) { retval = bytes_read ? bytes_read : -ENOMEM; } - dbg(2, " %s : submit failed", __func__); + dev_dbg(&dev->udev->dev, + "%s : submit failed\n", + __func__); goto exit; } } @@ -513,13 +463,16 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, remove_wait_queue(&dev->read_wait, &wait); if (timeout <= 0) { - dbg(2, " %s : timeout", __func__); + dev_dbg(&dev->udev->dev, + "%s : timeout\n", __func__); retval = bytes_read ? bytes_read : -ETIMEDOUT; goto exit; } if (signal_pending(current)) { - dbg(2, " %s : signal pending", __func__); + dev_dbg(&dev->udev->dev, + "%s : signal pending\n", + __func__); retval = bytes_read ? bytes_read : -EINTR; goto exit; } @@ -552,7 +505,6 @@ exit: /* unlock the device */ mutex_unlock(&dev->mtx); - dbg(2, " %s : leave, return value %d", __func__, retval); return retval; } @@ -567,8 +519,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, unsigned long flags; int retval; - dbg(2, " %s : enter, count = %Zd", __func__, count); - dev = file->private_data; retval = mutex_lock_interruptible(&dev->mtx); @@ -578,14 +528,14 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - printk(KERN_ERR "adutux: No device or device unplugged %d\n", - retval); + pr_err("No device or device unplugged %d\n", retval); goto exit; } /* verify that we actually have some data to write */ if (count == 0) { - dbg(1, " %s : write request of 0 bytes", __func__); + dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n", + __func__); goto exit; } @@ -598,13 +548,15 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, mutex_unlock(&dev->mtx); if (signal_pending(current)) { - dbg(1, " %s : interrupted", __func__); + dev_dbg(&dev->udev->dev, "%s : interrupted\n", + __func__); set_current_state(TASK_RUNNING); retval = -EINTR; goto exit_onqueue; } if (schedule_timeout(COMMAND_TIMEOUT) == 0) { - dbg(1, "%s - command timed out.", __func__); + dev_dbg(&dev->udev->dev, + "%s - command timed out.\n", __func__); retval = -ETIMEDOUT; goto exit_onqueue; } @@ -615,18 +567,22 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, goto exit_nolock; } - dbg(4, " %s : in progress, count = %Zd", __func__, count); + dev_dbg(&dev->udev->dev, + "%s : in progress, count = %Zd\n", + __func__, count); } else { spin_unlock_irqrestore(&dev->buflock, flags); set_current_state(TASK_RUNNING); remove_wait_queue(&dev->write_wait, &waita); - dbg(4, " %s : sending, count = %Zd", __func__, count); + dev_dbg(&dev->udev->dev, "%s : sending, count = %Zd\n", + __func__, count); /* write the data into interrupt_out_buffer from userspace */ buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint); bytes_to_write = count > buffer_size ? buffer_size : count; - dbg(4, " %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd", - __func__, buffer_size, count, bytes_to_write); + dev_dbg(&dev->udev->dev, + "%s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd\n", + __func__, buffer_size, count, bytes_to_write); if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) { retval = -EFAULT; @@ -665,7 +621,6 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, exit: mutex_unlock(&dev->mtx); exit_nolock: - dbg(2, " %s : leave, return value %d", __func__, retval); return retval; exit_onqueue: @@ -711,8 +666,6 @@ static int adu_probe(struct usb_interface *interface, int out_end_size; int i; - dbg(2, " %s : enter", __func__); - if (udev == NULL) { dev_err(&interface->dev, "udev is NULL.\n"); goto exit; @@ -812,7 +765,7 @@ static int adu_probe(struct usb_interface *interface, dev_err(&interface->dev, "Could not retrieve serial number\n"); goto error; } - dbg(2, " %s : serial_number=%s", __func__, dev->serial_number); + dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number); /* we can register the device now, as it is ready */ usb_set_intfdata(interface, dev); @@ -833,8 +786,6 @@ static int adu_probe(struct usb_interface *interface, udev->descriptor.idProduct, dev->serial_number, (dev->minor - ADU_MINOR_BASE)); exit: - dbg(2, " %s : leave, return value %p (dev)", __func__, dev); - return retval; error: @@ -852,8 +803,6 @@ static void adu_disconnect(struct usb_interface *interface) struct adu_device *dev; int minor; - dbg(2, " %s : enter", __func__); - dev = usb_get_intfdata(interface); mutex_lock(&dev->mtx); /* not interruptible */ @@ -866,7 +815,8 @@ static void adu_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); /* if the device is not opened, then we clean up right now */ - dbg(2, " %s : open count %d", __func__, dev->open_count); + dev_dbg(&dev->udev->dev, "%s : open count %d\n", + __func__, dev->open_count); if (!dev->open_count) adu_delete(dev); @@ -874,8 +824,6 @@ static void adu_disconnect(struct usb_interface *interface) dev_info(&interface->dev, "ADU device adutux%d now disconnected\n", (minor - ADU_MINOR_BASE)); - - dbg(2, " %s : leave", __func__); } /* usb specific object needed to register this driver with the usb subsystem */ diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c new file mode 100644 index 00000000000..c31b4a33e6b --- /dev/null +++ b/drivers/usb/misc/ehset.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/ch11.h> + +#define TEST_SE0_NAK_PID 0x0101 +#define TEST_J_PID 0x0102 +#define TEST_K_PID 0x0103 +#define TEST_PACKET_PID 0x0104 +#define TEST_HS_HOST_PORT_SUSPEND_RESUME 0x0106 +#define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107 +#define TEST_SINGLE_STEP_SET_FEATURE 0x0108 + +static int ehset_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = -EINVAL; + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_device *hub_udev = dev->parent; + struct usb_device_descriptor *buf; + u8 portnum = dev->portnum; + u16 test_pid = le16_to_cpu(dev->descriptor.idProduct); + + switch (test_pid) { + case TEST_SE0_NAK_PID: + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, + (TEST_SE0_NAK << 8) | portnum, + NULL, 0, 1000); + break; + case TEST_J_PID: + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, + (TEST_J << 8) | portnum, + NULL, 0, 1000); + break; + case TEST_K_PID: + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, + (TEST_K << 8) | portnum, + NULL, 0, 1000); + break; + case TEST_PACKET_PID: + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, + (TEST_PACKET << 8) | portnum, + NULL, 0, 1000); + break; + case TEST_HS_HOST_PORT_SUSPEND_RESUME: + /* Test: wait for 15secs -> suspend -> 15secs delay -> resume */ + msleep(15 * 1000); + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_SUSPEND, portnum, + NULL, 0, 1000); + if (ret < 0) + break; + + msleep(15 * 1000); + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_SUSPEND, portnum, + NULL, 0, 1000); + break; + case TEST_SINGLE_STEP_GET_DEV_DESC: + /* Test: wait for 15secs -> GetDescriptor request */ + msleep(15 * 1000); + buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + USB_DT_DEVICE << 8, 0, + buf, USB_DT_DEVICE_SIZE, + USB_CTRL_GET_TIMEOUT); + kfree(buf); + break; + case TEST_SINGLE_STEP_SET_FEATURE: + /* + * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS + * + * Note, this test is only supported on root hubs since the + * SetPortFeature handling can only be done inside the HCD's + * hub_control callback function. + */ + if (hub_udev != dev->bus->root_hub) { + dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n"); + break; + } + + ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, + (6 << 8) | portnum, + NULL, 0, 60 * 1000); + + break; + default: + dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n", + __func__, test_pid); + } + + return (ret < 0) ? ret : 0; +} + +static void ehset_disconnect(struct usb_interface *intf) +{ +} + +static const struct usb_device_id ehset_id_table[] = { + { USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) }, + { USB_DEVICE(0x1a0a, TEST_J_PID) }, + { USB_DEVICE(0x1a0a, TEST_K_PID) }, + { USB_DEVICE(0x1a0a, TEST_PACKET_PID) }, + { USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) }, + { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) }, + { USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ehset_id_table); + +static struct usb_driver ehset_driver = { + .name = "usb_ehset_test", + .probe = ehset_probe, + .disconnect = ehset_disconnect, + .id_table = ehset_id_table, +}; + +module_usb_driver(ehset_driver); + +MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index ac762299eaa..b1d59532ac2 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -129,19 +129,6 @@ MODULE_DESCRIPTION("LD USB Driver"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("LD USB Devices"); -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug = 0; -#endif - -/* Use our own dbg macro */ -#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) - -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - /* All interrupt in transfers are collected in a ring buffer to * avoid racing conditions and get better performance of the driver. */ @@ -256,8 +243,9 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) status == -ESHUTDOWN) { goto exit; } else { - dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", - __func__, status); + dev_dbg(&dev->intf->dev, + "%s: nonzero status received: %d\n", __func__, + status); spin_lock(&dev->rbsl); goto resubmit; /* maybe we can recover */ } @@ -272,8 +260,8 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) *actual_buffer = urb->actual_length; memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length); dev->ring_head = next_ring_head; - dbg_info(&dev->intf->dev, "%s: received %d bytes\n", - __func__, urb->actual_length); + dev_dbg(&dev->intf->dev, "%s: received %d bytes\n", + __func__, urb->actual_length); } else { dev_warn(&dev->intf->dev, "Ring buffer overflow, %d bytes dropped\n", @@ -310,9 +298,9 @@ static void ld_usb_interrupt_out_callback(struct urb *urb) if (status && !(status == -ENOENT || status == -ECONNRESET || status == -ESHUTDOWN)) - dbg_info(&dev->intf->dev, - "%s - nonzero write interrupt status received: %d\n", - __func__, status); + dev_dbg(&dev->intf->dev, + "%s - nonzero write interrupt status received: %d\n", + __func__, status); dev->interrupt_out_busy = 0; wake_up_interruptible(&dev->write_wait); @@ -585,7 +573,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); if (bytes_to_write < count) dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write); - dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write); + dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", + __func__, count, bytes_to_write); if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { retval = -EFAULT; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 80894791c02..eb37c954205 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -75,6 +75,8 @@ * - move reset into open to clean out spurious data */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> @@ -87,28 +89,11 @@ #include <linux/poll.h> -#ifdef CONFIG_USB_DEBUG - static int debug = 4; -#else - static int debug = 0; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(lvl, format, arg...) \ -do { \ - if (debug >= lvl) \ - printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ -} while (0) - /* Version Information */ #define DRIVER_VERSION "v0.96" #define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>" #define DRIVER_DESC "LEGO USB Tower Driver" -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); /* The defaults are chosen to work with the latest versions of leJOS and NQC. */ @@ -298,18 +283,12 @@ static struct usb_driver tower_driver = { /** * lego_usb_tower_debug_data */ -static inline void lego_usb_tower_debug_data (int level, const char *function, int size, const unsigned char *data) +static inline void lego_usb_tower_debug_data(struct device *dev, + const char *function, int size, + const unsigned char *data) { - int i; - - if (debug < level) - return; - - printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); + dev_dbg(dev, "%s - length = %d, data = %*ph\n", + function, size, size, data); } @@ -318,8 +297,6 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i */ static inline void tower_delete (struct lego_usb_tower *dev) { - dbg(2, "%s: enter", __func__); - tower_abort_transfers (dev); /* free data structures */ @@ -329,8 +306,6 @@ static inline void tower_delete (struct lego_usb_tower *dev) kfree (dev->interrupt_in_buffer); kfree (dev->interrupt_out_buffer); kfree (dev); - - dbg(2, "%s: leave", __func__); } @@ -346,16 +321,13 @@ static int tower_open (struct inode *inode, struct file *file) struct tower_reset_reply reset_reply; int result; - dbg(2, "%s: enter", __func__); - nonseekable_open(inode, file); subminor = iminor(inode); interface = usb_find_interface (&tower_driver, subminor); if (!interface) { - printk(KERN_ERR "%s - error, can't find device for minor %d\n", - __func__, subminor); + pr_err("error, can't find device for minor %d\n", subminor); retval = -ENODEV; goto exit; } @@ -435,8 +407,6 @@ unlock_exit: mutex_unlock(&dev->lock); exit: - dbg(2, "%s: leave, return value %d ", __func__, retval); - return retval; } @@ -448,12 +418,9 @@ static int tower_release (struct inode *inode, struct file *file) struct lego_usb_tower *dev; int retval = 0; - dbg(2, "%s: enter", __func__); - dev = file->private_data; if (dev == NULL) { - dbg(1, "%s: object is NULL", __func__); retval = -ENODEV; goto exit_nolock; } @@ -465,7 +432,8 @@ static int tower_release (struct inode *inode, struct file *file) } if (dev->open_count != 1) { - dbg(1, "%s: device not opened exactly once", __func__); + dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n", + __func__); retval = -ENODEV; goto unlock_exit; } @@ -491,7 +459,6 @@ unlock_exit: exit: mutex_unlock(&open_disc_mutex); exit_nolock: - dbg(2, "%s: leave, return value %d", __func__, retval); return retval; } @@ -502,12 +469,8 @@ exit_nolock: */ static void tower_abort_transfers (struct lego_usb_tower *dev) { - dbg(2, "%s: enter", __func__); - - if (dev == NULL) { - dbg(1, "%s: dev is null", __func__); - goto exit; - } + if (dev == NULL) + return; /* shutdown transfer */ if (dev->interrupt_in_running) { @@ -518,9 +481,6 @@ static void tower_abort_transfers (struct lego_usb_tower *dev) } if (dev->interrupt_out_busy && dev->udev) usb_kill_urb(dev->interrupt_out_urb); - -exit: - dbg(2, "%s: leave", __func__); } @@ -553,8 +513,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait) struct lego_usb_tower *dev; unsigned int mask = 0; - dbg(2, "%s: enter", __func__); - dev = file->private_data; if (!dev->udev) @@ -571,8 +529,6 @@ static unsigned int tower_poll (struct file *file, poll_table *wait) mask |= POLLOUT | POLLWRNORM; } - dbg(2, "%s: leave, mask = %d", __func__, mask); - return mask; } @@ -597,8 +553,6 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, int retval = 0; unsigned long timeout = 0; - dbg(2, "%s: enter, count = %Zd", __func__, count); - dev = file->private_data; /* lock this object */ @@ -610,13 +564,13 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); + pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; } /* verify that we actually have some data to read */ if (count == 0) { - dbg(1, "%s: read request of 0 bytes", __func__); + dev_dbg(&dev->udev->dev, "read request of 0 bytes\n"); goto unlock_exit; } @@ -672,7 +626,6 @@ unlock_exit: mutex_unlock(&dev->lock); exit: - dbg(2, "%s: leave, return value %d", __func__, retval); return retval; } @@ -686,8 +639,6 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t size_t bytes_to_write; int retval = 0; - dbg(2, "%s: enter, count = %Zd", __func__, count); - dev = file->private_data; /* lock this object */ @@ -699,13 +650,13 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); + pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; } /* verify that we actually have some data to write */ if (count == 0) { - dbg(1, "%s: write request of 0 bytes", __func__); + dev_dbg(&dev->udev->dev, "write request of 0 bytes\n"); goto unlock_exit; } @@ -723,7 +674,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t /* write the data into interrupt_out_buffer from userspace */ bytes_to_write = min_t(int, count, write_buffer_size); - dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write); + dev_dbg(&dev->udev->dev, "%s: count = %Zd, bytes_to_write = %Zd\n", + __func__, count, bytes_to_write); if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) { retval = -EFAULT; @@ -757,8 +709,6 @@ unlock_exit: mutex_unlock(&dev->lock); exit: - dbg(2, "%s: leave, return value %d", __func__, retval); - return retval; } @@ -772,9 +722,8 @@ static void tower_interrupt_in_callback (struct urb *urb) int status = urb->status; int retval; - dbg(4, "%s: enter, status %d", __func__, status); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); + lego_usb_tower_debug_data(&dev->udev->dev, __func__, + urb->actual_length, urb->transfer_buffer); if (status) { if (status == -ENOENT || @@ -782,7 +731,9 @@ static void tower_interrupt_in_callback (struct urb *urb) status == -ESHUTDOWN) { goto exit; } else { - dbg(1, "%s: nonzero status received: %d", __func__, status); + dev_dbg(&dev->udev->dev, + "%s: nonzero status received: %d\n", __func__, + status); goto resubmit; /* maybe we can recover */ } } @@ -795,9 +746,11 @@ static void tower_interrupt_in_callback (struct urb *urb) urb->actual_length); dev->read_buffer_length += urb->actual_length; dev->read_last_arrival = jiffies; - dbg(3, "%s: received %d bytes", __func__, urb->actual_length); + dev_dbg(&dev->udev->dev, "%s: received %d bytes\n", + __func__, urb->actual_length); } else { - printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length); + pr_warn("read_buffer overflow, %d bytes dropped\n", + urb->actual_length); } spin_unlock (&dev->read_buffer_lock); } @@ -815,9 +768,6 @@ resubmit: exit: dev->interrupt_in_done = 1; wake_up_interruptible (&dev->read_wait); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __func__, status); } @@ -829,22 +779,20 @@ static void tower_interrupt_out_callback (struct urb *urb) struct lego_usb_tower *dev = urb->context; int status = urb->status; - dbg(4, "%s: enter, status %d", __func__, status); - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); + lego_usb_tower_debug_data(&dev->udev->dev, __func__, + urb->actual_length, urb->transfer_buffer); /* sync/async unlink faults aren't errors */ if (status && !(status == -ENOENT || status == -ECONNRESET || status == -ESHUTDOWN)) { - dbg(1, "%s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&dev->udev->dev, + "%s: nonzero write bulk status received: %d\n", __func__, + status); } dev->interrupt_out_busy = 0; wake_up_interruptible(&dev->write_wait); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __func__, status); } @@ -866,8 +814,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device int retval = -ENOMEM; int result; - dbg(2, "%s: enter", __func__); - /* allocate memory for our device state and initialize it */ dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); @@ -993,8 +939,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device exit: - dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev); - return retval; error: @@ -1013,8 +957,6 @@ static void tower_disconnect (struct usb_interface *interface) struct lego_usb_tower *dev; int minor; - dbg(2, "%s: enter", __func__); - dev = usb_get_intfdata (interface); mutex_lock(&open_disc_mutex); usb_set_intfdata (interface, NULL); @@ -1041,8 +983,6 @@ static void tower_disconnect (struct usb_interface *interface) dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n", (minor - LEGO_USB_TOWER_MINOR_BASE)); - - dbg(2, "%s: leave", __func__); } module_usb_driver(tower_driver); diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index c3578393dde..a31641e18d1 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -26,6 +26,7 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/platform_data/usb3503.h> +#include <linux/regmap.h> #define USB3503_VIDL 0x00 #define USB3503_VIDM 0x01 @@ -50,60 +51,25 @@ #define USB3503_CFGP 0xee #define USB3503_CLKSUSP (1 << 7) +#define USB3503_RESET 0xff + struct usb3503 { enum usb3503_mode mode; - struct i2c_client *client; + struct regmap *regmap; + struct device *dev; u8 port_off_mask; int gpio_intn; int gpio_reset; int gpio_connect; }; -static int usb3503_write_register(struct i2c_client *client, - char reg, char data) -{ - return i2c_smbus_write_byte_data(client, reg, data); -} - -static int usb3503_read_register(struct i2c_client *client, char reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int usb3503_set_bits(struct i2c_client *client, char reg, char req) +static int usb3503_reset(struct usb3503 *hub, int state) { - int err; - - err = usb3503_read_register(client, reg); - if (err < 0) - return err; - - err = usb3503_write_register(client, reg, err | req); - if (err < 0) - return err; - - return 0; -} - -static int usb3503_clear_bits(struct i2c_client *client, char reg, char req) -{ - int err; - - err = usb3503_read_register(client, reg); - if (err < 0) - return err; - - err = usb3503_write_register(client, reg, err & ~req); - if (err < 0) - return err; - - return 0; -} + if (!state && gpio_is_valid(hub->gpio_connect)) + gpio_set_value_cansleep(hub->gpio_connect, 0); -static int usb3503_reset(int gpio_reset, int state) -{ - if (gpio_is_valid(gpio_reset)) - gpio_set_value(gpio_reset, state); + if (gpio_is_valid(hub->gpio_reset)) + gpio_set_value_cansleep(hub->gpio_reset, state); /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ if (state) @@ -112,90 +78,105 @@ static int usb3503_reset(int gpio_reset, int state) return 0; } -static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) +static int usb3503_connect(struct usb3503 *hub) { - struct i2c_client *i2c = hub->client; - int err = 0; + struct device *dev = hub->dev; + int err; - switch (mode) { - case USB3503_MODE_HUB: - usb3503_reset(hub->gpio_reset, 1); + usb3503_reset(hub, 1); + if (hub->regmap) { /* SP_ILOCK: set connect_n, config_n for config */ - err = usb3503_write_register(i2c, USB3503_SP_ILOCK, - (USB3503_SPILOCK_CONNECT + err = regmap_write(hub->regmap, USB3503_SP_ILOCK, + (USB3503_SPILOCK_CONNECT | USB3503_SPILOCK_CONFIG)); if (err < 0) { - dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err); - goto err_hubmode; + dev_err(dev, "SP_ILOCK failed (%d)\n", err); + return err; } /* PDS : Disable For Self Powered Operation */ if (hub->port_off_mask) { - err = usb3503_set_bits(i2c, USB3503_PDS, + err = regmap_update_bits(hub->regmap, USB3503_PDS, + hub->port_off_mask, hub->port_off_mask); if (err < 0) { - dev_err(&i2c->dev, "PDS failed (%d)\n", err); - goto err_hubmode; + dev_err(dev, "PDS failed (%d)\n", err); + return err; } } /* CFG1 : SELF_BUS_PWR -> Self-Powerd operation */ - err = usb3503_set_bits(i2c, USB3503_CFG1, USB3503_SELF_BUS_PWR); + err = regmap_update_bits(hub->regmap, USB3503_CFG1, + USB3503_SELF_BUS_PWR, + USB3503_SELF_BUS_PWR); if (err < 0) { - dev_err(&i2c->dev, "CFG1 failed (%d)\n", err); - goto err_hubmode; + dev_err(dev, "CFG1 failed (%d)\n", err); + return err; } /* SP_LOCK: clear connect_n, config_n for hub connect */ - err = usb3503_clear_bits(i2c, USB3503_SP_ILOCK, - (USB3503_SPILOCK_CONNECT - | USB3503_SPILOCK_CONFIG)); + err = regmap_update_bits(hub->regmap, USB3503_SP_ILOCK, + (USB3503_SPILOCK_CONNECT + | USB3503_SPILOCK_CONFIG), 0); if (err < 0) { - dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err); - goto err_hubmode; + dev_err(dev, "SP_ILOCK failed (%d)\n", err); + return err; } + } - hub->mode = mode; - dev_info(&i2c->dev, "switched to HUB mode\n"); + if (gpio_is_valid(hub->gpio_connect)) + gpio_set_value_cansleep(hub->gpio_connect, 1); + + hub->mode = USB3503_MODE_HUB; + dev_info(dev, "switched to HUB mode\n"); + + return 0; +} + +static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) +{ + struct device *dev = hub->dev; + int err = 0; + + switch (mode) { + case USB3503_MODE_HUB: + err = usb3503_connect(hub); break; case USB3503_MODE_STANDBY: - usb3503_reset(hub->gpio_reset, 0); + usb3503_reset(hub, 0); hub->mode = mode; - dev_info(&i2c->dev, "switched to STANDBY mode\n"); + dev_info(dev, "switched to STANDBY mode\n"); break; default: - dev_err(&i2c->dev, "unknown mode is request\n"); + dev_err(dev, "unknown mode is requested\n"); err = -EINVAL; break; } -err_hubmode: return err; } -static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +static const struct regmap_config usb3503_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = USB3503_RESET, +}; + +static int usb3503_probe(struct usb3503 *hub) { - struct usb3503_platform_data *pdata = i2c->dev.platform_data; - struct device_node *np = i2c->dev.of_node; - struct usb3503 *hub; - int err = -ENOMEM; - u32 mode = USB3503_MODE_UNKNOWN; + struct device *dev = hub->dev; + struct usb3503_platform_data *pdata = dev_get_platdata(dev); + struct device_node *np = dev->of_node; + int err; + u32 mode = USB3503_MODE_HUB; const u32 *property; int len; - hub = kzalloc(sizeof(struct usb3503), GFP_KERNEL); - if (!hub) { - dev_err(&i2c->dev, "private data alloc fail\n"); - return err; - } - - i2c_set_clientdata(i2c, hub); - hub->client = i2c; - if (pdata) { hub->port_off_mask = pdata->port_off_mask; hub->gpio_intn = pdata->gpio_intn; @@ -215,10 +196,10 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id) } } - hub->gpio_intn = of_get_named_gpio(np, "connect-gpios", 0); + hub->gpio_intn = of_get_named_gpio(np, "intn-gpios", 0); if (hub->gpio_intn == -EPROBE_DEFER) return -EPROBE_DEFER; - hub->gpio_connect = of_get_named_gpio(np, "intn-gpios", 0); + hub->gpio_connect = of_get_named_gpio(np, "connect-gpios", 0); if (hub->gpio_connect == -EPROBE_DEFER) return -EPROBE_DEFER; hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0); @@ -228,72 +209,86 @@ static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id) hub->mode = mode; } + if (hub->port_off_mask && !hub->regmap) + dev_err(dev, "Ports disabled with no control interface\n"); + if (gpio_is_valid(hub->gpio_intn)) { - err = gpio_request_one(hub->gpio_intn, + err = devm_gpio_request_one(dev, hub->gpio_intn, GPIOF_OUT_INIT_HIGH, "usb3503 intn"); if (err) { - dev_err(&i2c->dev, - "unable to request GPIO %d as connect pin (%d)\n", - hub->gpio_intn, err); - goto err_out; + dev_err(dev, + "unable to request GPIO %d as connect pin (%d)\n", + hub->gpio_intn, err); + return err; } } if (gpio_is_valid(hub->gpio_connect)) { - err = gpio_request_one(hub->gpio_connect, - GPIOF_OUT_INIT_HIGH, "usb3503 connect"); + err = devm_gpio_request_one(dev, hub->gpio_connect, + GPIOF_OUT_INIT_LOW, "usb3503 connect"); if (err) { - dev_err(&i2c->dev, - "unable to request GPIO %d as connect pin (%d)\n", - hub->gpio_connect, err); - goto err_gpio_connect; + dev_err(dev, + "unable to request GPIO %d as connect pin (%d)\n", + hub->gpio_connect, err); + return err; } } if (gpio_is_valid(hub->gpio_reset)) { - err = gpio_request_one(hub->gpio_reset, + err = devm_gpio_request_one(dev, hub->gpio_reset, GPIOF_OUT_INIT_LOW, "usb3503 reset"); if (err) { - dev_err(&i2c->dev, - "unable to request GPIO %d as reset pin (%d)\n", - hub->gpio_reset, err); - goto err_gpio_reset; + dev_err(dev, + "unable to request GPIO %d as reset pin (%d)\n", + hub->gpio_reset, err); + return err; } } usb3503_switch_mode(hub, hub->mode); - dev_info(&i2c->dev, "%s: probed on %s mode\n", __func__, + dev_info(dev, "%s: probed in %s mode\n", __func__, (hub->mode == USB3503_MODE_HUB) ? "hub" : "standby"); return 0; +} -err_gpio_reset: - if (gpio_is_valid(hub->gpio_connect)) - gpio_free(hub->gpio_connect); -err_gpio_connect: - if (gpio_is_valid(hub->gpio_intn)) - gpio_free(hub->gpio_intn); -err_out: - kfree(hub); +static int usb3503_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct usb3503 *hub; + int err; - return err; + hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL); + if (!hub) { + dev_err(&i2c->dev, "private data alloc fail\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c, hub); + hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config); + if (IS_ERR(hub->regmap)) { + err = PTR_ERR(hub->regmap); + dev_err(&i2c->dev, "Failed to initialise regmap: %d\n", err); + return err; + } + hub->dev = &i2c->dev; + + return usb3503_probe(hub); } -static int usb3503_remove(struct i2c_client *i2c) +static int usb3503_platform_probe(struct platform_device *pdev) { - struct usb3503 *hub = i2c_get_clientdata(i2c); - - if (gpio_is_valid(hub->gpio_intn)) - gpio_free(hub->gpio_intn); - if (gpio_is_valid(hub->gpio_connect)) - gpio_free(hub->gpio_connect); - if (gpio_is_valid(hub->gpio_reset)) - gpio_free(hub->gpio_reset); + struct usb3503 *hub; - kfree(hub); + hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL); + if (!hub) { + dev_err(&pdev->dev, "private data alloc fail\n"); + return -ENOMEM; + } + hub->dev = &pdev->dev; - return 0; + return usb3503_probe(hub); } static const struct i2c_device_id usb3503_id[] = { @@ -305,22 +300,53 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id); #ifdef CONFIG_OF static const struct of_device_id usb3503_of_match[] = { { .compatible = "smsc,usb3503", }, + { .compatible = "smsc,usb3503a", }, {}, }; MODULE_DEVICE_TABLE(of, usb3503_of_match); #endif -static struct i2c_driver usb3503_driver = { +static struct i2c_driver usb3503_i2c_driver = { .driver = { .name = USB3503_I2C_NAME, .of_match_table = of_match_ptr(usb3503_of_match), }, - .probe = usb3503_probe, - .remove = usb3503_remove, + .probe = usb3503_i2c_probe, .id_table = usb3503_id, }; -module_i2c_driver(usb3503_driver); +static struct platform_driver usb3503_platform_driver = { + .driver = { + .name = USB3503_I2C_NAME, + .of_match_table = of_match_ptr(usb3503_of_match), + .owner = THIS_MODULE, + }, + .probe = usb3503_platform_probe, +}; + +static int __init usb3503_init(void) +{ + int err; + + err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver); + if (err != 0) + pr_err("usb3503: Failed to register I2C driver: %d\n", err); + + err = platform_driver_register(&usb3503_platform_driver); + if (err != 0) + pr_err("usb3503: Failed to register platform driver: %d\n", + err); + + return 0; +} +module_init(usb3503_init); + +static void __exit usb3503_exit(void) +{ + platform_driver_unregister(&usb3503_platform_driver); + i2c_del_driver(&usb3503_i2c_driver); +} +module_exit(usb3503_exit); MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>"); MODULE_DESCRIPTION("USB3503 USB HUB driver"); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 8b4ca1cb450..aa28ac8c760 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -747,9 +747,9 @@ static int ch9_postconfig(struct usbtest_dev *dev) /* [9.4.5] get_status always works */ retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf); - if (retval != 2) { + if (retval) { dev_err(&iface->dev, "get dev status --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; + return retval; } /* FIXME configuration.bmAttributes says if we could try to set/clear @@ -758,9 +758,9 @@ static int ch9_postconfig(struct usbtest_dev *dev) retval = usb_get_status(udev, USB_RECIP_INTERFACE, iface->altsetting[0].desc.bInterfaceNumber, dev->buf); - if (retval != 2) { + if (retval) { dev_err(&iface->dev, "get interface status --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; + return retval; } /* FIXME get status for each endpoint in the interface */ @@ -1351,7 +1351,6 @@ static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) ep, retval); return retval; } - le16_to_cpus(&status); if (status != 1) { ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status); return -EINVAL; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b9d741614f8..18e877ffe7b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -99,7 +99,6 @@ #include <linux/prefetch.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/idr.h> #include <linux/dma-mapping.h> #include "musb_core.h" diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index ebb46eca179..59d2245db1c 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -481,7 +481,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int omap2430_probe(struct platform_device *pdev) { - struct resource musb_resources[2]; + struct resource musb_resources[3]; struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct omap_musb_board_data *data; struct platform_device *musb; @@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + ret = platform_device_add_resources(musb, musb_resources, ARRAY_SIZE(musb_resources)); if (ret) { diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 0d68fc1d9f3..b3b3ed72388 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1156,7 +1156,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32); static int tusb_probe(struct platform_device *pdev) { - struct resource musb_resources[2]; + struct resource musb_resources[3]; struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct tusb6010_glue *glue; @@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + ret = platform_device_add_resources(musb, musb_resources, ARRAY_SIZE(musb_resources)); if (ret) { diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index f41c3e12c6a..d5589f9c60a 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -58,6 +58,7 @@ config NOP_USB_XCEIV config OMAP_CONTROL_USB tristate "OMAP CONTROL USB Driver" + depends on ARCH_OMAP2PLUS || COMPILE_TEST help Enable this to add support for the USB part present in the control module. This driver has API to power on the USB2 PHY and to write to @@ -78,6 +79,7 @@ config OMAP_USB2 config OMAP_USB3 tristate "OMAP USB3 PHY Driver" + depends on ARCH_OMAP2PLUS || COMPILE_TEST select OMAP_CONTROL_USB select USB_PHY help diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index dae321de3b2..2135e85f46e 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -1,9 +1,6 @@ # # Makefile for physical layer USB drivers # - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - obj-$(CONFIG_USB_PHY) += phy.o obj-$(CONFIG_OF) += of.o diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index e965cf65d69..fa7c9f9628b 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -611,7 +611,7 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg, otg_dev->fsm.b_bus_req = 1; /* start the gadget right away if the ID pin says Mini-B */ - DBG("ID pin=%d\n", otg_dev->fsm.id); + pr_debug("ID pin=%d\n", otg_dev->fsm.id); if (otg_dev->fsm.id == 1) { fsl_otg_start_host(&otg_dev->fsm, 0); otg_drv_vbus(&otg_dev->fsm, 0); @@ -684,7 +684,7 @@ static int fsl_otg_start_hnp(struct usb_otg *otg) if (otg_dev != fsl_otg_dev) return -ENODEV; - DBG("start_hnp...n"); + pr_debug("start_hnp...\n"); /* clear a_bus_req to enter a_suspend state */ otg_dev->fsm.a_bus_req = 0; @@ -941,7 +941,7 @@ int usb_otg_start(struct platform_device *pdev) p_otg->fsm.id = 0; } - DBG("initial ID pin=%d\n", p_otg->fsm.id); + pr_debug("initial ID pin=%d\n", p_otg->fsm.id); /* enable OTG ID pin interrupt */ temp = fsl_readl(&p_otg->dr_mem_map->otgsc); diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index c30a2e1d9e4..fbe586206f3 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -15,18 +15,11 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef DEBUG #undef VERBOSE -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt , \ - __func__, ## args) -#else -#define DBG(fmt, args...) do {} while (0) -#endif - #ifdef VERBOSE -#define VDBG DBG +#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \ + __func__, ## args) #else #define VDBG(stuff...) do {} while (0) #endif diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index ae481afcb3e..d3a5160e4cc 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -40,9 +40,7 @@ #include <mach/usb.h> -#ifndef DEBUG -#undef VERBOSE -#endif +#undef VERBOSE #define DRIVER_VERSION "24 August 2004" @@ -387,7 +385,6 @@ static void b_idle(struct isp1301 *isp, const char *tag) static void dump_regs(struct isp1301 *isp, const char *label) { -#ifdef DEBUG u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); @@ -396,7 +393,6 @@ dump_regs(struct isp1301 *isp, const char *label) omap_readl(OTG_CTRL), label, state_name(isp), ctrl, status, src); /* mode control and irq enables don't change much */ -#endif } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 8c3a42ea910..c454bfa22a1 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -51,6 +51,24 @@ config USB_SERIAL_GENERIC support" be compiled as a module for this driver to be used properly. +config USB_SERIAL_SIMPLE + tristate "USB Serial Simple Driver" + help + Say Y here to use the USB serial "simple" driver. This driver + handles a wide range of very simple devices, all in one + driver. Specifically, it supports: + - Suunto ANT+ USB device. + - Fundamental Software dongle. + - HP4x calculators + - a number of Motoroloa phones + - Siemens USB/MPI adapter. + - ViVOtech ViVOpay USB device. + - Infineon Modem Flashloader USB interface + - ZIO Motherboard USB serial interface + + To compile this driver as a module, choose M here: the module + will be called usb-serial-simple. + config USB_SERIAL_AIRCABLE tristate "USB AIRcable Bluetooth Dongle Driver" help @@ -158,14 +176,6 @@ config USB_SERIAL_FTDI_SIO To compile this driver as a module, choose M here: the module will be called ftdi_sio. -config USB_SERIAL_FUNSOFT - tristate "USB Fundamental Software Dongle Driver" - ---help--- - Say Y here if you want to use the Fundamental Software dongle. - - To compile this driver as a module, choose M here: the - module will be called funsoft. - config USB_SERIAL_VISOR tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" help @@ -462,15 +472,6 @@ config USB_SERIAL_MOS7840 To compile this driver as a module, choose M here: the module will be called mos7840. If unsure, choose N. -config USB_SERIAL_MOTOROLA - tristate "USB Motorola Phone modem driver" - ---help--- - Say Y here if you want to use a Motorola phone with a USB - connector as a modem link. - - To compile this driver as a module, choose M here: the - module will be called moto_modem. If unsure, choose N. - config USB_SERIAL_NAVMAN tristate "USB Navman GPS device" help @@ -525,14 +526,6 @@ config USB_SERIAL_SPCP8X5 To compile this driver as a module, choose M here: the module will be called spcp8x5. -config USB_SERIAL_HP4X - tristate "USB HP4x Calculators support" - help - Say Y here if you want to use an Hewlett-Packard 4x Calculator. - - To compile this driver as a module, choose M here: the - module will be called hp4x. - config USB_SERIAL_SAFE tristate "USB Safe Serial (Encapsulated) Driver" @@ -540,14 +533,6 @@ config USB_SERIAL_SAFE_PADDED bool "USB Secure Encapsulated Driver - Padded" depends on USB_SERIAL_SAFE -config USB_SERIAL_SIEMENS_MPI - tristate "USB Siemens MPI driver" - help - Say M here if you want to use a Siemens USB/MPI adapter. - - To compile this driver as a module, choose M here: the - module will be called siemens_mpi. - config USB_SERIAL_SIERRAWIRELESS tristate "USB Sierra Wireless Driver" help @@ -639,14 +624,6 @@ config USB_SERIAL_OPTICON To compile this driver as a module, choose M here: the module will be called opticon. -config USB_SERIAL_VIVOPAY_SERIAL - tristate "USB ViVOpay serial interface driver" - help - Say Y here if you want to use a ViVOtech ViVOpay USB device. - - To compile this driver as a module, choose M here: the - module will be called vivopay-serial. - config USB_SERIAL_XSENS_MT tristate "Xsens motion tracker serial interface driver" help @@ -659,14 +636,6 @@ config USB_SERIAL_XSENS_MT To compile this driver as a module, choose M here: the module will be called xsens_mt. -config USB_SERIAL_ZIO - tristate "ZIO Motherboard USB serial interface driver" - help - Say Y here if you want to use ZIO Motherboard. - - To compile this driver as a module, choose M here: the - module will be called zio. - config USB_SERIAL_WISHBONE tristate "USB-Wishbone adapter interface driver" help @@ -710,16 +679,6 @@ config USB_SERIAL_QT2 To compile this driver as a module, choose M here: the module will be called quatech-serial. -config USB_SERIAL_FLASHLOADER - tristate "Infineon Modem Flashloader USB interface driver" - help - Say Y here if you want to download Infineon Modem - via USB Flashloader serial driver. - - To compile this driver as a module, choose M here: the - module will be called flashloader. - - config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index f7130114488..42670f0b5bc 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -24,9 +24,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o -obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o -obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o @@ -39,7 +37,6 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o -obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o @@ -50,8 +47,8 @@ obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o -obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o +obj-$(CONFIG_USB_SERIAL_SIMPLE) += usb-serial-simple.o obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o @@ -61,8 +58,5 @@ obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o -obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o -obj-$(CONFIG_USB_SERIAL_FLASHLOADER) += flashloader.o diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index afb50eab204..c69bb50d466 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -151,11 +151,7 @@ static int usb_console_setup(struct console *co, char *options) /* only call the device specific open if this * is the first time the port is opened */ - if (serial->type->open) - retval = serial->type->open(NULL, port); - else - retval = usb_serial_generic_open(NULL, port); - + retval = serial->type->open(NULL, port); if (retval) { dev_err(&port->dev, "could not open USB console port\n"); goto fail; @@ -210,10 +206,10 @@ static void usb_console_write(struct console *co, if (count == 0) return; - pr_debug("%s - minor %d, %d byte(s)\n", __func__, port->minor, count); + dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count); if (!port->port.console) { - pr_debug("%s - port not opened\n", __func__); + dev_dbg(&port->dev, "%s - port not opened\n", __func__); return; } @@ -230,21 +226,14 @@ static void usb_console_write(struct console *co, } /* pass on to the driver specific version of this function if it is available */ - if (serial->type->write) - retval = serial->type->write(NULL, port, buf, i); - else - retval = usb_serial_generic_write(NULL, port, buf, i); - pr_debug("%s - return value : %d\n", __func__, retval); + retval = serial->type->write(NULL, port, buf, i); + dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval); if (lf) { /* append CR after LF */ unsigned char cr = 13; - if (serial->type->write) - retval = serial->type->write(NULL, - port, &cr, 1); - else - retval = usb_serial_generic_write(NULL, - port, &cr, 1); - pr_debug("%s - return value : %d\n", __func__, retval); + retval = serial->type->write(NULL, port, &cr, 1); + dev_dbg(&port->dev, "%s - write cr: %d\n", + __func__, retval); } buf += i; count -= i; diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 0eae4ba3760..6987b535aa9 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -670,9 +670,6 @@ static void cp210x_set_termios(struct tty_struct *tty, unsigned int bits; unsigned int modem_ctl[4]; - if (!tty) - return; - cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e948dc02795..558605d646f 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -495,6 +495,8 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) } usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } @@ -625,7 +627,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) __func__, result); cypress_set_dead(port); } - port->port.drain_delay = 256; + return result; } /* cypress_open */ diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 75e85cbf9e8..639a18fb67e 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -207,7 +207,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } - port->port.drain_delay = 256; return 0; } @@ -322,6 +321,8 @@ static int f81232_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } diff --git a/drivers/usb/serial/flashloader.c b/drivers/usb/serial/flashloader.c deleted file mode 100644 index e6f5c10e891..00000000000 --- a/drivers/usb/serial/flashloader.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Infineon Flashloader driver - * - * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> -#include <linux/uaccess.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x8087, 0x0716) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver flashloader_device = { - .driver = { - .owner = THIS_MODULE, - .name = "flashloader", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &flashloader_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 7260ec66034..dbf2f281882 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -51,8 +51,6 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" -static __u16 vendor = FTDI_VID; -static __u16 product; struct ftdi_private { enum ftdi_chip_type chip_type; @@ -144,8 +142,8 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { /* - * Device ID not listed? Test via module params product/vendor or - * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! + * Device ID not listed? Test it using + * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report. */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, @@ -735,9 +733,34 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, @@ -881,7 +904,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, /* Crucible Devices */ { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, - { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -905,9 +927,6 @@ static const char *ftdi_chip_name[] = { #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) /* End TIOCMIWAIT */ -#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \ - | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP) - /* function prototypes for a FTDI serial converter */ static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id); @@ -974,10 +993,6 @@ static struct usb_serial_driver * const serial_drivers[] = { #define WDR_TIMEOUT 5000 /* default urb timeout */ #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ -/* High and low are for DTR, RTS etc etc */ -#define HIGH 1 -#define LOW 0 - /* * *************************************************************************** * Utility functions @@ -1842,7 +1857,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios dummy; struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -1858,10 +1872,8 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) This is same behaviour as serial.c/rs_open() - Kuba */ /* ftdi_set_termios will send usb control messages */ - if (tty) { - memset(&dummy, 0, sizeof(dummy)); - ftdi_set_termios(tty, port, &dummy); - } + if (tty) + ftdi_set_termios(tty, port, NULL); return usb_serial_generic_open(tty, port); } @@ -2190,7 +2202,7 @@ no_data_parity_stop_changes: dev_err(ddev, "%s urb failed to set baudrate\n", __func__); mutex_unlock(&priv->cfg_lock); /* Ensure RTS and DTR are raised when baudrate changed from 0 */ - if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) + if (old_termios && (old_termios->c_cflag & CBAUD) == B0) set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } @@ -2380,38 +2392,11 @@ static int ftdi_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } -static int __init ftdi_init(void) -{ - if (vendor > 0 && product > 0) { - /* Add user specified VID/PID to reserved element of table. */ - int i; - for (i = 0; id_table_combined[i].idVendor; i++) - ; - id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - id_table_combined[i].idVendor = vendor; - id_table_combined[i].idProduct = product; - } - return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined); -} - -static void __exit ftdi_exit(void) -{ - usb_serial_deregister_drivers(serial_drivers); -} - - -module_init(ftdi_init); -module_exit(ftdi_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" - __MODULE_STRING(FTDI_VID)")"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override"); diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 6dd79253205..1b8af461b52 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -815,11 +815,35 @@ /* * RT Systems programming cables for various ham radios */ -#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ -#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ -#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ -#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ - +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */ +#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */ +#define RTSYSTEMS_USB_57A_PID 0x9e51 /* USB-57A USB to 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_57B_PID 0x9e52 /* USB-57B USB to extended 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_29A_PID 0x9e53 /* USB-29A USB to 3.5mm stereo plug */ +#define RTSYSTEMS_USB_29B_PID 0x9e54 /* USB-29B USB to 6 pin mini din */ +#define RTSYSTEMS_USB_29F_PID 0x9e55 /* USB-29F USB to 6 pin modular plug */ +#define RTSYSTEMS_USB_62B_PID 0x9e56 /* USB-62B USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_S01_PID 0x9e57 /* USB-RTS01 USB to 3.5 mm stereo plug*/ +#define RTSYSTEMS_USB_63_PID 0x9e58 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_29C_PID 0x9e59 /* USB-29C USB to 4 pin modular plug*/ +#define RTSYSTEMS_USB_81B_PID 0x9e5A /* USB-81 USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_82B_PID 0x9e5B /* USB-82 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_K5D_PID 0x9e5C /* USB-K5D USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_K4Y_PID 0x9e5D /* USB-K4Y USB to 2.5/3.5 mm plugs*/ +#define RTSYSTEMS_USB_K5G_PID 0x9e5E /* USB-K5G USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_S05_PID 0x9e5F /* USB-RTS05 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_60_PID 0x9e60 /* USB-60 USB to 6 pin din*/ +#define RTSYSTEMS_USB_61_PID 0x9e61 /* USB-61 USB to 6 pin mini din*/ +#define RTSYSTEMS_USB_62_PID 0x9e62 /* USB-62 USB to 8 pin mini din*/ +#define RTSYSTEMS_USB_63B_PID 0x9e63 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_64_PID 0x9e64 /* USB-64 USB to 9 pin male*/ +#define RTSYSTEMS_USB_65_PID 0x9e65 /* USB-65 USB to 9 pin female null modem*/ +#define RTSYSTEMS_USB_92_PID 0x9e66 /* USB-92 USB to 12 pin plug*/ +#define RTSYSTEMS_USB_92D_PID 0x9e67 /* USB-92D USB to 12 pin plug data*/ +#define RTSYSTEMS_USB_W5R_PID 0x9e68 /* USB-W5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_A5R_PID 0x9e69 /* USB-A5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_PW1_PID 0x9e6A /* USB-PW1 USB to 8 pin modular plug*/ /* * Physik Instrumente diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c deleted file mode 100644 index 9362f8fd238..00000000000 --- a/drivers/usb/serial/funsoft.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Funsoft Serial USB driver - * - * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> -#include <linux/uaccess.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1404, 0xcddc) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver funsoft_device = { - .driver = { - .owner = THIS_MODULE, - .name = "funsoft", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &funsoft_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); - -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ba45170c78e..1f31e6b4c25 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -460,12 +460,7 @@ static bool usb_serial_generic_msr_changed(struct tty_struct *tty, /* * Use tty-port initialised flag to detect all hangups including the * one generated at USB-device disconnect. - * - * FIXME: Remove hupping check once tty_port_hangup calls shutdown - * (which clears the initialised flag) before wake up. */ - if (test_bit(TTY_HUPPING, &tty->flags)) - return true; if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) return true; @@ -496,12 +491,8 @@ int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) ret = wait_event_interruptible(port->port.delta_msr_wait, usb_serial_generic_msr_changed(tty, arg, &cnow)); - if (!ret) { - if (test_bit(TTY_HUPPING, &tty->flags)) - ret = -EIO; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) - ret = -EIO; - } + if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + ret = -EIO; return ret; } diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c deleted file mode 100644 index 2cba60d90c7..00000000000 --- a/drivers/usb/serial/hp4x.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * HP4x Calculators Serial USB driver - * - * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -#define DRIVER_DESC "HP4x (48/49) Generic Serial driver" - -#define HP_VENDOR_ID 0x03f0 -#define HP49GP_PRODUCT_ID 0x0121 - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver hp49gp_device = { - .driver = { - .owner = THIS_MODULE, - .name = "hp4X", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &hp49gp_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index dc2803b5eb0..c91481d74a1 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -56,9 +56,7 @@ #define MAX_NAME_LEN 64 -#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ -#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ /* receive port state */ enum RXSTATE { diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 60054e72b75..9c18f5985c8 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -64,8 +64,6 @@ #define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ -#define EDGE_OUT_BUF_SIZE 1024 - /* Product information read from the Edgeport */ struct product_info { @@ -93,7 +91,6 @@ struct edgeport_port { spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; - struct kfifo write_fifo; }; struct edgeport_serial { @@ -1732,22 +1729,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) return -ENODEV; port_number = port->port_number; - switch (port_number) { - case 0: - edge_port->uart_base = UMPMEM_BASE_UART1; - edge_port->dma_address = UMPD_OEDB1_ADDRESS; - break; - case 1: - edge_port->uart_base = UMPMEM_BASE_UART2; - edge_port->dma_address = UMPD_OEDB2_ADDRESS; - break; - default: - dev_err(&port->dev, "Unknown port number!!!\n"); - return -ENODEV; - } - - dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", - __func__, port_number, edge_port->uart_base, edge_port->dma_address); dev = port->serial->dev; @@ -1872,8 +1853,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) ++edge_serial->num_ports_open; - port->port.drain_delay = 1; - goto release_es_lock; unlink_int_urb: @@ -1905,7 +1884,7 @@ static void edge_close(struct usb_serial_port *port) usb_kill_urb(port->write_urb); edge_port->ep_write_urb_in_use = 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - kfifo_reset_out(&edge_port->write_fifo); + kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); @@ -1939,7 +1918,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, if (edge_port->close_pending == 1) return -ENODEV; - count = kfifo_in_locked(&edge_port->write_fifo, data, count, + count = kfifo_in_locked(&port->write_fifo, data, count, &edge_port->ep_lock); edge_send(port, tty); @@ -1959,7 +1938,7 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty) return; } - count = kfifo_out(&edge_port->write_fifo, + count = kfifo_out(&port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -2007,7 +1986,7 @@ static int edge_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - room = kfifo_avail(&edge_port->write_fifo); + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); @@ -2024,7 +2003,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty) return 0; spin_lock_irqsave(&edge_port->ep_lock, flags); - chars = kfifo_len(&edge_port->write_fifo); + chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); @@ -2451,30 +2430,45 @@ static int edge_port_probe(struct usb_serial_port *port) if (!edge_port) return -ENOMEM; - ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, - GFP_KERNEL); - if (ret) { - kfree(edge_port); - return -ENOMEM; - } - spin_lock_init(&edge_port->ep_lock); edge_port->port = port; edge_port->edge_serial = usb_get_serial_data(port->serial); edge_port->bUartMode = default_uart_mode; + switch (port->port_number) { + case 0: + edge_port->uart_base = UMPMEM_BASE_UART1; + edge_port->dma_address = UMPD_OEDB1_ADDRESS; + break; + case 1: + edge_port->uart_base = UMPMEM_BASE_UART2; + edge_port->dma_address = UMPD_OEDB2_ADDRESS; + break; + default: + dev_err(&port->dev, "unknown port number\n"); + ret = -ENODEV; + goto err; + } + + dev_dbg(&port->dev, + "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n", + __func__, port->port_number, edge_port->uart_base, + edge_port->dma_address); + usb_set_serial_port_data(port, edge_port); ret = edge_create_sysfs_attrs(port); - if (ret) { - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - return ret; - } + if (ret) + goto err; port->port.closing_wait = msecs_to_jiffies(closing_wait * 10); + port->port.drain_delay = 1; return 0; +err: + kfree(edge_port); + + return ret; } static int edge_port_remove(struct usb_serial_port *port) @@ -2483,7 +2477,6 @@ static int edge_port_remove(struct usb_serial_port *port) edge_port = usb_get_serial_port_data(port); edge_remove_sysfs_attrs(port); - kfifo_free(&edge_port->write_fifo); kfree(edge_port); return 0; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 603fb70dde8..dfa67890663 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -183,7 +183,10 @@ #define LED_ON_MS 500 #define LED_OFF_MS 500 -static int device_type; +enum mos7840_flag { + MOS7840_FLAG_CTRL_BUSY, + MOS7840_FLAG_LED_BUSY, +}; static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, @@ -218,7 +221,6 @@ struct moschip_port { __u8 shadowMCR; /* last MCR value received */ char open; char open_ports; - wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ struct usb_serial_port *port; /* loop back to the owner of this object */ /* Offsets */ @@ -238,9 +240,12 @@ struct moschip_port { /* For device(s) with LED indicator */ bool has_led; - bool led_flag; struct timer_list led_timer1; /* Timer for LED on */ struct timer_list led_timer2; /* Timer for LED off */ + struct urb *led_urb; + struct usb_ctrlrequest *led_dr; + + unsigned long flags; }; /* @@ -460,10 +465,10 @@ static void mos7840_control_callback(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); - return; + goto out; default: dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); - return; + goto out; } dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); @@ -476,6 +481,8 @@ static void mos7840_control_callback(struct urb *urb) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) mos7840_handle_new_lsr(mos7840_port, regval); +out: + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); } static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, @@ -486,6 +493,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, unsigned char *buffer = mcs->ctrl_buf; int ret; + if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) + return -EBUSY; + dr->bRequestType = MCS_RD_RTYPE; dr->bRequest = MCS_RDREQ; dr->wValue = cpu_to_le16(Wval); /* 0 */ @@ -497,6 +507,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, mos7840_control_callback, mcs); mcs->control_urb->transfer_buffer_length = 2; ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); + if (ret) + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); + return ret; } @@ -523,7 +536,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, __u16 reg) { struct usb_device *dev = mcs->port->serial->dev; - struct usb_ctrlrequest *dr = mcs->dr; + struct usb_ctrlrequest *dr = mcs->led_dr; dr->bRequestType = MCS_WR_RTYPE; dr->bRequest = MCS_WRREQ; @@ -531,10 +544,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, dr->wIndex = cpu_to_le16(reg); dr->wLength = cpu_to_le16(0); - usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), + usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0), (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); - usb_submit_urb(mcs->control_urb, GFP_ATOMIC); + usb_submit_urb(mcs->led_urb, GFP_ATOMIC); } static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, @@ -560,7 +573,19 @@ static void mos7840_led_flag_off(unsigned long arg) { struct moschip_port *mcs = (struct moschip_port *) arg; - mcs->led_flag = false; + clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags); +} + +static void mos7840_led_activity(struct usb_serial_port *port) +{ + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); + + if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags)) + return; + + mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); } /***************************************************************************** @@ -758,14 +783,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } - /* Turn on LED */ - if (mos7840_port->has_led && !mos7840_port->led_flag) { - mos7840_port->led_flag = true; - mos7840_set_led_async(mos7840_port, 0x0301, - MODEM_CONTROL_REGISTER); - mod_timer(&mos7840_port->led_timer1, - jiffies + msecs_to_jiffies(LED_ON_MS)); - } + if (mos7840_port->has_led) + mos7840_led_activity(port); mos7840_port->read_urb_busy = true; retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); @@ -816,18 +835,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) /************************************************************************/ /* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ /************************************************************************/ -#ifdef MCSSerialProbe -static int mos7840_serial_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - - /*need to implement the mode_reg reading and updating\ - structures usb_serial_ device_type\ - (i.e num_ports, num_bulkin,bulkout etc) */ - /* Also we can update the changes attach */ - return 1; -} -#endif /***************************************************************************** * mos7840_open @@ -1092,9 +1099,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) mos7840_port->read_urb_busy = false; } - /* initialize our wait queues */ - init_waitqueue_head(&mos7840_port->wait_chase); - /* initialize our port settings */ /* Must set to enable ints! */ mos7840_port->shadowMCR = MCR_MASTER_IE; @@ -1220,47 +1224,6 @@ static void mos7840_close(struct usb_serial_port *port) mos7840_port->open = 0; } -/************************************************************************ - * - * mos7840_block_until_chase_response - * - * This function will block the close until one of the following: - * 1. Response to our Chase comes from mos7840 - * 2. A timeout of 10 seconds without activity has expired - * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty) - * - ************************************************************************/ - -static void mos7840_block_until_chase_response(struct tty_struct *tty, - struct moschip_port *mos7840_port) -{ - int timeout = msecs_to_jiffies(1000); - int wait = 10; - int count; - - while (1) { - count = mos7840_chars_in_buffer(tty); - - /* Check for Buffer status */ - if (count <= 0) - return; - - /* Block the thread for a while */ - interruptible_sleep_on_timeout(&mos7840_port->wait_chase, - timeout); - /* No activity.. count down section */ - wait--; - if (wait == 0) { - dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__); - return; - } else { - /* Reset timeout value back to seconds */ - wait = 10; - } - } - -} - /***************************************************************************** * mos7840_break * this function sends a break to the port @@ -1284,9 +1247,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state) if (mos7840_port == NULL) return; - /* flush and block until tx is empty */ - mos7840_block_until_chase_response(tty, mos7840_port); - if (break_state == -1) data = mos7840_port->shadowLCR | LCR_SET_BREAK; else @@ -1454,13 +1414,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, data1 = urb->transfer_buffer; dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); - /* Turn on LED */ - if (mos7840_port->has_led && !mos7840_port->led_flag) { - mos7840_port->led_flag = true; - mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); - mod_timer(&mos7840_port->led_timer1, - jiffies + msecs_to_jiffies(LED_ON_MS)); - } + if (mos7840_port->has_led) + mos7840_led_activity(port); /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); @@ -2187,38 +2142,48 @@ static int mos7810_check(struct usb_serial *serial) return 0; } -static int mos7840_calc_num_ports(struct usb_serial *serial) +static int mos7840_probe(struct usb_serial *serial, + const struct usb_device_id *id) { - __u16 data = 0x00; + u16 product = serial->dev->descriptor.idProduct; u8 *buf; - int mos7840_num_ports; + int device_type; + + if (product == MOSCHIP_DEVICE_ID_7810 || + product == MOSCHIP_DEVICE_ID_7820) { + device_type = product; + goto out; + } buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); - if (buf) { - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + if (!buf) + return -ENOMEM; + + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - data = *buf; - kfree(buf); - } - if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || - serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { - device_type = serial->dev->descriptor.idProduct; - } else { - /* For a MCS7840 device GPIO0 must be set to 1 */ - if ((data & 0x01) == 1) - device_type = MOSCHIP_DEVICE_ID_7840; - else if (mos7810_check(serial)) - device_type = MOSCHIP_DEVICE_ID_7810; - else - device_type = MOSCHIP_DEVICE_ID_7820; - } + /* For a MCS7840 device GPIO0 must be set to 1 */ + if (buf[0] & 0x01) + device_type = MOSCHIP_DEVICE_ID_7840; + else if (mos7810_check(serial)) + device_type = MOSCHIP_DEVICE_ID_7810; + else + device_type = MOSCHIP_DEVICE_ID_7820; + + kfree(buf); +out: + usb_set_serial_data(serial, (void *)(unsigned long)device_type); + + return 0; +} + +static int mos7840_calc_num_ports(struct usb_serial *serial) +{ + int device_type = (unsigned long)usb_get_serial_data(serial); + int mos7840_num_ports; mos7840_num_ports = (device_type >> 4) & 0x000F; - serial->num_bulk_in = mos7840_num_ports; - serial->num_bulk_out = mos7840_num_ports; - serial->num_ports = mos7840_num_ports; return mos7840_num_ports; } @@ -2226,6 +2191,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + int device_type = (unsigned long)usb_get_serial_data(serial); struct moschip_port *mos7840_port; int status; int pnum; @@ -2401,6 +2367,14 @@ static int mos7840_port_probe(struct usb_serial_port *port) if (device_type == MOSCHIP_DEVICE_ID_7810) { mos7840_port->has_led = true; + mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL); + mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr), + GFP_KERNEL); + if (!mos7840_port->led_urb || !mos7840_port->led_dr) { + status = -ENOMEM; + goto error; + } + init_timer(&mos7840_port->led_timer1); mos7840_port->led_timer1.function = mos7840_led_off; mos7840_port->led_timer1.expires = @@ -2413,8 +2387,6 @@ static int mos7840_port_probe(struct usb_serial_port *port) jiffies + msecs_to_jiffies(LED_OFF_MS); mos7840_port->led_timer2.data = (unsigned long)mos7840_port; - mos7840_port->led_flag = false; - /* Turn off LED */ mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); } @@ -2436,6 +2408,8 @@ out: } return 0; error: + kfree(mos7840_port->led_dr); + usb_free_urb(mos7840_port->led_urb); kfree(mos7840_port->dr); kfree(mos7840_port->ctrl_buf); usb_free_urb(mos7840_port->control_urb); @@ -2456,6 +2430,10 @@ static int mos7840_port_remove(struct usb_serial_port *port) del_timer_sync(&mos7840_port->led_timer1); del_timer_sync(&mos7840_port->led_timer2); + + usb_kill_urb(mos7840_port->led_urb); + usb_free_urb(mos7840_port->led_urb); + kfree(mos7840_port->led_dr); } usb_kill_urb(mos7840_port->control_urb); usb_free_urb(mos7840_port->control_urb); @@ -2482,9 +2460,7 @@ static struct usb_serial_driver moschip7840_4port_device = { .throttle = mos7840_throttle, .unthrottle = mos7840_unthrottle, .calc_num_ports = mos7840_calc_num_ports, -#ifdef MCSSerialProbe - .probe = mos7840_serial_probe, -#endif + .probe = mos7840_probe, .ioctl = mos7840_ioctl, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c deleted file mode 100644 index c5ff6c7795a..00000000000 --- a/drivers/usb/serial/moto_modem.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Motorola USB Phone driver - * - * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * {sigh} - * Motorola should be using the CDC ACM USB spec, but instead - * they try to just "do their own thing"... This driver should handle a - * few phones in which a basic "dumb serial connection" is needed to be - * able to get a connection through to them. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ - { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ - { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ - { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ - { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver moto_device = { - .driver = { - .owner = THIS_MODULE, - .name = "moto-modem", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &moto_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 7e3e0782e51..a2080ac7b7e 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -343,6 +343,8 @@ static int oti6858_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + return 0; } @@ -411,9 +413,6 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - if (!tty) - return; - cflag = tty->termios.c_cflag; spin_lock_irqsave(&priv->lock, flags); @@ -509,7 +508,6 @@ static void oti6858_set_termios(struct tty_struct *tty, static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) { struct oti6858_private *priv = usb_get_serial_port_data(port); - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct oti6858_control_pkt *buf; unsigned long flags; @@ -560,8 +558,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) /* setup termios */ if (tty) - oti6858_set_termios(tty, port, &tmp_termios); - port->port.drain_delay = 256; /* FIXME: check the FIFO length */ + oti6858_set_termios(tty, port, NULL); + return 0; } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index cb6bbed374f..6638c5d9079 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -4,6 +4,11 @@ * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2003 IBM Corp. * + * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com> + * - fixes, improvements and documentation for the baud rate encoding methods + * Copyright (C) 2013 Reinhard Max <max@suse.de> + * - fixes and improvements for the divisor based baud rate encoding method + * * Original driver for 2.2.x by anonymous * * This program is free software; you can redistribute it and/or @@ -29,6 +34,7 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> +#include <asm/unaligned.h> #include "pl2303.h" /* @@ -235,6 +241,8 @@ static int pl2303_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } @@ -261,6 +269,153 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) return retval; } +static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, + u8 buf[4]) +{ + /* + * NOTE: Only the values defined in baud_sup are supported ! + * => if unsupported values are set, the PL2303 seems to + * use 9600 baud (at least my PL2303X always does) + */ + const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, + 4800, 7200, 9600, 14400, 19200, 28800, 38400, + 57600, 115200, 230400, 460800, 614400, 921600, + 1228800, 2457600, 3000000, 6000000 }; + /* + * NOTE: The PL2303HX (tested with rev. 3A) also supports the following + * baud rates: 128000, 134400, 161280, 201600, 268800, 403200, 806400. + * As long as we are not using this encoding method for them, there is + * no point in complicating the code to support them. + */ + int i; + + /* Set baudrate to nearest supported value */ + for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { + if (baud_sup[i] > baud) + break; + } + if (i == ARRAY_SIZE(baud_sup)) + baud = baud_sup[i - 1]; + else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) + baud = baud_sup[i - 1]; + else + baud = baud_sup[i]; + /* type_0, type_1 only support up to 1228800 baud */ + if (type != HX) + baud = min_t(int, baud, 1228800); + /* Direct (standard) baud rate encoding method */ + put_unaligned_le32(baud, buf); + + return baud; +} + +static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type, + u8 buf[4]) +{ + /* + * Divisor based baud rate encoding method + * + * NOTE: it's not clear if the type_0/1 chips support this method + * + * divisor = 12MHz * 32 / baudrate = 2^A * B + * + * with + * + * A = buf[1] & 0x0e + * B = buf[0] + (buf[1] & 0x01) << 8 + * + * Special cases: + * => 8 < B < 16: device seems to work not properly + * => B <= 8: device uses the max. value B = 512 instead + */ + unsigned int A, B; + + /* + * NOTE: The Windows driver allows maximum baud rates of 110% of the + * specified maximium value. + * Quick tests with early (2004) HX (rev. A) chips suggest, that even + * higher baud rates (up to the maximum of 24M baud !) are working fine, + * but that should really be tested carefully in "real life" scenarios + * before removing the upper limit completely. + * Baud rates smaller than the specified 75 baud are definitely working + * fine. + */ + if (type == HX) + baud = min_t(int, baud, 6000000 * 1.1); + else + baud = min_t(int, baud, 1228800 * 1.1); + /* Determine factors A and B */ + A = 0; + B = 12000000 * 32 / baud; /* 12MHz */ + B <<= 1; /* Add one bit for rounding */ + while (B > (512 << 1) && A <= 14) { + A += 2; + B >>= 2; + } + if (A > 14) { /* max. divisor = min. baudrate reached */ + A = 14; + B = 512; + /* => ~45.78 baud */ + } else { + B = (B + 1) >> 1; /* Round the last bit */ + } + /* Handle special cases */ + if (B == 512) + B = 0; /* also: 1 to 8 */ + else if (B < 16) + /* + * NOTE: With the current algorithm this happens + * only for A=0 and means that the min. divisor + * (respectively: the max. baudrate) is reached. + */ + B = 16; /* => 24 MBaud */ + /* Encode the baud rate */ + buf[3] = 0x80; /* Select divisor encoding method */ + buf[2] = 0; + buf[1] = (A & 0x0e); /* A */ + buf[1] |= ((B & 0x100) >> 8); /* MSB of B */ + buf[0] = B & 0xff; /* 8 LSBs of B */ + /* Calculate the actual/resulting baud rate */ + if (B <= 8) + B = 512; + baud = 12000000 * 32 / ((1 << A) * B); + + return baud; +} + +static void pl2303_encode_baudrate(struct tty_struct *tty, + struct usb_serial_port *port, + enum pl2303_type type, + u8 buf[4]) +{ + int baud; + + baud = tty_get_baud_rate(tty); + dev_dbg(&port->dev, "baud requested = %d\n", baud); + if (!baud) + return; + /* + * There are two methods for setting/encoding the baud rate + * 1) Direct method: encodes the baud rate value directly + * => supported by all chip types + * 2) Divisor based method: encodes a divisor to a base value (12MHz*32) + * => supported by HX chips (and likely not by type_0/1 chips) + * + * NOTE: Although the divisor based baud rate encoding method is much + * more flexible, some of the standard baud rate values can not be + * realized exactly. But the difference is very small (max. 0.2%) and + * the device likely uses the same baud rate generator for both methods + * so that there is likley no difference. + */ + if (type != HX) + baud = pl2303_baudrate_encode_direct(baud, type, buf); + else + baud = pl2303_baudrate_encode_divisor(baud, type, buf); + /* Save resulting baud rate */ + tty_encode_baud_rate(tty, baud, baud); + dev_dbg(&port->dev, "baud set = %d\n", baud); +} + static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -268,27 +423,18 @@ static void pl2303_set_termios(struct tty_struct *tty, struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag; unsigned char *buf; - int baud; int i; u8 control; - const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, - 57600, 115200, 230400, 460800, 500000, 614400, - 921600, 1228800, 2457600, 3000000, 6000000 }; - int baud_floor, baud_ceil; - int k; - - /* The PL2303 is reported to lose bytes if you change - serial settings even to the same values as before. Thus - we actually need to filter in this specific case */ + /* + * The PL2303 is reported to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + */ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; - cflag = tty->termios.c_cflag; - buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); @@ -303,8 +449,8 @@ static void pl2303_set_termios(struct tty_struct *tty, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); - if (cflag & CSIZE) { - switch (cflag & CSIZE) { + if (C_CSIZE(tty)) { + switch (C_CSIZE(tty)) { case CS5: buf[6] = 5; break; @@ -317,73 +463,22 @@ static void pl2303_set_termios(struct tty_struct *tty, default: case CS8: buf[6] = 8; - break; } dev_dbg(&port->dev, "data bits = %d\n", buf[6]); } - /* For reference buf[0]:buf[3] baud rate value */ - /* NOTE: Only the values defined in baud_sup are supported ! - * => if unsupported values are set, the PL2303 seems to use - * 9600 baud (at least my PL2303X always does) - */ - baud = tty_get_baud_rate(tty); - dev_dbg(&port->dev, "baud requested = %d\n", baud); - if (baud) { - /* Set baudrate to nearest supported value */ - for (k=0; k<ARRAY_SIZE(baud_sup); k++) { - if (baud_sup[k] / baud) { - baud_ceil = baud_sup[k]; - if (k==0) { - baud = baud_ceil; - } else { - baud_floor = baud_sup[k-1]; - if ((baud_ceil % baud) - > (baud % baud_floor)) - baud = baud_floor; - else - baud = baud_ceil; - } - break; - } - } - if (baud > 1228800) { - /* type_0, type_1 only support up to 1228800 baud */ - if (spriv->type != HX) - baud = 1228800; - else if (baud > 6000000) - baud = 6000000; - } - dev_dbg(&port->dev, "baud set = %d\n", baud); - if (baud <= 115200) { - buf[0] = baud & 0xff; - buf[1] = (baud >> 8) & 0xff; - buf[2] = (baud >> 16) & 0xff; - buf[3] = (baud >> 24) & 0xff; - } else { - /* apparently the formula for higher speeds is: - * baudrate = 12M * 32 / (2^buf[1]) / buf[0] - */ - unsigned tmp = 12*1000*1000*32 / baud; - buf[3] = 0x80; - buf[2] = 0; - buf[1] = (tmp >= 256); - while (tmp >= 256) { - tmp >>= 2; - buf[1] <<= 1; - } - buf[0] = tmp; - } - } + /* For reference: buf[0]:buf[3] baud rate value */ + pl2303_encode_baudrate(tty, port, spriv->type, buf); /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - if (cflag & CSTOPB) { - /* NOTE: Comply with "real" UARTs / RS232: + if (C_CSTOPB(tty)) { + /* + * NOTE: Comply with "real" UARTs / RS232: * use 1.5 instead of 2 stop bits with 5 data bits */ - if ((cflag & CSIZE) == CS5) { + if (C_CSIZE(tty) == CS5) { buf[4] = 1; dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { @@ -395,14 +490,14 @@ static void pl2303_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "stop bits = 1\n"); } - if (cflag & PARENB) { + if (C_PARENB(tty)) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ - if (cflag & PARODD) { - if (cflag & CMSPAR) { + if (C_PARODD(tty)) { + if (tty->termios.c_cflag & CMSPAR) { buf[5] = 3; dev_dbg(&port->dev, "parity = mark\n"); } else { @@ -410,7 +505,7 @@ static void pl2303_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "parity = odd\n"); } } else { - if (cflag & CMSPAR) { + if (tty->termios.c_cflag & CMSPAR) { buf[5] = 4; dev_dbg(&port->dev, "parity = space\n"); } else { @@ -431,7 +526,7 @@ static void pl2303_set_termios(struct tty_struct *tty, /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; - if ((cflag & CBAUD) == B0) + if (C_BAUD(tty) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); @@ -443,14 +538,13 @@ static void pl2303_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&priv->lock, flags); } - buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - + memset(buf, 0, 7); i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); - if (cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { if (spriv->type == HX) pl2303_vendor_write(0x0, 0x61, serial); else @@ -459,10 +553,6 @@ static void pl2303_set_termios(struct tty_struct *tty, pl2303_vendor_write(0x0, 0x0, serial); } - /* Save resulting baud rate */ - if (baud) - tty_encode_baud_rate(tty, baud, baud); - kfree(buf); } @@ -521,7 +611,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } - port->port.drain_delay = 256; return 0; } @@ -789,8 +878,10 @@ static void pl2303_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); + if (tty_flag != TTY_NORMAL) + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, + tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 21cd7bf2a8c..ba895989d8c 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -92,13 +92,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static __u16 vendor; /* no default */ -static __u16 product; /* no default */ -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); - module_param(safe, bool, 0); MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); @@ -140,8 +133,6 @@ static struct usb_device_id id_table[] = { {MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ {MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ {MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Sharp tmp */ - /* extra null entry for module vendor/produc parameters */ - {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, {} /* terminating entry */ }; @@ -272,7 +263,19 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port, static int safe_startup(struct usb_serial *serial) { - switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) { + struct usb_interface_descriptor *desc; + + if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS) + return -ENODEV; + + desc = &serial->interface->cur_altsetting->desc; + + if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS) + return -ENODEV; + if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL) + return -ENODEV; + + switch (desc->bInterfaceProtocol) { case LINEO_SAFESERIAL_CRC: break; case LINEO_SAFESERIAL_CRC_PADDED: @@ -300,30 +303,4 @@ static struct usb_serial_driver * const serial_drivers[] = { &safe_device, NULL }; -static int __init safe_init(void) -{ - int i; - - /* if we have vendor / product parameters patch them into id list */ - if (vendor || product) { - pr_info("vendor: %x product: %x\n", vendor, product); - - for (i = 0; i < ARRAY_SIZE(id_table); i++) { - if (!id_table[i].idVendor && !id_table[i].idProduct) { - id_table[i].idVendor = vendor; - id_table[i].idProduct = product; - break; - } - } - } - - return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table); -} - -static void __exit safe_exit(void) -{ - usb_serial_deregister_drivers(serial_drivers); -} - -module_init(safe_init); -module_exit(safe_exit); +module_usb_serial_driver(serial_drivers, id_table); diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c deleted file mode 100644 index a76b1ae54a2..00000000000 --- a/drivers/usb/serial/siemens_mpi.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Siemens USB-MPI Serial USB driver - * - * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de> - * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net" -#define DRIVER_DESC "Driver for Siemens USB/MPI adapter" - - -static const struct usb_device_id id_table[] = { - /* Vendor and product id for 6ES7-972-0CB20-0XA0 */ - { USB_DEVICE(0x908, 0x0004) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver siemens_usb_mpi_device = { - .driver = { - .owner = THIS_MODULE, - .name = "siemens_mpi", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &siemens_usb_mpi_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index ddf6c47137d..4abac28b599 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -169,6 +169,8 @@ static int spcp8x5_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); + port->port.drain_delay = 256; + return 0; } @@ -411,8 +413,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) spcp8x5_set_termios(tty, port, NULL); - port->port.drain_delay = 256; - return usb_serial_generic_open(tty, port); } diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 375b5a400b6..5c07d55ece7 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -45,8 +45,6 @@ #define TI_FIRMWARE_BUF_SIZE 16284 -#define TI_WRITE_BUF_SIZE 1024 - #define TI_TRANSFER_TIMEOUT 2 #define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ @@ -71,13 +69,11 @@ struct ti_port { __u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; int tp_flags; - wait_queue_head_t tp_write_wait; struct ti_device *tp_tdev; struct usb_serial_port *tp_port; spinlock_t tp_lock; int tp_read_urb_state; int tp_write_urb_in_use; - struct kfifo write_fifo; }; struct ti_device { @@ -145,20 +141,9 @@ static int ti_download_firmware(struct ti_device *tdev); /* module parameters */ static int closing_wait = TI_DEFAULT_CLOSING_WAIT; -static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_3410_count; -static ushort product_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_3410_count; -static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_5052_count; -static ushort product_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_5052_count; /* supported devices */ -/* the array dimension is the number of default entries plus */ -/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ -/* null entry */ -static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -175,16 +160,18 @@ static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, + { } /* terminator */ }; -static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_5052[] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, + { } /* terminator */ }; -static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -204,7 +191,7 @@ static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, - { } + { } /* terminator */ }; static struct usb_serial_driver ti_1port_device = { @@ -293,61 +280,12 @@ module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain in close, in .01 secs, default is 4000"); -module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO); -MODULE_PARM_DESC(vendor_3410, - "Vendor ids for 3410 based devices, 1-5 short integers"); -module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO); -MODULE_PARM_DESC(product_3410, - "Product ids for 3410 based devices, 1-5 short integers"); -module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO); -MODULE_PARM_DESC(vendor_5052, - "Vendor ids for 5052 based devices, 1-5 short integers"); -module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO); -MODULE_PARM_DESC(product_5052, - "Product ids for 5052 based devices, 1-5 short integers"); - MODULE_DEVICE_TABLE(usb, ti_id_table_combined); +module_usb_serial_driver(serial_drivers, ti_id_table_combined); /* Functions */ -static int __init ti_init(void) -{ - int i, j, c; - - /* insert extra vendor and product ids */ - c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1; - j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) { - ti_id_table_3410[j].idVendor = vendor_3410[i]; - ti_id_table_3410[j].idProduct = product_3410[i]; - ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_3410[i]; - ti_id_table_combined[c].idProduct = product_3410[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) { - ti_id_table_5052[j].idVendor = vendor_5052[i]; - ti_id_table_5052[j].idProduct = product_5052[i]; - ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_5052[i]; - ti_id_table_combined[c].idProduct = product_5052[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - - return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined); -} - -static void __exit ti_exit(void) -{ - usb_serial_deregister_drivers(serial_drivers); -} - -module_init(ti_init); -module_exit(ti_exit); - - static int ti_startup(struct usb_serial *serial) { struct ti_device *tdev; @@ -430,17 +368,14 @@ static int ti_port_probe(struct usb_serial_port *port) else tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); - init_waitqueue_head(&tport->tp_write_wait); - if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) { - kfree(tport); - return -ENOMEM; - } tport->tp_port = port; tport->tp_tdev = usb_get_serial_data(port->serial); tport->tp_uart_mode = 0; /* default is RS232 */ usb_set_serial_port_data(port, tport); + port->port.drain_delay = 3; + return 0; } @@ -449,7 +384,6 @@ static int ti_port_remove(struct usb_serial_port *port) struct ti_port *tport; tport = usb_get_serial_port_data(port); - kfifo_free(&tport->write_fifo); kfree(tport); return 0; @@ -582,8 +516,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) tport->tp_is_open = 1; ++tdev->td_open_port_count; - port->port.drain_delay = 3; - goto release_lock; unlink_int_urb: @@ -616,7 +548,7 @@ static void ti_close(struct usb_serial_port *port) usb_kill_urb(port->write_urb); tport->tp_write_urb_in_use = 0; spin_lock_irqsave(&tport->tp_lock, flags); - kfifo_reset_out(&tport->write_fifo); + kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); port_number = port->port_number; @@ -655,7 +587,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, if (tport == NULL || !tport->tp_is_open) return -ENODEV; - count = kfifo_in_locked(&tport->write_fifo, data, count, + count = kfifo_in_locked(&port->write_fifo, data, count, &tport->tp_lock); ti_send(tport); @@ -674,7 +606,7 @@ static int ti_write_room(struct tty_struct *tty) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - room = kfifo_avail(&tport->write_fifo); + room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); @@ -693,7 +625,7 @@ static int ti_chars_in_buffer(struct tty_struct *tty) return 0; spin_lock_irqsave(&tport->tp_lock, flags); - chars = kfifo_len(&tport->write_fifo); + chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); @@ -1090,13 +1022,11 @@ static void ti_bulk_in_callback(struct urb *urb) case -ESHUTDOWN: dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); return; default: dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); } if (status == -EPIPE) @@ -1152,13 +1082,11 @@ static void ti_bulk_out_callback(struct urb *urb) case -ESHUTDOWN: dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); return; default: dev_err_console(port, "%s - nonzero urb status, %d\n", __func__, status); tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); } /* send any buffered data */ @@ -1197,7 +1125,7 @@ static void ti_send(struct ti_port *tport) if (tport->tp_write_urb_in_use) goto unlock; - count = kfifo_out(&tport->write_fifo, + count = kfifo_out(&port->write_fifo, port->write_urb->transfer_buffer, port->bulk_out_size); @@ -1232,7 +1160,6 @@ static void ti_send(struct ti_port *tport) /* more room in the buffer for new writes, wakeup */ tty_port_tty_wakeup(&port->port); - wake_up_interruptible(&tport->tp_write_wait); return; unlock: spin_unlock_irqrestore(&tport->tp_lock, flags); @@ -1312,7 +1239,7 @@ static int ti_get_serial_info(struct ti_port *tport, ret_serial.line = port->minor; ret_serial.port = port->port_number; ret_serial.flags = tport->tp_flags; - ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE; + ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo); ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; ret_serial.closing_wait = cwait; diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c new file mode 100644 index 00000000000..6a06131f48f --- /dev/null +++ b/drivers/usb/serial/usb-serial-simple.c @@ -0,0 +1,110 @@ +/* + * USB Serial "Simple" driver + * + * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) + * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de> + * Copyright (C) 2009 Outpost Embedded, LLC + * Copyright (C) 2010 Zilogic Systems <code@zilogic.com> + * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com> + * Copyright (C) 2013 Linux Foundation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +#define DEVICE(vendor, IDS) \ +static const struct usb_device_id vendor##_id_table[] = { \ + IDS(), \ + { }, \ +}; \ +static struct usb_serial_driver vendor##_device = { \ + .driver = { \ + .owner = THIS_MODULE, \ + .name = "stringify(vendor)", \ + }, \ + .id_table = vendor##_id_table, \ + .num_ports = 1, \ +}; + + +/* ZIO Motherboard USB driver */ +#define ZIO_IDS() \ + { USB_DEVICE(0x1CBE, 0x0103) } +DEVICE(zio, ZIO_IDS); + +/* Funsoft Serial USB driver */ +#define FUNSOFT_IDS() \ + { USB_DEVICE(0x1404, 0xcddc) } +DEVICE(funsoft, FUNSOFT_IDS); + +/* Infineon Flashloader driver */ +#define FLASHLOADER_IDS() \ + { USB_DEVICE(0x8087, 0x0716) } +DEVICE(flashloader, FLASHLOADER_IDS); + +/* ViVOpay USB Serial Driver */ +#define VIVOPAY_IDS() \ + { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */ +DEVICE(vivopay, VIVOPAY_IDS); + +/* Motorola USB Phone driver */ +#define MOTO_IDS() \ + { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ \ + { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ \ + { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ \ + { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ \ + { USB_DEVICE(0x22b8, 0x2c64) } /* Motorola V950 phone */ +DEVICE(moto_modem, MOTO_IDS); + +/* HP4x (48/49) Generic Serial driver */ +#define HP4X_IDS() \ + { USB_DEVICE(0x03f0, 0x0121) } +DEVICE(hp4x, HP4X_IDS); + +/* Suunto ANT+ USB Driver */ +#define SUUNTO_IDS() \ + { USB_DEVICE(0x0fcf, 0x1008) } +DEVICE(suunto, SUUNTO_IDS); + +/* Siemens USB/MPI adapter */ +#define SIEMENS_IDS() \ + { USB_DEVICE(0x908, 0x0004) } +DEVICE(siemens_mpi, SIEMENS_IDS); + +/* All of the above structures mushed into two lists */ +static struct usb_serial_driver * const serial_drivers[] = { + &zio_device, + &funsoft_device, + &flashloader_device, + &vivopay_device, + &moto_modem_device, + &hp4x_device, + &suunto_device, + &siemens_mpi_device, + NULL +}; + +static const struct usb_device_id id_table[] = { + ZIO_IDS(), + FUNSOFT_IDS(), + FLASHLOADER_IDS(), + VIVOPAY_IDS(), + MOTO_IDS(), + HP4X_IDS(), + SUUNTO_IDS(), + SIEMENS_IDS(), + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +module_usb_serial_driver(serial_drivers, id_table); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index cb27fcb2fc9..6091bd5a1f4 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -681,20 +681,10 @@ static int serial_port_carrier_raised(struct tty_port *port) static void serial_port_dtr_rts(struct tty_port *port, int on) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); - struct usb_serial *serial = p->serial; - struct usb_serial_driver *drv = serial->type; + struct usb_serial_driver *drv = p->serial->type; - if (!drv->dtr_rts) - return; - /* - * Work-around bug in the tty-layer which can result in dtr_rts - * being called after a disconnect (and tty_unregister_device - * has returned). Remove once bug has been squashed. - */ - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) + if (drv->dtr_rts) drv->dtr_rts(p, on); - mutex_unlock(&serial->disc_mutex); } static const struct tty_port_operations serial_port_ops = { diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c deleted file mode 100644 index 6299526ff8c..00000000000 --- a/drivers/usb/serial/vivopay-serial.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2009 Outpost Embedded, LLC - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> - -#define DRIVER_DESC "ViVOpay USB Serial Driver" - -#define VIVOPAY_VENDOR_ID 0x1d5f - - -static struct usb_device_id id_table [] = { - /* ViVOpay 8800 */ - { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver vivopay_serial_device = { - .driver = { - .owner = THIS_MODULE, - .name = "vivopay-serial", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &vivopay_serial_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); - -MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c deleted file mode 100644 index c043aa84a0b..00000000000 --- a/drivers/usb/serial/zio.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ZIO Motherboard USB driver - * - * Copyright (C) 2010 Zilogic Systems <code@zilogic.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/usb/serial.h> -#include <linux/uaccess.h> - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1CBE, 0x0103) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_serial_driver zio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "zio", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &zio_device, NULL -}; - -module_usb_serial_driver(serial_drivers, id_table); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 7ed3b039dbe..ff97652343a 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -325,9 +325,8 @@ retry: rv = skel_do_read_io(dev, count); if (rv < 0) goto exit; - else if (!(file->f_flags & O_NONBLOCK)) + else goto retry; - rv = -EAGAIN; } exit: mutex_unlock(&dev->io_mutex); diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index bdb0cc3046b..fe8bc777ab8 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -141,18 +141,26 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) { struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - size_t cnt, size; - unsigned long *buf = (unsigned long *) _buf; + size_t cnt, size, bits_set = 0; /* WE DON'T LOCK, see comment */ - size = wusbhc->ports_max + 1 /* hub bit */; - size = (size + 8 - 1) / 8; /* round to bytes */ - for (cnt = 0; cnt < wusbhc->ports_max; cnt++) - if (wusb_port_by_idx(wusbhc, cnt)->change) - set_bit(cnt + 1, buf); - else - clear_bit(cnt + 1, buf); - return size; + /* round up to bytes. Hub bit is bit 0 so add 1. */ + size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8); + + /* clear the output buffer. */ + memset(_buf, 0, size); + /* set the bit for each changed port. */ + for (cnt = 0; cnt < wusbhc->ports_max; cnt++) { + + if (wusb_port_by_idx(wusbhc, cnt)->change) { + const int bitpos = cnt+1; + + _buf[bitpos/8] |= (1 << (bitpos % 8)); + bits_set++; + } + } + + return bits_set ? size : 0; } EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 16968c89949..f5c81afc6e9 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -928,7 +928,7 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) spin_lock_irqsave(&rpipe->seg_lock, flags); while (atomic_read(&rpipe->segs_available) > 0 && !list_empty(&rpipe->seg_list)) { - seg = list_entry(rpipe->seg_list.next, struct wa_seg, + seg = list_first_entry(&(rpipe->seg_list), struct wa_seg, list_node); list_del(&seg->list_node); xfer = seg->xfer; @@ -1093,30 +1093,35 @@ error_xfer_submit: * * We need to be careful here, as dequeue() could be called in the * middle. That's why we do the whole thing under the - * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock + * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock * and then checks the list -- so as we would be acquiring in inverse - * order, we just drop the lock once we have the xfer and reacquire it - * later. + * order, we move the delayed list to a separate list while locked and then + * submit them without the list lock held. */ void wa_urb_enqueue_run(struct work_struct *ws) { struct wahc *wa = container_of(ws, struct wahc, xfer_work); struct wa_xfer *xfer, *next; struct urb *urb; + LIST_HEAD(tmp_list); + /* Create a copy of the wa->xfer_delayed_list while holding the lock */ spin_lock_irq(&wa->xfer_list_lock); - list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list, - list_node) { + list_cut_position(&tmp_list, &wa->xfer_delayed_list, + wa->xfer_delayed_list.prev); + spin_unlock_irq(&wa->xfer_list_lock); + + /* + * enqueue from temp list without list lock held since wa_urb_enqueue_b + * can take xfer->lock as well as lock mutexes. + */ + list_for_each_entry_safe(xfer, next, &tmp_list, list_node) { list_del_init(&xfer->list_node); - spin_unlock_irq(&wa->xfer_list_lock); urb = xfer->urb; wa_urb_enqueue_b(xfer); usb_put_urb(urb); /* taken when queuing */ - - spin_lock_irq(&wa->xfer_list_lock); } - spin_unlock_irq(&wa->xfer_list_lock); } EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); |