diff options
Diffstat (limited to 'drivers/usb')
177 files changed, 7451 insertions, 2523 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8ed451dd651e..8689dcba5201 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -31,8 +31,6 @@ if USB_SUPPORT config USB_COMMON tristate - default y - depends on USB || USB_GADGET config USB_ARCH_HAS_HCD def_bool y @@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD config USB tristate "Support for Host-side USB" depends on USB_ARCH_HAS_HCD + select USB_COMMON select NLS # for UTF-8 strings ---help--- Universal Serial Bus (USB) is a specification for a serial bus diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index a2ae88dbda78..4333dc576a12 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -173,10 +173,10 @@ struct uea_softc { const struct firmware *dsp_firm; struct urb *urb_int; - void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); - void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); - int (*stat) (struct uea_softc *); - int (*send_cmvs) (struct uea_softc *); + void (*dispatch_cmv)(struct uea_softc *, struct intr_pkt *); + void (*schedule_load_page)(struct uea_softc *, struct intr_pkt *); + int (*stat)(struct uea_softc *); + int (*send_cmvs)(struct uea_softc *); /* keep in sync with eaglectl */ struct uea_stats { @@ -2454,7 +2454,7 @@ UEA_ATTR(firmid, 0); /* Retrieve the device End System Identifier (MAC) */ -static int uea_getesi(struct uea_softc *sc, u_char * esi) +static int uea_getesi(struct uea_softc *sc, u_char *esi) { unsigned char mac_str[2 * ETH_ALEN + 1]; int i; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 9ce8c9f91674..dedc33e589f4 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -292,10 +292,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) data->supports_runtime_pm = true; - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - goto err_clk; - ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a6c4a1b895bd..94a14f5dc4d4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1680,7 +1680,7 @@ static int acm_resume(struct usb_interface *intf) if (--acm->susp_count) goto out; - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { + if (tty_port_initialized(&acm->port)) { rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); for (;;) { @@ -1710,7 +1710,7 @@ static int acm_reset_resume(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) + if (tty_port_initialized(&acm->port)) tty_port_tty_hangup(&acm->port, false); return acm_resume(intf); diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c index 504708f59b93..9059b7dc185e 100644 --- a/drivers/usb/common/usb-otg-fsm.c +++ b/drivers/usb/common/usb-otg-fsm.c @@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) return 0; } -static int state_changed; - /* Called when leaving a state. Do state clean up jobs here */ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) { @@ -208,7 +206,6 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm) /* Called when entering a state */ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) { - state_changed = 1; if (fsm->otg->state == new_state) return 0; VDBG("Set state: %s\n", usb_otg_state_string(new_state)); @@ -324,6 +321,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) } fsm->otg->state = new_state; + fsm->state_changed = 1; return 0; } @@ -335,7 +333,7 @@ int otg_statemachine(struct otg_fsm *fsm) mutex_lock(&fsm->lock); state = fsm->otg->state; - state_changed = 0; + fsm->state_changed = 0; /* State machine state change judgement */ switch (state) { @@ -448,7 +446,7 @@ int otg_statemachine(struct otg_fsm *fsm) } mutex_unlock(&fsm->lock); - VDBG("quit statemachine, changed = %d\n", state_changed); - return state_changed; + VDBG("quit statemachine, changed = %d\n", fsm->state_changed); + return fsm->state_changed; } EXPORT_SYMBOL_GPL(otg_statemachine); diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 2741566ee4f2..98e39f91723a 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -122,6 +122,9 @@ void *hcd_buffer_alloc( struct usb_hcd *hcd = bus_to_hcd(bus); int i; + if (size == 0) + return NULL; + /* some USB hosts just use PIO */ if (!IS_ENABLED(CONFIG_HAS_DMA) || (!bus->controller->dma_mask && diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 52c4461dfccd..e9f5043a2167 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -216,7 +216,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma) dec_usb_memory_use_count(usbm, &usbm->vma_use_count); } -struct vm_operations_struct usbdev_vm_ops = { +static struct vm_operations_struct usbdev_vm_ops = { .open = usbdev_vm_open, .close = usbdev_vm_close }; @@ -1316,10 +1316,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg) static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg) { - struct usbdevfs_connectinfo ci = { - .devnum = ps->dev->devnum, - .slow = ps->dev->speed == USB_SPEED_LOW - }; + struct usbdevfs_connectinfo ci; + + memset(&ci, 0, sizeof(ci)); + ci.devnum = ps->dev->devnum; + ci.slow = ps->dev->speed == USB_SPEED_LOW; if (copy_to_user(arg, &ci, sizeof(ci))) return -EFAULT; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 2057d91d8336..dadd1e8dfe09 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev) struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; - int lpm_disable_error; + int lpm_disable_error = -ENODEV; dev_dbg(dev, "%s\n", __func__); @@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev) * setting during probe, that should also be fine. usb_set_interface() * will attempt to disable LPM, and fail if it can't disable it. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error && driver->disable_hub_initiated_lpm) { - dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); - error = lpm_disable_error; - goto err; + if (driver->disable_hub_initiated_lpm) { + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error) { + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + error = lpm_disable_error; + goto err; + } } /* Carry out a deferred switch to altsetting 0 */ @@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev) struct usb_interface *intf = to_usb_interface(dev); struct usb_host_endpoint *ep, **eps = NULL; struct usb_device *udev; - int i, j, error, r, lpm_disable_error; + int i, j, error, r; + int lpm_disable_error = -ENODEV; intf->condition = USB_INTERFACE_UNBINDING; @@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev) udev = interface_to_usbdev(intf); error = usb_autoresume_device(udev); - /* Hub-initiated LPM policy may change, so attempt to disable LPM until + /* If hub-initiated LPM policy may change, attempt to disable LPM until * the driver is unbound. If LPM isn't disabled, that's fine because it * wouldn't be enabled unless all the bound interfaces supported * hub-initiated LPM. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (driver->disable_hub_initiated_lpm) + lpm_disable_error = usb_unlocked_disable_lpm(udev); /* * Terminate all URBs for this interface unless the driver @@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct device *dev; struct usb_device *udev; int retval = 0; - int lpm_disable_error; + int lpm_disable_error = -ENODEV; if (!iface) return -ENODEV; @@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver, iface->condition = USB_INTERFACE_BOUND; - /* Disable LPM until this driver is bound. */ - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error && driver->disable_hub_initiated_lpm) { - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); - return -ENOMEM; + /* See the comment about disabling LPM in usb_probe_interface(). */ + if (driver->disable_hub_initiated_lpm) { + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error) { + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + return -ENOMEM; + } } /* Claimed interfaces are initially inactive (suspended) and diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 2ca2cef7f681..34b837ae1ed7 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -994,7 +994,7 @@ static void usb_bus_init (struct usb_bus *bus) bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; - mutex_init(&bus->usb_address0_mutex); + mutex_init(&bus->devnum_next_mutex); } /*-------------------------------------------------------------------------*/ @@ -1118,6 +1118,7 @@ static int register_root_hub(struct usb_hcd *hcd) /* Did the HC die before the root hub was registered? */ if (HCD_DEAD(hcd)) usb_hc_died (hcd); /* This time clean up */ + usb_dev->dev.of_node = parent_dev->of_node; } mutex_unlock(&usb_bus_idr_lock); @@ -2521,6 +2522,14 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, return NULL; } if (primary_hcd == NULL) { + hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex), + GFP_KERNEL); + if (!hcd->address0_mutex) { + kfree(hcd); + dev_dbg(dev, "hcd address0 mutex alloc failed\n"); + return NULL; + } + mutex_init(hcd->address0_mutex); hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex), GFP_KERNEL); if (!hcd->bandwidth_mutex) { @@ -2532,6 +2541,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, dev_set_drvdata(dev, hcd); } else { mutex_lock(&usb_port_peer_mutex); + hcd->address0_mutex = primary_hcd->address0_mutex; hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; hcd->primary_hcd = primary_hcd; primary_hcd->primary_hcd = primary_hcd; @@ -2598,8 +2608,10 @@ static void hcd_release(struct kref *kref) struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); mutex_lock(&usb_port_peer_mutex); - if (usb_hcd_is_primary_hcd(hcd)) + if (usb_hcd_is_primary_hcd(hcd)) { + kfree(hcd->address0_mutex); kfree(hcd->bandwidth_mutex); + } if (hcd->shared_hcd) { struct usb_hcd *peer = hcd->shared_hcd; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 38cc4bae0a82..bee13517676f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -104,6 +104,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev); static inline char *portspeed(struct usb_hub *hub, int portstatus) { + if (hub_is_superspeedplus(hub->hdev)) + return "10.0 Gb/s"; if (hub_is_superspeed(hub->hdev)) return "5.0 Gb/s"; if (portstatus & USB_PORT_STAT_HIGH_SPEED) @@ -2080,7 +2082,7 @@ static void choose_devnum(struct usb_device *udev) struct usb_bus *bus = udev->bus; /* be safe when more hub events are proceed in parallel */ - mutex_lock(&bus->usb_address0_mutex); + mutex_lock(&bus->devnum_next_mutex); if (udev->wusb) { devnum = udev->portnum + 1; BUG_ON(test_bit(devnum, bus->devmap.devicemap)); @@ -2098,7 +2100,7 @@ static void choose_devnum(struct usb_device *udev) set_bit(devnum, bus->devmap.devicemap); udev->devnum = devnum; } - mutex_unlock(&bus->usb_address0_mutex); + mutex_unlock(&bus->devnum_next_mutex); } static void release_devnum(struct usb_device *udev) @@ -4364,7 +4366,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; - mutex_lock(&hdev->bus->usb_address0_mutex); + mutex_lock(hcd->address0_mutex); /* Reset the device; full speed may morph to high speed */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ @@ -4650,7 +4652,7 @@ fail: hub_port_disable(hub, port1, 0); update_devnum(udev, devnum); /* for disconnect processing */ } - mutex_unlock(&hdev->bus->usb_address0_mutex); + mutex_unlock(hcd->address0_mutex); return retval; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 8e641b5893ed..ea681f157368 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -302,9 +302,10 @@ static void sg_complete(struct urb *urb) */ spin_unlock(&io->lock); for (i = 0, found = 0; i < io->entries; i++) { - if (!io->urbs[i] || !io->urbs[i]->dev) + if (!io->urbs[i]) continue; if (found) { + usb_block_urb(io->urbs[i]); retval = usb_unlink_urb(io->urbs[i]); if (retval != -EINPROGRESS && retval != -ENODEV && @@ -515,12 +516,10 @@ void usb_sg_wait(struct usb_sg_request *io) int retval; io->urbs[i]->dev = io->dev; - retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC); - - /* after we submit, let completions or cancellations fire; - * we handshake using io->status. - */ spin_unlock_irq(&io->lock); + + retval = usb_submit_urb(io->urbs[i], GFP_NOIO); + switch (retval) { /* maybe we retrying will recover */ case -ENXIO: /* hc didn't queue this one */ @@ -578,31 +577,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait); void usb_sg_cancel(struct usb_sg_request *io) { unsigned long flags; + int i, retval; spin_lock_irqsave(&io->lock, flags); + if (io->status) { + spin_unlock_irqrestore(&io->lock, flags); + return; + } + /* shut everything down */ + io->status = -ECONNRESET; + spin_unlock_irqrestore(&io->lock, flags); - /* shut everything down, if it didn't already */ - if (!io->status) { - int i; - - io->status = -ECONNRESET; - spin_unlock(&io->lock); - for (i = 0; i < io->entries; i++) { - int retval; + for (i = io->entries - 1; i >= 0; --i) { + usb_block_urb(io->urbs[i]); - if (!io->urbs[i]->dev) - continue; - retval = usb_unlink_urb(io->urbs[i]); - if (retval != -EINPROGRESS - && retval != -ENODEV - && retval != -EBUSY - && retval != -EIDRM) - dev_warn(&io->dev->dev, "%s, unlink --> %d\n", - __func__, retval); - } - spin_lock(&io->lock); + retval = usb_unlink_urb(io->urbs[i]); + if (retval != -EINPROGRESS + && retval != -ENODEV + && retval != -EBUSY + && retval != -EIDRM) + dev_warn(&io->dev->dev, "%s, unlink --> %d\n", + __func__, retval); } - spin_unlock_irqrestore(&io->lock, flags); } EXPORT_SYMBOL_GPL(usb_sg_cancel); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 6dc810bce295..944a6dca0fcb 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* USB3503 */ + { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Microsoft Wireless Laser Mouse 6000 Receiver */ { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -173,6 +176,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* MAYA44USB sound device */ { USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, + /* ASUS Base Station(T100) */ + { USB_DEVICE(0x0b05, 0x17e0), .driver_info = + USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -188,26 +195,22 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1908, 0x1315), .driver_info = USB_QUIRK_HONOR_BNUMINTERFACES }, - /* INTEL VALUE SSD */ - { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* USB3503 */ - { USB_DEVICE(0x0424, 0x3503), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* ASUS Base Station(T100) */ - { USB_DEVICE(0x0b05, 0x17e0), .driver_info = - USB_QUIRK_IGNORE_REMOTE_WAKEUP }, - /* Protocol and OTG Electrical Test Device */ { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Acer C120 LED Projector */ + { USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM }, + /* Blackmagic Design Intensity Shuttle */ { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM }, /* Blackmagic Design UltraStudio SDI */ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, + /* INTEL VALUE SSD */ + { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + { } /* terminating entry must be last */ }; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 479187c32571..5e80697ef952 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -466,7 +466,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->route = 0; dev->dev.parent = bus->controller; - dev->dev.of_node = bus->controller->of_node; dev_set_name(&dev->dev, "usb%d", bus->busnum); root_hub = 1; } else { diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 3c58d633ce80..dec0b21fc626 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -64,6 +64,17 @@ DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \ dev_name(hsotg->dev), ##__VA_ARGS__) +#ifdef CONFIG_MIPS +/* + * There are some MIPS machines that can run in either big-endian + * or little-endian mode and that use the dwc2 register without + * a byteswap in both ways. + * Unlike other architectures, MIPS apparently does not require a + * barrier before the __raw_writel() to synchronize with DMA but does + * require the barrier after the __raw_writel() to serialize a set of + * writes. This set of operations was added specifically for MIPS and + * should only be used there. + */ static inline u32 dwc2_readl(const void __iomem *addr) { u32 value = __raw_readl(addr); @@ -90,6 +101,22 @@ static inline void dwc2_writel(u32 value, void __iomem *addr) pr_info("INFO:: wrote %08x to %p\n", value, addr); #endif } +#else +/* Normal architectures just use readl/write */ +static inline u32 dwc2_readl(const void __iomem *addr) +{ + return readl(addr); +} + +static inline void dwc2_writel(u32 value, void __iomem *addr) +{ + writel(value, addr); + +#ifdef DWC2_LOG_WRITES + pr_info("info:: wrote %08x to %p\n", value, addr); +#endif +} +#endif /* Maximum number of Endpoints/HostChannels */ #define MAX_EPS_CHANNELS 16 diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 818f158232bb..26cf09d0fe3c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -1018,7 +1018,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, return 1; } -static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value); +static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); /** * get_ep_head - return the first request on the endpoint @@ -1094,7 +1094,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, case USB_ENDPOINT_HALT: halted = ep->halted; - dwc2_hsotg_ep_sethalt(&ep->ep, set); + dwc2_hsotg_ep_sethalt(&ep->ep, set, true); ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); if (ret) { @@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) u32 gintsts; u32 gintmsk; + if (!dwc2_is_device_mode(hsotg)) + return IRQ_NONE; + spin_lock(&hsotg->lock); irq_retry: gintsts = dwc2_readl(hsotg->regs + GINTSTS); @@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, desc->wMaxPacketSize, desc->bInterval); /* not to be called for EP0 */ - WARN_ON(index == 0); + if (index == 0) { + dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); + return -EINVAL; + } dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; if (dir_in != hs_ep->dir_in) { @@ -2942,8 +2948,13 @@ static int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) * dwc2_hsotg_ep_sethalt - set halt on a given endpoint * @ep: The endpoint to set halt. * @value: Set or unset the halt. + * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if + * the endpoint is busy processing requests. + * + * We need to stall the endpoint immediately if request comes from set_feature + * protocol command handler. */ -static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) +static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hs = hs_ep->parent; @@ -2963,6 +2974,17 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value) return 0; } + if (hs_ep->isochronous) { + dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); + return -EINVAL; + } + + if (!now && value && !list_empty(&hs_ep->queue)) { + dev_dbg(hs->dev, "%s request is pending, cannot halt\n", + ep->name); + return -EAGAIN; + } + if (hs_ep->dir_in) { epreg = DIEPCTL(index); epctl = dwc2_readl(hs->regs + epreg); @@ -3014,7 +3036,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) int ret = 0; spin_lock_irqsave(&hs->lock, flags); - ret = dwc2_hsotg_ep_sethalt(ep, value); + ret = dwc2_hsotg_ep_sethalt(ep, value, false); spin_unlock_irqrestore(&hs->lock, flags); return ret; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1f6255131857..2df3d04d26f5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4703,6 +4703,7 @@ fail2: spin_unlock_irqrestore(&hsotg->lock, flags); urb->hcpriv = NULL; kfree(qtd); + qtd = NULL; fail1: if (qh_allocated) { struct dwc2_qtd *qtd2, *qtd2_tmp; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 89fa26cb25f4..7758bfb644ff 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, { list_del(&qtd->qtd_list_entry); kfree(qtd); + qtd = NULL; } /* Descriptor DMA support functions */ diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 7f634fd771c7..b5c7793a2df2 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) dwc2_deschedule_periodic(hsotg, qh); hsotg->periodic_qh_count--; - if (!hsotg->periodic_qh_count) { + if (!hsotg->periodic_qh_count && + hsotg->core_params->dma_desc_enable <= 0) { intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask &= ~GINTSTS_SOF; dwc2_writel(intr_mask, hsotg->regs + GINTMSK); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 88629bed6614..fc6f5251de5d 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev) retval = dwc2_get_dr_mode(hsotg); if (retval) - return retval; + goto error; /* * Reset before dwc2_get_hwparams() then it could get power-on real diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 34277ced26bd..a590cd225bb7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) dwc3_writel(dwc->regs, DWC3_GCTL, reg); } +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) +{ + struct dwc3 *dwc = dep->dwc; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, + DWC3_GDBGFIFOSPACE_NUM(dep->number) | + DWC3_GDBGFIFOSPACE_TYPE(type)); + + reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); + + return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); +} + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure @@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, static void dwc3_free_event_buffers(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int i; - for (i = 0; i < dwc->num_event_buffers; i++) { - evt = dwc->ev_buffs[i]; - if (evt) - dwc3_free_one_event_buffer(dwc, evt); - } + evt = dwc->ev_buf; + if (evt) + dwc3_free_one_event_buffer(dwc, evt); } /** @@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) */ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) { - int num; - int i; - - num = DWC3_NUM_INT(dwc->hwparams.hwparams1); - dwc->num_event_buffers = num; - - dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, - GFP_KERNEL); - if (!dwc->ev_buffs) - return -ENOMEM; - - for (i = 0; i < num; i++) { - struct dwc3_event_buffer *evt; + struct dwc3_event_buffer *evt; - evt = dwc3_alloc_one_event_buffer(dwc, length); - if (IS_ERR(evt)) { - dev_err(dwc->dev, "can't allocate event buffer\n"); - return PTR_ERR(evt); - } - dwc->ev_buffs[i] = evt; + evt = dwc3_alloc_one_event_buffer(dwc, length); + if (IS_ERR(evt)) { + dev_err(dwc->dev, "can't allocate event buffer\n"); + return PTR_ERR(evt); } + dwc->ev_buf = evt; return 0; } @@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) static int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int n; - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; - dwc3_trace(trace_dwc3_core, - "Event buf %p dma %08llx length %d\n", - evt->buf, (unsigned long long) evt->dma, - evt->length); - - evt->lpos = 0; - - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), - lower_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), - upper_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), - DWC3_GEVNTSIZ_SIZE(evt->length)); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } + evt = dwc->ev_buf; + dwc3_trace(trace_dwc3_core, + "Event buf %p dma %08llx length %d\n", + evt->buf, (unsigned long long) evt->dma, + evt->length); + + evt->lpos = 0; + + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), + lower_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), + upper_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_SIZE(evt->length)); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); return 0; } @@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int n; - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; + evt = dwc->ev_buf; - evt->lpos = 0; + evt->lpos = 0; - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK - | DWC3_GEVNTSIZ_SIZE(0)); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK + | DWC3_GEVNTSIZ_SIZE(0)); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) @@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + if (dwc->dis_rxdet_inp3_quirk) + reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3; + if (dwc->req_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; @@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); - dwc->needs_fifo_resize = device_property_read_bool(dev, - "tx-fifo-resize"); - dwc->disable_scramble_quirk = device_property_read_bool(dev, "snps,disable_scramble_quirk"); dwc->u2exit_lfps_quirk = device_property_read_bool(dev, @@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_u2_susphy_quirk"); dwc->dis_enblslpm_quirk = device_property_read_bool(dev, "snps,dis_enblslpm_quirk"); + dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, + "snps,dis_rxdet_inp3_quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); @@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev) if (pdata->hird_threshold) hird_threshold = pdata->hird_threshold; - dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; dwc->dr_mode = pdata->dr_mode; @@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk; + dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) @@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto err5; - ret = dwc3_debugfs_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize debugfs\n"); - goto err6; - } - + dwc3_debugfs_init(dwc); pm_runtime_allow(dev); return 0; -err6: - dwc3_core_exit_mode(dwc); - err5: dwc3_event_buffers_cleanup(dwc); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6254b2ff9080..654050684f4f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -152,6 +152,24 @@ /* Bit fields */ +/* Global Debug Queue/FIFO Space Available Register */ +#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) +#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) +#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) + +#define DWC3_TXFIFOQ 1 +#define DWC3_RXFIFOQ 3 +#define DWC3_TXREQQ 5 +#define DWC3_RXREQQ 7 +#define DWC3_RXINFOQ 9 +#define DWC3_DESCFETCHQ 13 +#define DWC3_EVENTQ 15 + +/* Global RX Threshold Configuration Register */ +#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) +#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24) +#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29) + /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_U2RSTECN (1 << 16) @@ -193,6 +211,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) +#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) @@ -257,6 +276,9 @@ #define DWC3_DCFG_LOWSPEED (2 << 0) #define DWC3_DCFG_FULLSPEED1 (3 << 0) +#define DWC3_DCFG_NUMP_SHIFT 17 +#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f) +#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT) #define DWC3_DCFG_LPM_CAP (1 << 22) /* Device Control Register */ @@ -380,6 +402,7 @@ #define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) #define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F) #define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) +#define DWC3_DEPCMD_CLEARPENDIN (1 << 11) #define DWC3_DEPCMD_CMDACT (1 << 10) #define DWC3_DEPCMD_CMDIOC (1 << 8) @@ -438,18 +461,17 @@ struct dwc3_event_buffer { #define DWC3_EP_DIRECTION_TX true #define DWC3_EP_DIRECTION_RX false -#define DWC3_TRB_NUM 32 -#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1) +#define DWC3_TRB_NUM 256 /** * struct dwc3_ep - device side endpoint representation * @endpoint: usb endpoint - * @request_list: list of requests for this endpoint - * @req_queued: list of requests on this ep which have TRBs setup + * @pending_list: list of pending requests for this endpoint + * @started_list: list of started requests on this endpoint * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool - * @free_slot: next slot which is going to be used - * @busy_slot: first slot which is owned by HW + * @trb_enqueue: enqueue 'pointer' into TRB array + * @trb_dequeue: dequeue 'pointer' into TRB array * @desc: usb_endpoint_descriptor pointer * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation @@ -464,13 +486,11 @@ struct dwc3_event_buffer { */ struct dwc3_ep { struct usb_ep endpoint; - struct list_head request_list; - struct list_head req_queued; + struct list_head pending_list; + struct list_head started_list; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; - u32 free_slot; - u32 busy_slot; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; @@ -486,6 +506,18 @@ struct dwc3_ep { /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN (1 << 31) + /* + * IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will + * use a u8 type here. If anybody decides to increase number of TRBs to + * anything larger than 256 - I can't see why people would want to do + * this though - then this type needs to be changed. + * + * By using u8 types we ensure that our % operator when incrementing + * enqueue and dequeue get optimized away by the compiler. + */ + u8 trb_enqueue; + u8 trb_dequeue; + u8 number; u8 type; u8 resource_index; @@ -557,6 +589,7 @@ enum dwc3_link_state { #define DWC3_TRB_CTRL_IOC (1 << 11) #define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) +#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4)) #define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) #define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2) #define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3) @@ -623,19 +656,32 @@ struct dwc3_hwparams { /* HWPARAMS7 */ #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) +/** + * struct dwc3_request - representation of a transfer request + * @request: struct usb_request to be transferred + * @list: a list_head used for request queueing + * @dep: struct dwc3_ep owning this request + * @first_trb_index: index to first trb used by this request + * @epnum: endpoint number to which this request refers + * @trb: pointer to struct dwc3_trb + * @trb_dma: DMA address of @trb + * @direction: IN or OUT direction flag + * @mapped: true when request has been dma-mapped + * @queued: true when request has been queued to HW + */ struct dwc3_request { struct usb_request request; struct list_head list; struct dwc3_ep *dep; - u32 start_slot; + u8 first_trb_index; u8 epnum; struct dwc3_trb *trb; dma_addr_t trb_dma; unsigned direction:1; unsigned mapped:1; - unsigned queued:1; + unsigned started:1; }; /* @@ -667,7 +713,6 @@ struct dwc3_scratchpad_array { * @regs: base address for our registers * @regs_size: address space size * @nr_scratch: number of scratch buffers - * @num_event_buffers: calculated number of event buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents @@ -709,9 +754,7 @@ struct dwc3_scratchpad_array { * 0 - utmi_sleep_n * 1 - utmi_l1_suspend_n * @is_fpga: true when we are using the FPGA board - * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup @@ -756,7 +799,7 @@ struct dwc3 { struct platform_device *xhci; struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; - struct dwc3_event_buffer **ev_buffs; + struct dwc3_event_buffer *ev_buf; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct usb_gadget gadget; @@ -780,7 +823,6 @@ struct dwc3 { u32 gctl; u32 nr_scratch; - u32 num_event_buffers; u32 u1u2; u32 maximum_speed; @@ -855,9 +897,7 @@ struct dwc3 { unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; - unsigned needs_fifo_resize:1; unsigned pullups_connected:1; - unsigned resize_fifos:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; unsigned usb3_lpm_capable:1; @@ -873,6 +913,7 @@ struct dwc3 { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_rxdet_inp3_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; @@ -938,6 +979,10 @@ struct dwc3_event_depevt { #define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_STATUS 2 +/* In response to Start Transfer */ +#define DEPEVT_TRANSFER_NO_RESOURCE 1 +#define DEPEVT_TRANSFER_BUS_EXPIRY 2 + u32 parameters:16; } __packed; @@ -1025,7 +1070,7 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); /* check whether we are on the DWC_usb31 core */ static inline bool dwc3_is_usb31(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 07fbc2d94fd4..71e318025964 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS -extern int dwc3_debugfs_init(struct dwc3 *); +extern void dwc3_debugfs_init(struct dwc3 *); extern void dwc3_debugfs_exit(struct dwc3 *); #else -static inline int dwc3_debugfs_init(struct dwc3 *d) -{ return 0; } +static inline void dwc3_debugfs_init(struct dwc3 *d) +{ } static inline void dwc3_debugfs_exit(struct dwc3 *d) { } #endif diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index cebf9e38b60a..b1dd3c6d7ef7 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = { .release = single_release, }; -int dwc3_debugfs_init(struct dwc3 *dwc) +struct dwc3_ep_file_map { + char name[25]; + int (*show)(struct seq_file *s, void *unused); +}; + +static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_TXREQQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_event_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + if (!(dep->flags & DWC3_EP_ENABLED) || + !dep->endpoint.desc) { + seq_printf(s, "--\n"); + goto out; + } + + switch (usb_endpoint_type(dep->endpoint.desc)) { + case USB_ENDPOINT_XFER_CONTROL: + seq_printf(s, "control\n"); + break; + case USB_ENDPOINT_XFER_ISOC: + seq_printf(s, "isochronous\n"); + break; + case USB_ENDPOINT_XFER_BULK: + seq_printf(s, "bulk\n"); + break; + case USB_ENDPOINT_XFER_INT: + seq_printf(s, "interrupt\n"); + break; + default: + seq_printf(s, "--\n"); + } + +out: + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb) +{ + switch (DWC3_TRBCTL_TYPE(trb->ctrl)) { + case DWC3_TRBCTL_NORMAL: + return "normal"; + case DWC3_TRBCTL_CONTROL_SETUP: + return "control-setup"; + case DWC3_TRBCTL_CONTROL_STATUS2: + return "control-status2"; + case DWC3_TRBCTL_CONTROL_STATUS3: + return "control-status3"; + case DWC3_TRBCTL_CONTROL_DATA: + return "control-data"; + case DWC3_TRBCTL_ISOCHRONOUS_FIRST: + return "isoc-first"; + case DWC3_TRBCTL_ISOCHRONOUS: + return "isoc"; + case DWC3_TRBCTL_LINK_TRB: + return "link"; + default: + return "UNKNOWN"; + } +} + +static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + int i; + + spin_lock_irqsave(&dwc->lock, flags); + if (dep->number <= 1) { + seq_printf(s, "--\n"); + goto out; + } + + seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue); + seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue); + seq_printf(s, "\n--------------------------------------------------\n\n"); + seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n"); + + for (i = 0; i < DWC3_TRB_NUM; i++) { + struct dwc3_trb *trb = &dep->trb_pool[i]; + + seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n", + trb->bph, trb->bpl, trb->size, + dwc3_trb_type_string(trb), + !!(trb->ctrl & DWC3_TRB_CTRL_IOC), + !!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI), + !!(trb->ctrl & DWC3_TRB_CTRL_CSP), + !!(trb->ctrl & DWC3_TRB_CTRL_CHN), + !!(trb->ctrl & DWC3_TRB_CTRL_LST), + !!(trb->ctrl & DWC3_TRB_CTRL_HWO)); + } + +out: + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static struct dwc3_ep_file_map map[] = { + { "tx_fifo_queue", dwc3_tx_fifo_queue_show, }, + { "rx_fifo_queue", dwc3_rx_fifo_queue_show, }, + { "tx_request_queue", dwc3_tx_request_queue_show, }, + { "rx_request_queue", dwc3_rx_request_queue_show, }, + { "rx_info_queue", dwc3_rx_info_queue_show, }, + { "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, }, + { "event_queue", dwc3_event_queue_show, }, + { "transfer_type", dwc3_ep_transfer_type_show, }, + { "trb_ring", dwc3_ep_trb_ring_show, }, +}; + +static int dwc3_endpoint_open(struct inode *inode, struct file *file) +{ + const char *file_name = file_dentry(file)->d_iname; + struct dwc3_ep_file_map *f_map; + int i; + + for (i = 0; i < ARRAY_SIZE(map); i++) { + f_map = &map[i]; + + if (strcmp(f_map->name, file_name) == 0) + break; + } + + return single_open(file, f_map->show, inode->i_private); +} + +static const struct file_operations dwc3_endpoint_fops = { + .open = dwc3_endpoint_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep, + struct dentry *parent, int type) { - struct dentry *root; struct dentry *file; - int ret; + struct dwc3_ep_file_map *ep_file = &map[type]; - root = debugfs_create_dir(dev_name(dwc->dev), NULL); - if (!root) { - ret = -ENOMEM; - goto err0; + file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep, + &dwc3_endpoint_fops); +} + +static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep, + struct dentry *parent) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(map); i++) + dwc3_debugfs_create_endpoint_file(dep, parent, i); +} + +static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep, + struct dentry *parent) +{ + struct dentry *dir; + + dir = debugfs_create_dir(dep->name, parent); + if (IS_ERR_OR_NULL(dir)) + return; + + dwc3_debugfs_create_endpoint_files(dep, dir); +} + +static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc, + struct dentry *parent) +{ + int i; + + for (i = 0; i < dwc->num_in_eps; i++) { + u8 epnum = (i << 1) | 1; + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!dep) + continue; + + dwc3_debugfs_create_endpoint_dir(dep, parent); + } + + for (i = 0; i < dwc->num_out_eps; i++) { + u8 epnum = (i << 1); + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!dep) + continue; + + dwc3_debugfs_create_endpoint_dir(dep, parent); } +} + +void dwc3_debugfs_init(struct dwc3 *dwc) +{ + struct dentry *root; + struct dentry *file; + root = debugfs_create_dir(dev_name(dwc->dev), NULL); + if (IS_ERR_OR_NULL(root)) { + if (!root) + dev_err(dwc->dev, "Can't create debugfs root\n"); + return; + } dwc->root = root; dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL); if (!dwc->regset) { - ret = -ENOMEM; - goto err1; + debugfs_remove_recursive(root); + return; } dwc->regset->regs = dwc3_regs; @@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->base = dwc->regs; file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); - if (!file) { - ret = -ENOMEM; - goto err2; - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs regdump\n"); if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) { file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_mode_fops); - if (!file) { - ret = -ENOMEM; - goto err2; - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs mode\n"); } if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) || IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_testmode_fops); - if (!file) { - ret = -ENOMEM; - goto err2; - } - - file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_link_state_fops); - if (!file) { - ret = -ENOMEM; - goto err2; - } - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs testmode\n"); - return 0; + file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, + root, dwc, &dwc3_link_state_fops); + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs link_state\n"); -err2: - kfree(dwc->regset); - -err1: - debugfs_remove_recursive(root); - -err0: - return ret; + dwc3_debugfs_create_endpoint_dirs(dwc, root); + } } void dwc3_debugfs_exit(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index dd5cb5577dca..2f1fb7e7aa54 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -128,12 +128,6 @@ static int dwc3_exynos_probe(struct platform_device *pdev) platform_set_drvdata(pdev, exynos); - ret = dwc3_exynos_register_phys(exynos); - if (ret) { - dev_err(dev, "couldn't register PHYs\n"); - return ret; - } - exynos->dev = dev; exynos->clk = devm_clk_get(dev, "usbdrd30"); @@ -183,20 +177,29 @@ static int dwc3_exynos_probe(struct platform_device *pdev) goto err3; } + ret = dwc3_exynos_register_phys(exynos); + if (ret) { + dev_err(dev, "couldn't register PHYs\n"); + goto err4; + } + if (node) { ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(dev, "failed to add dwc3 core\n"); - goto err4; + goto err5; } } else { dev_err(dev, "no device node, failed to add dwc3 core\n"); ret = -ENODEV; - goto err4; + goto err5; } return 0; +err5: + platform_device_unregister(exynos->usb2_phy); + platform_device_unregister(exynos->usb3_phy); err4: regulator_disable(exynos->vdd10); err3: diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 55da2c7f727f..af264493bbae 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -126,8 +126,6 @@ struct dwc3_omap { u32 debug_offset; u32 irq0_offset; - u32 dma_status:1; - struct extcon_dev *edev; struct notifier_block vbus_nb; struct notifier_block id_nb; @@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) reg = dwc3_omap_read_irqmisc_status(omap); - if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) - omap->dma_status = false; - dwc3_omap_write_irqmisc_status(omap, reg); reg = dwc3_omap_read_irq0_status(omap); @@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) dwc3_omap_write_irqmisc_clr(omap, reg); } -static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); - static int dwc3_omap_id_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { @@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) omap->irq = irq; omap->base = base; omap->vbus_reg = vbus_reg; - dev->dma_mask = &dwc3_omap_dma_mask; pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); @@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) /* check the DMA Status */ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); - omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, "dwc3-omap", omap); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index adc1e8a624cb..14196cd416b3 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = { { }, }; -static int dwc3_pci_quirks(struct pci_dev *pdev) +static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3) { if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { @@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) pdata.dis_u3_susphy_quirk = true; pdata.dis_u2_susphy_quirk = true; - return platform_device_add_data(pci_get_drvdata(pdev), &pdata, - sizeof(pdata)); + return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); } if (pdev->vendor == PCI_VENDOR_ID_INTEL && @@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) pdata.has_lpm_erratum = true; pdata.dis_enblslpm_quirk = true; - return platform_device_add_data(pci_get_drvdata(pdev), &pdata, - sizeof(pdata)); + return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); } return 0; @@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci, return ret; } - pci_set_drvdata(pci, dwc3); - ret = dwc3_pci_quirks(pci); - if (ret) - goto err; - dwc3->dev.parent = dev; ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev)); + ret = dwc3_pci_quirks(pci, dwc3); + if (ret) + goto err; + ret = platform_device_add(dwc3); if (ret) { dev_err(dev, "failed to register dwc3 device\n"); goto err; } + pci_set_drvdata(pci, dwc3); return 0; err: platform_device_put(dwc3); diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 5c0adb9c6fb2..50d6ae6f88bc 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -129,12 +129,18 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) switch (dwc3_data->dr_mode) { case USB_DR_MODE_PERIPHERAL: - val &= ~(USB3_FORCE_VBUSVALID | USB3_DELAY_VBUSVALID + val &= ~(USB3_DELAY_VBUSVALID | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); - val |= USB3_DEVICE_NOT_HOST; + /* + * USB3_PORT2_FORCE_VBUSVALID When '1' and when + * USB3_PORT2_DEVICE_NOT_HOST = 1, forces VBUSVLDEXT2 input + * of the pico PHY to 1. + */ + + val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID; break; case USB_DR_MODE_HOST: diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index eca2e6d8e041..51b52a79dfec 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, return 0; } - trb = &dwc->ep0_trb[dep->free_slot]; + trb = &dwc->ep0_trb[dep->trb_enqueue]; if (chain) - dep->free_slot++; + dep->trb_enqueue++; trb->bpl = lower_32_bits(buf_dma); trb->bph = upper_32_bits(buf_dma); @@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, req->request.status = -EINPROGRESS; req->epnum = dep->number; - list_add_tail(&req->list, &dep->request_list); + list_add_tail(&req->list, &dep->pending_list); /* * Gadget driver might not be quick enough to queue a request @@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, } /* we share one TRB for ep0/1 */ - if (!list_empty(&dep->request_list)) { + if (!list_empty(&dep->pending_list)) { ret = -EBUSY; goto out; } @@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; - if (!list_empty(&dep->request_list)) { + if (!list_empty(&dep->pending_list)) { struct dwc3_request *req; - req = next_request(&dep->request_list); + req = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, req, -ECONNRESET); } @@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (!set) return -EINVAL; - dwc->test_mode_nr = wIndex >> 8; - dwc->test_mode = true; + switch (wIndex >> 8) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + dwc->test_mode_nr = wIndex >> 8; + dwc->test_mode = true; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - dwc->resize_fifos = true; - dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET"); } break; @@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trace_dwc3_complete_trb(ep0, trb); - r = next_request(&ep0->request_list); + r = next_request(&ep0->pending_list); if (!r) return; @@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trb++; length = trb->size & DWC3_TRB_SIZE_MASK; - ep0->free_slot = 0; + ep0->trb_enqueue = 0; } transfer_size = roundup((ur->length - transfer_size), @@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, trace_dwc3_complete_trb(dep, trb); - if (!list_empty(&dep->request_list)) { - r = next_request(&dep->request_list); + if (!list_empty(&dep->pending_list)) { + r = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, r, 0); } @@ -1027,12 +1034,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { - if (dwc->resize_fifos) { - dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs"); - dwc3_gadget_resize_tx_fifos(dwc); - dwc->resize_fifos = 0; - } - WARN_ON(dwc3_ep0_start_control_status(dep)); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8e4a1b195e9b..07248ff1be5c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -145,90 +145,21 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } -/** - * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case - * @dwc: pointer to our context structure - * - * This function will a best effort FIFO allocation in order - * to improve FIFO usage and throughput, while still allowing - * us to enable as many endpoints as possible. - * - * Keep in mind that this operation will be highly dependent - * on the configured size for RAM1 - which contains TxFifo -, - * the amount of endpoints enabled on coreConsultant tool, and - * the width of the Master Bus. - * - * In the ideal world, we would always be able to satisfy the - * following equation: - * - * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \ - * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes - * - * Unfortunately, due to many variables that's not always the case. - */ -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) +static void dwc3_ep_inc_enq(struct dwc3_ep *dep) { - int last_fifo_depth = 0; - int ram1_depth; - int fifo_size; - int mdwidth; - int num; - - if (!dwc->needs_fifo_resize) - return 0; - - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - - /* MDWIDTH is represented in bits, we need it in bytes */ - mdwidth >>= 3; - - /* - * FIXME For now we will only allocate 1 wMaxPacketSize space - * for each enabled endpoint, later patches will come to - * improve this algorithm so that we better use the internal - * FIFO space - */ - for (num = 0; num < dwc->num_in_eps; num++) { - /* bit0 indicates direction; 1 means IN ep */ - struct dwc3_ep *dep = dwc->eps[(num << 1) | 1]; - int mult = 1; - int tmp; - - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - if (usb_endpoint_xfer_bulk(dep->endpoint.desc) - || usb_endpoint_xfer_isoc(dep->endpoint.desc)) - mult = 3; - - /* - * REVISIT: the following assumes we will always have enough - * space available on the FIFO RAM for all possible use cases. - * Make sure that's true somehow and change FIFO allocation - * accordingly. - * - * If we have Bulk or Isochronous endpoints, we want - * them to be able to be very, very fast. So we're giving - * those endpoints a fifo_size which is enough for 3 full - * packets - */ - tmp = mult * (dep->endpoint.maxpacket + mdwidth); - tmp += mdwidth; - - fifo_size = DIV_ROUND_UP(tmp, mdwidth); - - fifo_size |= (last_fifo_depth << 16); - - dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d", - dep->name, last_fifo_depth, fifo_size & 0xffff); - - dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size); + dep->trb_enqueue++; + dep->trb_enqueue %= DWC3_TRB_NUM; +} - last_fifo_depth += (fifo_size & 0xffff); - } +static void dwc3_ep_inc_deq(struct dwc3_ep *dep) +{ + dep->trb_dequeue++; + dep->trb_dequeue %= DWC3_TRB_NUM; +} - return 0; +static int dwc3_ep_is_last_trb(unsigned int index) +{ + return index == DWC3_TRB_NUM - 1; } void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, @@ -237,21 +168,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3 *dwc = dep->dwc; int i; - if (req->queued) { + if (req->started) { i = 0; do { - dep->busy_slot++; + dwc3_ep_inc_deq(dep); /* * Skip LINK TRB. We can't use req->trb and check for * DWC3_TRBCTL_LINK_TRB because it points the TRB we * just completed (not the LINK TRB). */ - if (((dep->busy_slot & DWC3_TRB_MASK) == - DWC3_TRB_NUM- 1) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->busy_slot++; + if (dwc3_ep_is_last_trb(dep->trb_dequeue)) + dwc3_ep_inc_deq(dep); } while(++i < req->request.num_mapped_sgs); - req->queued = false; + req->started = false; } list_del(&req->list); req->trb = NULL; @@ -307,6 +236,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) } while (1); } +static int __dwc3_gadget_wakeup(struct dwc3 *dwc); + int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { @@ -314,8 +245,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, u32 timeout = 500; u32 reg; + int susphy = false; + int ret = -EINVAL; + trace_dwc3_gadget_ep_cmd(dep, cmd, params); + /* + * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if + * we're issuing an endpoint command, we must check if + * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it. + * + * We will also set SUSPHY bit to what it was before returning as stated + * by the same section on Synopsys databook. + */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { + susphy = true; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + + if (cmd == DWC3_DEPCMD_STARTTRANSFER) { + int needs_wakeup; + + needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || + dwc->link_state == DWC3_LINK_STATE_U2 || + dwc->link_state == DWC3_LINK_STATE_U3); + + if (unlikely(needs_wakeup)) { + ret = __dwc3_gadget_wakeup(dwc); + dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", + ret); + } + } + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); @@ -324,12 +287,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, do { reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); if (!(reg & DWC3_DEPCMD_CMDACT)) { + int cmd_status = DWC3_DEPCMD_STATUS(reg); + dwc3_trace(trace_dwc3_gadget, "Command Complete --> %d", - DWC3_DEPCMD_STATUS(reg)); - if (DWC3_DEPCMD_STATUS(reg)) - return -EINVAL; - return 0; + cmd_status); + + switch (cmd_status) { + case 0: + ret = 0; + break; + case DEPEVT_TRANSFER_NO_RESOURCE: + dwc3_trace(trace_dwc3_gadget, "%s: no resource available"); + ret = -EINVAL; + break; + case DEPEVT_TRANSFER_BUS_EXPIRY: + /* + * SW issues START TRANSFER command to + * isochronous ep with future frame interval. If + * future interval time has already passed when + * core receives the command, it will respond + * with an error status of 'Bus Expiry'. + * + * Instead of always returning -EINVAL, let's + * give a hint to the gadget driver that this is + * the case by returning -EAGAIN. + */ + dwc3_trace(trace_dwc3_gadget, "%s: bus expiry"); + ret = -EAGAIN; + break; + default: + dev_WARN(dwc->dev, "UNKNOWN cmd status\n"); + } + + break; } /* @@ -340,11 +331,42 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, if (!timeout) { dwc3_trace(trace_dwc3_gadget, "Command Timed Out"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + break; } udelay(1); } while (1); + + if (unlikely(susphy)) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + + return ret; +} + +static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) +{ + struct dwc3 *dwc = dep->dwc; + struct dwc3_gadget_ep_cmd_params params; + u32 cmd = DWC3_DEPCMD_CLEARSTALL; + + /* + * As of core revision 2.60a the recommended programming model + * is to set the ClearPendIN bit when issuing a Clear Stall EP + * command for IN endpoints. This is to prevent an issue where + * some (non-compliant) hosts may not send ACK TPs for pending + * IN transfers due to a mishandled error condition. Synopsys + * STAR 9000614252. + */ + if (dep->direction && (dwc->revision >= DWC3_REVISION_260A)) + cmd |= DWC3_DEPCMD_CLEARPENDIN; + + memset(¶ms, 0, sizeof(params)); + + return dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); } static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, @@ -464,9 +486,19 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, /* Burst size is only needed in SuperSpeed mode */ if (dwc->gadget.speed >= USB_SPEED_SUPER) { - u32 burst = dep->endpoint.maxburst - 1; + u32 burst = dep->endpoint.maxburst; + u32 nump; + u32 reg; + + /* update NumP */ + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + nump = DWC3_DCFG_NUMP(reg); + nump = max(nump, burst); + reg &= ~DWC3_DCFG_NUMP_MASK; + reg |= nump << DWC3_DCFG_NUMP_SHIFT; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); - params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1); } if (ignore) @@ -567,10 +599,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); - if (!usb_endpoint_xfer_isoc(desc)) + if (usb_endpoint_xfer_control(desc)) goto out; - /* Link TRB for ISOC. The HWO bit is never reset */ + /* Link TRB. The HWO bit is never reset */ trb_st_hw = &dep->trb_pool[0]; trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; @@ -608,19 +640,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - if (!list_empty(&dep->req_queued)) { + if (!list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); /* - giveback all requests to gadget driver */ - while (!list_empty(&dep->req_queued)) { - req = next_request(&dep->req_queued); + while (!list_empty(&dep->started_list)) { + req = next_request(&dep->started_list); dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } } - while (!list_empty(&dep->request_list)) { - req = next_request(&dep->request_list); + while (!list_empty(&dep->pending_list)) { + req = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } @@ -783,20 +815,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, chain ? " chain" : ""); - trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; + trb = &dep->trb_pool[dep->trb_enqueue]; if (!req->trb) { - dwc3_gadget_move_request_queued(req); + dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); - req->start_slot = dep->free_slot & DWC3_TRB_MASK; + req->first_trb_index = dep->trb_enqueue; } - dep->free_slot++; - /* Skip the LINK-TRB on ISOC */ - if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->free_slot++; + dwc3_ep_inc_enq(dep); + /* Skip the LINK-TRB */ + if (dwc3_ep_is_last_trb(dep->trb_enqueue)) + dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); trb->bpl = lower_32_bits(dma); @@ -812,6 +843,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; else trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; + + /* always enable Interrupt on Missed ISOC */ + trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; break; case USB_ENDPOINT_XFER_BULK: @@ -826,15 +860,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, BUG(); } + /* always enable Continue on Short Packet */ + trb->ctrl |= DWC3_TRB_CTRL_CSP; + if (!req->request.no_interrupt && !chain) - trb->ctrl |= DWC3_TRB_CTRL_IOC; + trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; - trb->ctrl |= DWC3_TRB_CTRL_CSP; - } else if (last) { + if (last) trb->ctrl |= DWC3_TRB_CTRL_LST; - } if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; @@ -860,55 +893,29 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) { struct dwc3_request *req, *n; u32 trbs_left; - u32 max; unsigned int last_one = 0; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - /* the first request must not be queued */ - trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; - - /* Can't wrap around on a non-isoc EP since there's no link TRB */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); - if (trbs_left > max) - trbs_left = max; - } + trbs_left = dep->trb_dequeue - dep->trb_enqueue; /* - * If busy & slot are equal than it is either full or empty. If we are - * starting to process requests then we are empty. Otherwise we are + * If enqueue & dequeue are equal than it is either full or empty. If we + * are starting to process requests then we are empty. Otherwise we are * full and don't do anything */ if (!trbs_left) { if (!starting) return; + trbs_left = DWC3_TRB_NUM; - /* - * In case we start from scratch, we queue the ISOC requests - * starting from slot 1. This is done because we use ring - * buffer and have no LST bit to stop us. Instead, we place - * IOC bit every TRB_NUM/4. We try to avoid having an interrupt - * after the first request so we start at slot 1 and have - * 7 requests proceed before we hit the first IOC. - * Other transfer types don't use the ring buffer and are - * processed from the first TRB until the last one. Since we - * don't wrap around we have to start at the beginning. - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - dep->busy_slot = 1; - dep->free_slot = 1; - } else { - dep->busy_slot = 0; - dep->free_slot = 0; - } } /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if (trbs_left <= 1) return; - list_for_each_entry_safe(req, n, &dep->request_list, list) { + list_for_each_entry_safe(req, n, &dep->pending_list, list) { unsigned length; dma_addr_t dma; last_one = false; @@ -927,7 +934,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) if (i == (request->num_mapped_sgs - 1) || sg_is_last(s)) { - if (list_empty(&dep->request_list)) + if (list_empty(&dep->pending_list)) last_one = true; chain = false; } @@ -957,7 +964,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) last_one = 1; /* Is this the last request? */ - if (list_is_last(&req->list, &dep->request_list)) + if (list_is_last(&req->list, &dep->pending_list)) last_one = 1; dwc3_prepare_one_trb(dep, req, dma, length, @@ -988,18 +995,18 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, * new requests as we try to set the IOC bit only on the last request. */ if (start_new) { - if (list_empty(&dep->req_queued)) + if (list_empty(&dep->started_list)) dwc3_prepare_trbs(dep, start_new); /* req points to the first request which will be sent */ - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); } else { dwc3_prepare_trbs(dep, start_new); /* * req points to the first request where HWO changed from 0 to 1 */ - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); } if (!req) { dep->flags |= DWC3_EP_PENDING_REQUEST; @@ -1046,7 +1053,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, { u32 uf; - if (list_empty(&dep->request_list)) { + if (list_empty(&dep->pending_list)) { dwc3_trace(trace_dwc3_gadget, "ISOC ep %s run out for requests", dep->name); @@ -1114,7 +1121,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (ret) return ret; - list_add_tail(&req->list, &dep->request_list); + list_add_tail(&req->list, &dep->pending_list); /* * If there are no pending requests and the endpoint isn't already @@ -1149,7 +1156,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * notion of current microframe. */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (list_empty(&dep->req_queued)) { + if (list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); dep->flags = DWC3_EP_ENABLED; } @@ -1267,13 +1274,13 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, spin_lock_irqsave(&dwc->lock, flags); - list_for_each_entry(r, &dep->request_list, list) { + list_for_each_entry(r, &dep->pending_list, list) { if (r == req) break; } if (r != req) { - list_for_each_entry(r, &dep->req_queued, list) { + list_for_each_entry(r, &dep->started_list, list) { if (r == req) break; } @@ -1313,10 +1320,10 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) if (value) { if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || - (!list_empty(&dep->req_queued) || - !list_empty(&dep->request_list)))) { + (!list_empty(&dep->started_list) || + !list_empty(&dep->pending_list)))) { dwc3_trace(trace_dwc3_gadget, - "%s: pending request, cannot halt\n", + "%s: pending request, cannot halt", dep->name); return -EAGAIN; } @@ -1329,8 +1336,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) else dep->flags |= DWC3_EP_STALL; } else { - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_CLEARSTALL, ¶ms); + ret = dwc3_send_clear_stall_ep_cmd(dep); if (ret) dev_err(dwc->dev, "failed to clear STALL on %s\n", dep->name); @@ -1417,22 +1423,16 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return DWC3_DSTS_SOFFN(reg); } -static int dwc3_gadget_wakeup(struct usb_gadget *g) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long timeout; - unsigned long flags; + int ret; u32 reg; - int ret = 0; - u8 link_state; u8 speed; - spin_lock_irqsave(&dwc->lock, flags); - /* * According to the Databook Remote wakeup request should * be issued only when the device is in early suspend state. @@ -1445,8 +1445,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if ((speed == DWC3_DSTS_SUPERSPEED) || (speed == DWC3_DSTS_SUPERSPEED_PLUS)) { dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } link_state = DWC3_DSTS_USBLNKST(reg); @@ -1459,14 +1458,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) dwc3_trace(trace_dwc3_gadget, "can't wakeup from '%s'\n", dwc3_gadget_link_string(link_state)); - ret = -EINVAL; - goto out; + return -EINVAL; } ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); - goto out; + return ret; } /* Recent versions do this automatically */ @@ -1490,10 +1488,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); - ret = -EINVAL; + return -EINVAL; } -out: + return 0; +} + +static int dwc3_gadget_wakeup(struct usb_gadget *g) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; + + spin_lock_irqsave(&dwc->lock, flags); + ret = __dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1620,7 +1628,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, irq = platform_get_irq(to_platform_device(dwc->dev), 0); ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED, "dwc3", dwc); + IRQF_SHARED, "dwc3", dwc->ev_buf); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); @@ -1682,6 +1690,17 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc3_writel(dwc->regs, DWC3_DCFG, reg); + /* + * We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP + * field instead of letting dwc3 itself calculate that automatically. + * + * This way, we maximize the chances that we'll be able to get several + * bursts of data without going through any sort of endpoint throttling. + */ + reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); + reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL; + dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); @@ -1720,7 +1739,7 @@ err2: err1: spin_unlock_irqrestore(&dwc->lock, flags); - free_irq(irq, dwc); + free_irq(irq, dwc->ev_buf); err0: return ret; @@ -1743,7 +1762,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_unlock_irqrestore(&dwc->lock, flags); irq = platform_get_irq(to_platform_device(dwc->dev), 0); - free_irq(irq, dwc); + free_irq(irq, dwc->ev_buf); return 0; } @@ -1815,8 +1834,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->endpoint.caps.dir_in = !!direction; dep->endpoint.caps.dir_out = !direction; - INIT_LIST_HEAD(&dep->request_list); - INIT_LIST_HEAD(&dep->req_queued); + INIT_LIST_HEAD(&dep->pending_list); + INIT_LIST_HEAD(&dep->started_list); } return 0; @@ -1913,11 +1932,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, * If there are still queued request * then wait, do not issue either END * or UPDATE TRANSFER, just attach next - * request in request_list during + * request in pending_list during * giveback.If any future queued request * is successfully transferred then we * will issue UPDATE TRANSFER for all - * request in the request_list. + * request in the pending_list. */ dep->flags |= DWC3_EP_MISSED_ISOC; } else { @@ -1963,15 +1982,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int ret; do { - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); if (WARN_ON_ONCE(!req)) return 1; i = 0; do { - slot = req->start_slot + i; - if ((slot == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) + slot = req->first_trb_index + i; + if (slot == DWC3_TRB_NUM - 1) slot++; slot %= DWC3_TRB_NUM; trb = &dep->trb_pool[slot]; @@ -1989,8 +2007,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, } while (1); if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - list_empty(&dep->req_queued)) { - if (list_empty(&dep->request_list)) { + list_empty(&dep->started_list)) { + if (list_empty(&dep->pending_list)) { /* * If there is no entry in request list then do * not issue END TRANSFER now. Just set PENDING @@ -2039,7 +2057,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, if (!(dep->flags & DWC3_EP_ENABLED)) continue; - if (!list_empty(&dep->req_queued)) + if (!list_empty(&dep->started_list)) return; } @@ -2250,7 +2268,6 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) { struct dwc3_ep *dep; - struct dwc3_gadget_ep_cmd_params params; int ret; dep = dwc->eps[epnum]; @@ -2262,9 +2279,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) dep->flags &= ~DWC3_EP_STALL; - memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_CLEARSTALL, ¶ms); + ret = dwc3_send_clear_stall_ep_cmd(dep); WARN_ON_ONCE(ret); } } @@ -2686,14 +2701,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) { - struct dwc3_event_buffer *evt; + struct dwc3 *dwc = evt->dwc; irqreturn_t ret = IRQ_NONE; int left; u32 reg; - evt = dwc->ev_buffs[buf]; left = evt->count; if (!(evt->flags & DWC3_EVENT_PENDING)) @@ -2718,7 +2732,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; left -= 4; - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4); } evt->count = 0; @@ -2726,39 +2740,34 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) ret = IRQ_HANDLED; /* Unmask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0)); reg &= ~DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); return ret; } -static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) +static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) { - struct dwc3 *dwc = _dwc; + struct dwc3_event_buffer *evt = _evt; + struct dwc3 *dwc = evt->dwc; unsigned long flags; irqreturn_t ret = IRQ_NONE; - int i; spin_lock_irqsave(&dwc->lock, flags); - - for (i = 0; i < dwc->num_event_buffers; i++) - ret |= dwc3_process_event_buf(dwc, i); - + ret = dwc3_process_event_buf(evt); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } -static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) { - struct dwc3_event_buffer *evt; + struct dwc3 *dwc = evt->dwc; u32 count; u32 reg; - evt = dwc->ev_buffs[buf]; - - count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) return IRQ_NONE; @@ -2767,28 +2776,18 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) evt->flags |= DWC3_EVENT_PENDING; /* Mask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0)); reg |= DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); return IRQ_WAKE_THREAD; } -static irqreturn_t dwc3_interrupt(int irq, void *_dwc) +static irqreturn_t dwc3_interrupt(int irq, void *_evt) { - struct dwc3 *dwc = _dwc; - int i; - irqreturn_t ret = IRQ_NONE; + struct dwc3_event_buffer *evt = _evt; - for (i = 0; i < dwc->num_event_buffers; i++) { - irqreturn_t status; - - status = dwc3_check_event_buf(dwc, i); - if (status == IRQ_WAKE_THREAD) - ret = status; - } - - return ret; + return dwc3_check_event_buf(evt); } /** diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 18ae3eaa8b6f..f21c0fccbebd 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list) return list_first_entry(list, struct dwc3_request, list); } -static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req) +static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->queued = true; - list_move_tail(&req->list, &dep->req_queued); + req->started = true; + list_move_tail(&req->list, &dep->started_list); } void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 2bb4d3ad0e6b..8826cca5fc6f 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -23,7 +23,6 @@ struct dwc3_platform_data { enum usb_device_speed maximum_speed; enum usb_dr_mode dr_mode; - bool tx_fifo_resize; bool usb3_lpm_capable; unsigned is_utmi_l1_suspend:1; @@ -43,6 +42,7 @@ struct dwc3_platform_data { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_rxdet_inp3_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index af5d922a8f5d..2057add439f0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -15,6 +15,7 @@ menuconfig USB_GADGET tristate "USB Gadget Support" + select USB_COMMON select NLS help USB is a master/slave protocol, organized with one master diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 524e233d48de..eb648485a58c 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f, { struct usb_descriptor_header **descriptors; + /* + * NOTE: we try to help gadget drivers which might not be setting + * max_speed appropriately. + */ + switch (speed) { case USB_SPEED_SUPER_PLUS: descriptors = f->ssp_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_SUPER: descriptors = f->ss_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_HIGH: descriptors = f->hs_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ default: descriptors = f->fs_descriptors; } + /* + * if we can't find any descriptors at all, then this gadget deserves to + * Oops with a NULL pointer dereference + */ + return descriptors; } @@ -1852,14 +1868,19 @@ unknown: } break; } - req->length = value; - req->context = cdev; - req->zero = value < w_length; - value = composite_ep0_queue(cdev, req, GFP_ATOMIC); - if (value < 0) { - DBG(cdev, "ep_queue --> %d\n", value); - req->status = 0; - composite_setup_complete(gadget->ep0, req); + + if (value >= 0) { + req->length = value; + req->context = cdev; + req->zero = value < w_length; + value = composite_ep0_queue(cdev, req, + GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, + req); + } } return value; } diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index b6f60ca8a035..70cf3477f951 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1401,6 +1401,7 @@ static const struct usb_gadget_driver configfs_driver_template = { .owner = THIS_MODULE, .name = "configfs-gadget", }, + .match_existing_only = 1, }; static struct config_group *gadgets_make( diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 15b648cbc75c..cc33d2667408 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (iov_iter_count(&io_data->data)) + if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) ret = -EFAULT; unuse_mm(io_data->mm); } @@ -2051,7 +2051,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, if (len < sizeof(*d) || d->bFirstInterfaceNumber >= ffs->interfaces_count || - d->Reserved1) + !d->Reserved1) return -EINVAL; for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) if (d->Reserved2[i]) @@ -2729,6 +2729,7 @@ static int _ffs_func_bind(struct usb_configuration *c, func->ffs->ss_descs_count; int fs_len, hs_len, ss_len, ret, i; + struct ffs_ep *eps_ptr; /* Make it a single chunk, less management later on */ vla_group(d); @@ -2777,12 +2778,9 @@ static int _ffs_func_bind(struct usb_configuration *c, ffs->raw_descs_length); memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); - for (ret = ffs->eps_count; ret; --ret) { - struct ffs_ep *ptr; - - ptr = vla_ptr(vlabuf, d, eps); - ptr[ret].num = -1; - } + eps_ptr = vla_ptr(vlabuf, d, eps); + for (i = 0; i < ffs->eps_count; i++) + eps_ptr[i].num = -1; /* Save pointers * d_eps == vlabuf, func->eps used to kfree vlabuf later @@ -2851,7 +2849,7 @@ static int _ffs_func_bind(struct usb_configuration *c, goto error; func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table); - if (c->cdev->use_os_string) + if (c->cdev->use_os_string) { for (i = 0; i < ffs->interfaces_count; ++i) { struct usb_os_desc *desc; @@ -2862,13 +2860,15 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_ptr(vlabuf, d, ext_compat) + i * 16; INIT_LIST_HEAD(&desc->ext_prop); } - ret = ffs_do_os_descs(ffs->ms_os_descs_count, - vla_ptr(vlabuf, d, raw_descs) + - fs_len + hs_len + ss_len, - d_raw_descs__sz - fs_len - hs_len - ss_len, - __ffs_func_bind_do_os_desc, func); - if (unlikely(ret < 0)) - goto error; + ret = ffs_do_os_descs(ffs->ms_os_descs_count, + vla_ptr(vlabuf, d, raw_descs) + + fs_len + hs_len + ss_len, + d_raw_descs__sz - fs_len - hs_len - + ss_len, + __ffs_func_bind_do_os_desc, func); + if (unlikely(ret < 0)) + goto error; + } func->function.os_desc_n = c->cdev->use_os_string ? ffs->interfaces_count : 0; diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index acf210f16328..5c6d4d7ca605 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, } EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); -int fsg_common_run_thread(struct fsg_common *common) -{ - common->state = FSG_STATE_IDLE; - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); - if (IS_ERR(common->thread_task)) { - common->state = FSG_STATE_TERMINATED; - return PTR_ERR(common->thread_task); - } - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - - wake_up_process(common->thread_task); - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_run_thread); - static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); @@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref) if (common->state != FSG_STATE_TERMINATED) { raise_exception(common, FSG_STATE_EXIT); wait_for_completion(&common->thread_notifier); + common->thread_task = NULL; } for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { @@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (ret) return ret; fsg_common_set_inquiry_string(fsg->common, NULL, NULL); - ret = fsg_common_run_thread(fsg->common); - if (ret) + } + + if (!common->thread_task) { + common->state = FSG_STATE_IDLE; + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + int ret = PTR_ERR(common->thread_task); + common->thread_task = NULL; + common->state = FSG_STATE_TERMINATED; return ret; + } + DBG(common, "I/O thread pid: %d\n", + task_pid_nr(common->thread_task)); + wake_up_process(common->thread_task); } fsg->gadget = gadget; diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 445df6775609..b6a9918eaefb 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn); -int fsg_common_run_thread(struct fsg_common *common); - void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index c45104e3a64b..64706a789580 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -161,14 +161,6 @@ static struct usb_endpoint_descriptor hs_ep_out_desc = { .wMaxPacketSize = cpu_to_le16(512) }; -static struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof(dev_qualifier), - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PRINTER, - .bNumConfigurations = 1 -}; - static struct usb_descriptor_header *hs_printer_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &hs_ep_in_desc, diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 2ace0295408e..197f73386fac 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1290,15 +1290,6 @@ static void usbg_release_cmd(struct se_cmd *se_cmd) percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); } -static int usbg_shutdown_session(struct se_session *se_sess) -{ - return 0; -} - -static void usbg_close_session(struct se_session *se_sess) -{ -} - static u32 usbg_sess_get_index(struct se_session *se_sess) { return 0; @@ -1454,16 +1445,18 @@ static void usbg_drop_tpg(struct se_portal_group *se_tpg) for (i = 0; i < TPG_INSTANCES; ++i) if (tpg_instances[i].tpg == tpg) break; - if (i < TPG_INSTANCES) + if (i < TPG_INSTANCES) { tpg_instances[i].tpg = NULL; - opts = container_of(tpg_instances[i].func_inst, - struct f_tcm_opts, func_inst); - mutex_lock(&opts->dep_lock); - if (opts->has_dep) - module_put(opts->dependent); - else - configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item); - mutex_unlock(&opts->dep_lock); + opts = container_of(tpg_instances[i].func_inst, + struct f_tcm_opts, func_inst); + mutex_lock(&opts->dep_lock); + if (opts->has_dep) + module_put(opts->dependent); + else + configfs_undepend_item_unlocked( + &opts->func_inst.group.cg_item); + mutex_unlock(&opts->dep_lock); + } mutex_unlock(&tpg_instances_lock); kfree(tpg); @@ -1735,8 +1728,6 @@ static const struct target_core_fabric_ops usbg_ops = { .tpg_check_prod_mode_write_protect = usbg_check_false, .tpg_get_inst_index = usbg_tpg_get_inst_index, .release_cmd = usbg_release_cmd, - .shutdown_session = usbg_shutdown_session, - .close_session = usbg_close_session, .sess_get_index = usbg_sess_get_index, .sess_get_initiator_sid = NULL, .write_pending = usbg_send_write_request, diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 186d4b162524..cd214ec8a601 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -598,18 +598,6 @@ static struct usb_gadget_strings *fn_strings[] = { NULL, }; -static struct usb_qualifier_descriptor devqual_desc = { - .bLength = sizeof devqual_desc, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = cpu_to_le16(0x200), - .bDeviceClass = USB_CLASS_MISC, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x01, - .bNumConfigurations = 1, - .bRESERVED = 0, -}; - static struct usb_interface_assoc_descriptor iad_desc = { .bLength = sizeof iad_desc, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, @@ -1292,6 +1280,7 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { struct cntrl_cur_lay3 c; + memset(&c, 0, sizeof(struct cntrl_cur_lay3)); if (entity_id == USB_IN_CLK_ID) c.dCUR = p_srate; diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index d62683017cf3..990df221c629 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -83,9 +83,7 @@ EXPORT_SYMBOL_GPL(fsg_fs_function); * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. * - * That means alternate endpoint descriptors (bigger packets) - * and a "device qualifier" ... plus more construction options - * for the configuration descriptor. + * That means alternate endpoint descriptors (bigger packets). */ struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 6af145f2a99d..3580f198df8b 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -512,7 +512,7 @@ static void gs_rx_push(unsigned long _port) req = list_first_entry(queue, struct usb_request, list); /* leave data queued if tty was rx throttled */ - if (tty && test_bit(TTY_THROTTLED, &tty->flags)) + if (tty && tty_throttled(tty)) break; switch (req->status) { @@ -579,7 +579,7 @@ static void gs_rx_push(unsigned long _port) * from starving ... but it's not clear that case ever happens. */ if (!list_empty(queue) && tty) { - if (!test_bit(TTY_THROTTLED, &tty->flags)) { + if (!tty_throttled(tty)) { if (do_push) tasklet_schedule(&port->push); else diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c16089efc322..c39de65a448b 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c) if (status < 0) goto put_msg; - status = fsg_common_run_thread(opts->common); - if (status) - goto remove_acm; - status = usb_add_function(c, f_msg); if (status) goto remove_acm; diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index e64479f882a5..aa3707bdebb4 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -938,8 +938,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) struct usb_ep *ep = dev->gadget->ep0; struct usb_request *req = dev->req; - if ((retval = setup_req (ep, req, 0)) == 0) - retval = usb_ep_queue (ep, req, GFP_ATOMIC); + if ((retval = setup_req (ep, req, 0)) == 0) { + spin_unlock_irq (&dev->lock); + retval = usb_ep_queue (ep, req, GFP_KERNEL); + spin_lock_irq (&dev->lock); + } dev->state = STATE_DEV_CONNECTED; /* assume that was SET_CONFIGURATION */ @@ -1457,8 +1460,11 @@ delegate: w_length); if (value < 0) break; + + spin_unlock (&dev->lock); value = usb_ep_queue (gadget->ep0, dev->req, - GFP_ATOMIC); + GFP_KERNEL); + spin_lock (&dev->lock); if (value < 0) { clean_req (gadget->ep0, dev->req); break; @@ -1481,11 +1487,14 @@ delegate: if (value >= 0 && dev->state != STATE_DEV_SETUP) { req->length = value; req->zero = value < w_length; - value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + + spin_unlock (&dev->lock); + value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL); if (value < 0) { DBG (dev, "ep_queue --> %d\n", value); req->status = 0; } + return value; } /* device stalls when value < 0 */ diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index e61af53c7d2b..125974f32f50 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c) if (IS_ERR(f_msg)) return PTR_ERR(f_msg); - ret = fsg_common_run_thread(opts->common); - if (ret) - goto put_func; - ret = usb_add_function(c, f_msg); if (ret) goto put_func; diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index 229d704a620b..a70a406580ea 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis; static int rndis_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_rndis); if (ret) goto err_run; @@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi; static int cdc_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_multi); if (ret) goto err_run; diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 09975046c694..b1e535f4022e 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c) struct usb_function *f_ecm; struct usb_function *f_obex2 = NULL; struct usb_function *f_msg; - struct fsg_opts *fsg_opts; int status = 0; int obex1_stat = -1; int obex2_stat = -1; @@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c) goto err_ecm; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - - status = fsg_common_run_thread(fsg_opts->common); - if (status) - goto err_msg; - status = usb_add_function(c, f_msg); if (status) goto err_msg; diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index d0d18947f58b..8bc78418d40e 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc) udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node, "atmel,matrix"); - if (IS_ERR(udc->matrix)) - return PTR_ERR(udc->matrix); - - return 0; + return PTR_ERR_OR_ZERO(udc->matrix); } static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 9571ef54b86b..ebc51ec5790a 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -325,11 +325,8 @@ struct pch_vbus_gpio_data { * @pdev: reference to the PCI device * @ep: array of endpoints * @lock: protects all state - * @active: enabled the PCI device * @stall: stall requested * @prot_stall: protcol stall requested - * @irq_registered: irq registered with system - * @mem_region: device memory mapped * @registered: driver registered with system * @suspended: driver in suspended state * @connected: gadget driver associated @@ -339,12 +336,8 @@ struct pch_vbus_gpio_data { * @data_requests: DMA pool for data requests * @stp_requests: DMA pool for setup requests * @dma_addr: DMA pool for received - * @ep0out_buf: Buffer for DMA * @setup_data: Received setup data - * @phys_addr: of device memory * @base_addr: for mapped device memory - * @bar: Indicates which PCI BAR for USB regs - * @irq: IRQ line for the device * @cfg_data: current cfg, intf, and alt in use * @vbus_gpio: GPIO informaton for detecting VBUS */ @@ -354,11 +347,9 @@ struct pch_udc_dev { struct pci_dev *pdev; struct pch_udc_ep ep[PCH_UDC_EP_NUM]; spinlock_t lock; /* protects all state */ - unsigned active:1, + unsigned stall:1, prot_stall:1, - irq_registered:1, - mem_region:1, suspended:1, connected:1, vbus_session:1, @@ -367,12 +358,8 @@ struct pch_udc_dev { struct pci_pool *data_requests; struct pci_pool *stp_requests; dma_addr_t dma_addr; - void *ep0out_buf; struct usb_ctrlrequest setup_data; - unsigned long phys_addr; void __iomem *base_addr; - unsigned bar; - unsigned irq; struct pch_udc_cfg_data cfg_data; struct pch_vbus_gpio_data vbus_gpio; }; @@ -380,8 +367,10 @@ struct pch_udc_dev { #define PCH_UDC_PCI_BAR_QUARK_X1000 0 #define PCH_UDC_PCI_BAR 1 -#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939 +#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 @@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if ((usbep->name == ep0_string) || !ep->ep.desc) return -EINVAL; @@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, struct pch_udc_request *req; struct pch_udc_ep *ep; struct pch_udc_data_dma_desc *dma_desc; - struct pch_udc_dev *dev; if (!usbep) return NULL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; req = kzalloc(sizeof *req, gfp); if (!req) return NULL; @@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, { struct pch_udc_ep *ep; struct pch_udc_request *req; - struct pch_udc_dev *dev; unsigned long flags; int ret = -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) return ret; req = container_of(usbreq, struct pch_udc_request, req); @@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev) static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) { u32 reg, dev_stat = 0; - int i, ret; + int i; dev_stat = pch_udc_read_device_status(dev); dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> @@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) } dev->stall = 0; spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } @@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) */ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) { - int i, ret; + int i; u32 reg, dev_stat = 0; dev_stat = pch_udc_read_device_status(dev); @@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) /* call gadget zero with setup data received */ spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } @@ -2856,17 +2835,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev) } /** - * gadget_release() - Free the gadget driver private data - * @pdev reference to struct pci_dev - */ -static void gadget_release(struct device *pdev) -{ - struct pch_udc_dev *dev = dev_get_drvdata(pdev); - - kfree(dev); -} - -/** * pch_udc_pcd_reinit() - This API initializes the endpoint structures * @dev: Reference to the driver structure */ @@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) { struct pch_udc_stp_dma_desc *td_stp; struct pch_udc_data_dma_desc *td_data; + void *ep0out_buf; /* DMA setup */ dev->data_requests = pci_pool_create("data_requests", dev->pdev, @@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev) dev->ep[UDC_EP0IN_IDX].td_data = NULL; dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; - dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); - if (!dev->ep0out_buf) + ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4, + GFP_KERNEL); + if (!ep0out_buf) return -ENOMEM; - dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, + dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); return 0; @@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev) if (dev->dma_addr) dma_unmap_single(&dev->pdev->dev, dev->dma_addr, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); - kfree(dev->ep0out_buf); pch_vbus_gpio_free(dev); pch_udc_exit(dev); - - if (dev->irq_registered) - free_irq(pdev->irq, dev); - if (dev->base_addr) - iounmap(dev->base_addr); - if (dev->mem_region) - release_mem_region(dev->phys_addr, - pci_resource_len(pdev, dev->bar)); - if (dev->active) - pci_disable_device(pdev); - kfree(dev); } -#ifdef CONFIG_PM -static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pch_udc_suspend(struct device *d) { + struct pci_dev *pdev = to_pci_dev(d); struct pch_udc_dev *dev = pci_get_drvdata(pdev); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - pci_disable_device(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - - if (pci_save_state(pdev)) { - dev_err(&pdev->dev, - "%s: could not save PCI config state\n", __func__); - return -ENOMEM; - } - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int pch_udc_resume(struct pci_dev *pdev) +static int pch_udc_resume(struct device *d) { - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__); - return ret; - } - pci_enable_wake(pdev, PCI_D3hot, 0); return 0; } + +static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); +#define PCH_UDC_PM_OPS (&pch_udc_pm) #else -#define pch_udc_suspend NULL -#define pch_udc_resume NULL -#endif /* CONFIG_PM */ +#define PCH_UDC_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - unsigned long resource; - unsigned long len; + int bar; int retval; struct pch_udc_dev *dev; /* init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (!dev) { - pr_err("%s: no memory for device structure\n", __func__); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) return -ENOMEM; - } + /* pci setup */ - if (pci_enable_device(pdev) < 0) { - kfree(dev); - pr_err("%s: pci_enable_device failed\n", __func__); - return -ENODEV; - } - dev->active = 1; + retval = pcim_enable_device(pdev); + if (retval) + return retval; + pci_set_drvdata(pdev, dev); /* Determine BAR based on PCI ID */ if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC) - dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000; + bar = PCH_UDC_PCI_BAR_QUARK_X1000; else - dev->bar = PCH_UDC_PCI_BAR; + bar = PCH_UDC_PCI_BAR; /* PCI resource allocation */ - resource = pci_resource_start(pdev, dev->bar); - len = pci_resource_len(pdev, dev->bar); + retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev)); + if (retval) + return retval; - if (!request_mem_region(resource, len, KBUILD_MODNAME)) { - dev_err(&pdev->dev, "%s: pci device used already\n", __func__); - retval = -EBUSY; - goto finished; - } - dev->phys_addr = resource; - dev->mem_region = 1; + dev->base_addr = pcim_iomap_table(pdev)[bar]; - dev->base_addr = ioremap_nocache(resource, len); - if (!dev->base_addr) { - pr_err("%s: device memory cannot be mapped\n", __func__); - retval = -ENOMEM; - goto finished; - } - if (!pdev->irq) { - dev_err(&pdev->dev, "%s: irq not set\n", __func__); - retval = -ENODEV; - goto finished; - } /* initialize the hardware */ - if (pch_udc_pcd_init(dev)) { - retval = -ENODEV; - goto finished; - } - if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, - dev)) { + if (pch_udc_pcd_init(dev)) + return -ENODEV; + + pci_enable_msi(pdev); + + retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (retval) { dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, pdev->irq); - retval = -ENODEV; goto finished; } - dev->irq = pdev->irq; - dev->irq_registered = 1; pci_set_master(pdev); pci_try_set_mwi(pdev); @@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev, /* Put the device in disconnected state till a driver is bound */ pch_udc_set_disconnect(dev); - retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, - gadget_release); + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); if (retval) goto finished; return 0; @@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = { .id_table = pch_udc_pcidev_id, .probe = pch_udc_probe, .remove = pch_udc_remove, - .suspend = pch_udc_suspend, - .resume = pch_udc_resume, .shutdown = pch_udc_shutdown, + .driver = { + .pm = PCH_UDC_PM_OPS, + }, }; module_pci_driver(pch_udc_driver); diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index baa0609a429d..8b300e6da7fc 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, } while ((tmp & mask) != loop); } -static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) +static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e4e70e11d0f6..e1b2dcebdc2e 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc, #ifdef CONFIG_HAS_DMA -int usb_gadget_map_request(struct usb_gadget *gadget, +int usb_gadget_map_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { - struct device *dev = gadget->dev.parent; - if (req->length == 0) return 0; @@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget, mapped = dma_map_sg(dev, req->sg, req->num_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (mapped == 0) { - dev_err(&gadget->dev, "failed to map SGs\n"); + dev_err(dev, "failed to map SGs\n"); return -EFAULT; } @@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget, return 0; } +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_map_request); -void usb_gadget_unmap_request(struct usb_gadget *gadget, +void usb_gadget_unmap_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { if (req->length == 0) return; if (req->num_mapped_sgs) { - dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs, + dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->num_mapped_sgs = 0; } else { - dma_unmap_single(gadget->dev.parent, req->dma, req->length, + dma_unmap_single(dev, req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); #endif /* CONFIG_HAS_DMA */ @@ -591,11 +603,15 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) } } - list_add_tail(&driver->pending, &gadget_driver_pending_list); - pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", - driver->function); + if (!driver->match_existing_only) { + list_add_tail(&driver->pending, &gadget_driver_pending_list); + pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", + driver->function); + ret = 0; + } + mutex_unlock(&udc_lock); - return 0; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3050b18b2447..d8f5674809e8 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -35,6 +35,7 @@ config USB_XHCI_PCI config USB_XHCI_PLATFORM tristate "Generic xHCI driver for a platform device" + select USB_XHCI_RCAR if ARCH_RENESAS ---help--- Adds an xHCI host driver for a generic platform device, which provides a memory space and an irq. @@ -63,12 +64,21 @@ config USB_XHCI_MVEBU config USB_XHCI_RCAR tristate "xHCI support for Renesas R-Car SoCs" - select USB_XHCI_PLATFORM + depends on USB_XHCI_PLATFORM depends on ARCH_RENESAS || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller found in Renesas R-Car ARM SoCs. +config USB_XHCI_TEGRA + tristate "xHCI support for NVIDIA Tegra SoCs" + depends on PHY_TEGRA_XUSB + depends on RESET_CONTROLLER + select FW_LOADER + ---help--- + Say 'Y' to enable the support for the xHCI host controller + found in NVIDIA Tegra124 and later SoCs. + endif # USB_XHCI_HCD config USB_EHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index a9ddd3c9ec94..6ef785b0ea8f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o +obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 963e2d0e8f92..172ef17911aa 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -352,10 +352,8 @@ static int bcma_hcd_probe(struct bcma_device *core) usb_dev->core = core; if (core->dev.of_node) - usb_dev->gpio_desc = devm_get_gpiod_from_child(&core->dev, "vcc", - &core->dev.of_node->fwnode); - if (!IS_ERR_OR_NULL(usb_dev->gpio_desc)) - gpiod_direction_output(usb_dev->gpio_desc, 1); + usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc", + GPIOD_OUT_HIGH); switch (core->id.id) { case BCMA_CORE_USB20_HOST: diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 79d12b2ba3c4..1a2614aae42c 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -52,13 +52,6 @@ static void dbg_hcs_params(struct ehci_hcd *ehci, char *label) ehci_dbg(ehci, "%s portroute %s\n", label, buf); } } -#else - -static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) {} - -#endif - -#ifdef CONFIG_DYNAMIC_DEBUG /* * check the values in the HCCPARAMS register @@ -92,13 +85,6 @@ static void dbg_hcc_params(struct ehci_hcd *ehci, char *label) " 32 periodic list" : ""); } } -#else - -static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) {} - -#endif - -#ifdef CONFIG_DYNAMIC_DEBUG static void __maybe_unused dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) @@ -281,37 +267,6 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) (status & PORT_CONNECT) ? " CONNECT" : ""); } -#else -static inline void __maybe_unused -dbg_qh(char *label, struct ehci_hcd *ehci, struct ehci_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 /* CONFIG_DYNAMIC_DEBUG */ - static inline void dbg_status(struct ehci_hcd *ehci, const char *label, u32 status) { @@ -341,13 +296,6 @@ dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status) /*-------------------------------------------------------------------------*/ -#ifndef CONFIG_DYNAMIC_DEBUG - -static inline void create_debug_files(struct ehci_hcd *bus) { } -static inline void remove_debug_files(struct ehci_hcd *bus) { } - -#else - /* troubleshooting help: expose state in debugfs */ static int debug_async_open(struct inode *, struct file *); @@ -1120,4 +1068,38 @@ static inline void remove_debug_files(struct ehci_hcd *ehci) debugfs_remove_recursive(ehci->debug_dir); } +#else /* CONFIG_DYNAMIC_DEBUG */ + +static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) { } +static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) { } + +static inline void __maybe_unused dbg_qh(const char *label, + struct ehci_hcd *ehci, struct ehci_qh *qh) { } + +static inline int __maybe_unused dbg_status_buf(const char *buf, + unsigned int len, const char *label, u32 status) +{ return 0; } + +static inline int __maybe_unused dbg_command_buf(const char *buf, + unsigned int len, const char *label, u32 command) +{ return 0; } + +static inline int __maybe_unused dbg_intr_buf(const char *buf, + unsigned int len, const char *label, u32 enable) +{ return 0; } + +static inline int __maybe_unused dbg_port_buf(char *buf, + unsigned int len, const char *label, int port, u32 status) +{ return 0; } + +static inline void dbg_status(struct ehci_hcd *ehci, const char *label, + u32 status) { } +static inline void dbg_cmd(struct ehci_hcd *ehci, const char *label, + u32 command) { } +static inline void dbg_port(struct ehci_hcd *ehci, const char *label, + int port, u32 status) { } + +static inline void create_debug_files(struct ehci_hcd *bus) { } +static inline void remove_debug_files(struct ehci_hcd *bus) { } + #endif /* CONFIG_DYNAMIC_DEBUG */ diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index df538fd10aa4..42e5b66353ef 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -321,7 +321,7 @@ static struct platform_driver exynos_ehci_driver = { .of_match_table = of_match_ptr(exynos_ehci_match), } }; -static const struct ehci_driver_overrides exynos_overrides __initdata = { +static const struct ehci_driver_overrides exynos_overrides __initconst = { .extra_priv_size = sizeof(struct exynos_ehci_hcd), }; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ae1b6e69eb96..a962b89b65a6 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -368,6 +368,15 @@ static void ehci_shutdown(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); + /** + * Protect the system from crashing at system shutdown in cases where + * usb host is not added yet from OTG controller driver. + * As ehci_setup() not done yet, so stop accessing registers or + * variables initialized in ehci_setup() + */ + if (!ehci->sbrn) + return; + spin_lock_irq(&ehci->lock); ehci->shutdown = true; ehci->rh_state = EHCI_RH_STOPPING; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index ffc90295a95f..74f62d68f013 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -872,15 +872,23 @@ int ehci_hub_control( ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int ports = HCS_N_PORTS (ehci->hcs_params); - u32 __iomem *status_reg = &ehci->regs->port_status[ - (wIndex & 0xff) - 1]; - u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; + u32 __iomem *status_reg, *hostpc_reg; u32 temp, temp1, status; unsigned long flags; int retval = 0; unsigned selector; /* + * Avoid underflow while calculating (wIndex & 0xff) - 1. + * The compiler might deduce that wIndex can never be 0 and then + * optimize away the tests for !wIndex below. + */ + temp = wIndex & 0xff; + temp -= (temp > 0); + status_reg = &ehci->regs->port_status[temp]; + hostpc_reg = &ehci->regs->hostpc[temp]; + + /* * 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, diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 3e226ef6ca62..2f8d3af811ce 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -179,22 +179,32 @@ static int ehci_msm_remove(struct platform_device *pdev) static int ehci_msm_pm_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); bool do_wakeup = device_may_wakeup(dev); dev_dbg(dev, "ehci-msm PM suspend\n"); - return ehci_suspend(hcd, do_wakeup); + /* Only call ehci_suspend if ehci_setup has been done */ + if (ehci->sbrn) + return ehci_suspend(hcd, do_wakeup); + + return 0; } static int ehci_msm_pm_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); dev_dbg(dev, "ehci-msm PM resume\n"); - ehci_resume(hcd, false); + + /* Only call ehci_resume if ehci_setup has been done */ + if (ehci->sbrn) + ehci_resume(hcd, false); return 0; } + #else #define ehci_msm_pm_suspend NULL #define ehci_msm_pm_resume NULL @@ -229,7 +239,7 @@ static struct platform_driver ehci_msm_driver = { }, }; -static const struct ehci_driver_overrides msm_overrides __initdata = { +static const struct ehci_driver_overrides msm_overrides __initconst = { .reset = ehci_msm_reset, }; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index a24720beb39d..94ea9fff13e6 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -86,7 +86,7 @@ static inline u32 ehci_read(void __iomem *base, u32 reg) static struct hc_driver __read_mostly ehci_omap_hc_driver; -static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { +static const struct ehci_driver_overrides ehci_omap_overrides __initconst = { .extra_priv_size = sizeof(struct omap_hcd), }; diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 3c4e5253955c..1f25c7985f5b 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -163,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = { } }; -static const struct ehci_driver_overrides spear_overrides __initdata = { +static const struct ehci_driver_overrides spear_overrides __initconst = { .extra_priv_size = sizeof(struct spear_ehci), }; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4031b372008e..9a3d7db5be57 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -81,15 +81,23 @@ static int tegra_reset_usb_controller(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv; + bool has_utmi_pad_registers = false; phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0); if (!phy_np) return -ENOENT; + if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers")) + has_utmi_pad_registers = true; + if (!usb1_reset_attempted) { struct reset_control *usb1_reset; - usb1_reset = of_reset_control_get(phy_np, "usb"); + if (!has_utmi_pad_registers) + usb1_reset = of_reset_control_get(phy_np, "utmi-pads"); + else + usb1_reset = tegra->rst; + if (IS_ERR(usb1_reset)) { dev_warn(&pdev->dev, "can't get utmi-pads reset from the PHY\n"); @@ -99,13 +107,15 @@ static int tegra_reset_usb_controller(struct platform_device *pdev) reset_control_assert(usb1_reset); udelay(1); reset_control_deassert(usb1_reset); + + if (!has_utmi_pad_registers) + reset_control_put(usb1_reset); } - reset_control_put(usb1_reset); usb1_reset_attempted = true; } - if (!of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers")) { + if (!has_utmi_pad_registers) { reset_control_assert(tegra->rst); udelay(1); reset_control_deassert(tegra->rst); diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index a9609a336efe..2f162faabbca 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -288,7 +288,7 @@ static int scan_ed_list(struct fhci_usb *usb, list_for_each_entry(ed, list, node) { td = ed->td_head; - if (!td || (td && td->status == USB_TD_INPROGRESS)) + if (!td || td->status == USB_TD_INPROGRESS) continue; if (ed->state != FHCI_ED_OPER) { diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 360a5e95abca..66efa9a67687 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -4795,14 +4795,8 @@ static DEVICE_ATTR(uframe_periodic_max, 0644, show_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; + return device_create_file(controller, &dev_attr_uframe_periodic_max); } static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 04dcedfdebf8..0449235d4f22 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1245,11 +1245,6 @@ MODULE_LICENSE ("GPL"); #define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver #endif -#ifdef CONFIG_MACH_JZ4740 -#include "ohci-jz4740.c" -#define PLATFORM_DRIVER ohci_hcd_jz4740_driver -#endif - #ifdef CONFIG_TILE_USB #include "ohci-tilegx.c" #define PLATFORM_DRIVER ohci_hcd_tilegx_driver diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c deleted file mode 100644 index 4db78f169256..000000000000 --- a/drivers/usb/host/ohci-jz4740.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> - * - * 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. - * - * 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/platform_device.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> - -struct jz4740_ohci_hcd { - struct ohci_hcd ohci_hcd; - - struct regulator *vbus; - bool vbus_enabled; - struct clk *clk; -}; - -static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd) -{ - return (struct jz4740_ohci_hcd *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci) -{ - return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv); -} - -static int ohci_jz4740_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "Can not start %s", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci, - bool enabled) -{ - int ret = 0; - - if (!jz4740_ohci->vbus) - return 0; - - if (enabled && !jz4740_ohci->vbus_enabled) { - ret = regulator_enable(jz4740_ohci->vbus); - if (ret) - dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller, - "Could not power vbus\n"); - } else if (!enabled && jz4740_ohci->vbus_enabled) { - ret = regulator_disable(jz4740_ohci->vbus); - } - - if (ret == 0) - jz4740_ohci->vbus_enabled = enabled; - - return ret; -} - -static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - int ret = 0; - - switch (typeReq) { - case SetPortFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true); - break; - case ClearPortFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false); - break; - } - - if (ret) - return ret; - - return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); -} - - -static const struct hc_driver ohci_jz4740_hc_driver = { - .description = hcd_name, - .product_desc = "JZ4740 OHCI", - .hcd_priv_size = sizeof(struct jz4740_ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_jz4740_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_jz4740_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - - -static int jz4740_ohci_probe(struct platform_device *pdev) -{ - int ret; - struct usb_hcd *hcd; - struct jz4740_ohci_hcd *jz4740_ohci; - struct resource *res; - int irq; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq\n"); - return irq; - } - - hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740"); - if (!hcd) { - dev_err(&pdev->dev, "Failed to create hcd.\n"); - return -ENOMEM; - } - - jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hcd->regs)) { - ret = PTR_ERR(hcd->regs); - goto err_free; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc"); - if (IS_ERR(jz4740_ohci->clk)) { - ret = PTR_ERR(jz4740_ohci->clk); - dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); - goto err_free; - } - - jz4740_ohci->vbus = devm_regulator_get(&pdev->dev, "vbus"); - if (IS_ERR(jz4740_ohci->vbus)) - jz4740_ohci->vbus = NULL; - - - clk_set_rate(jz4740_ohci->clk, 48000000); - clk_enable(jz4740_ohci->clk); - if (jz4740_ohci->vbus) - ohci_jz4740_set_vbus_power(jz4740_ohci, true); - - platform_set_drvdata(pdev, hcd); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret); - goto err_disable; - } - device_wakeup_enable(hcd->self.controller); - - return 0; - -err_disable: - if (jz4740_ohci->vbus) - regulator_disable(jz4740_ohci->vbus); - clk_disable(jz4740_ohci->clk); - -err_free: - usb_put_hcd(hcd); - - return ret; -} - -static int jz4740_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - usb_remove_hcd(hcd); - - if (jz4740_ohci->vbus) - regulator_disable(jz4740_ohci->vbus); - - clk_disable(jz4740_ohci->clk); - - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_jz4740_driver = { - .probe = jz4740_ohci_probe, - .remove = jz4740_ohci_remove, - .driver = { - .name = "jz4740-ohci", - }, -}; - -MODULE_ALIAS("platform:jz4740-ohci"); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index d029bbe9eb36..641fed609911 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -183,7 +183,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) { int branch; - ed->state = ED_OPER; ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; @@ -259,6 +258,8 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) /* the HC may not see the schedule updates yet, but if it does * then they'll be properly ordered. */ + + ed->state = ED_OPER; return 0; } diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 43626c44683b..5b3603c360ab 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -257,14 +257,14 @@ static int whc_probe(struct umc_dev *umc) ret = whc_init(whc); if (ret) - goto error; + goto error_whc_init; wusbhc->dev = dev; wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); if (!wusbhc->uwb_rc) { ret = -ENODEV; dev_err(dev, "cannot get radio controller\n"); - goto error; + goto error_uwb_rc; } if (whc->n_devices > USB_MAXCHILDREN) { @@ -311,8 +311,9 @@ error_usb_add_hcd: wusbhc_destroy(wusbhc); error_wusbhc_create: uwb_rc_put(wusbhc->uwb_rc); -error: +error_uwb_rc: whc_clean_up(whc); +error_whc_init: usb_put_hcd(usb_hcd); return ret; } diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 1a8e960d073b..c0e6812426b3 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -314,7 +314,7 @@ void qset_free_std(struct whc *whc, struct whc_std *std) kfree(std->bounce_buf); } if (std->pl_virt) { - if (std->dma_addr) + if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) dma_unmap_single(whc->wusbhc.dev, std->dma_addr, std->num_pointers * sizeof(struct whc_page_list_entry), DMA_TO_DEVICE); @@ -535,9 +535,11 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u list_for_each_entry(std, &qset->stds, list_node) { if (std->ntds_remaining == -1) { pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); - std->ntds_remaining = ntds--; std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); + if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) + return -EFAULT; + std->ntds_remaining = ntds--; } } return 0; @@ -618,6 +620,8 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset, std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(&whc->umc->dev, std->dma_addr)) + return -EFAULT; if (qset_fill_page_list(whc, std, mem_flags) < 0) return -ENOMEM; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 1eefc988192d..85908a3ecb8f 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -12,6 +12,9 @@ #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + #include "xhci-mvebu.h" #define USB3_MAX_WINDOWS 4 @@ -41,8 +44,10 @@ static void xhci_mvebu_mbus_config(void __iomem *base, } } -int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) { + struct device *dev = hcd->self.controller; + struct platform_device *pdev = to_platform_device(dev); struct resource *res; void __iomem *base; const struct mbus_dram_target_info *dram; diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h index 7ede92aa41f6..301fc984cae6 100644 --- a/drivers/usb/host/xhci-mvebu.h +++ b/drivers/usb/host/xhci-mvebu.h @@ -10,10 +10,13 @@ #ifndef __LINUX_XHCI_MVEBU_H #define __LINUX_XHCI_MVEBU_H + +struct usb_hcd; + #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) -int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev); +int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); #else -static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) { return 0; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 48672fac7ff3..c10972fcc8e4 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -37,6 +37,7 @@ /* Device for a quirk */ #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 #define PCI_VENDOR_ID_ETRON 0x1b6f @@ -114,6 +115,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_TRUST_TX_LENGTH; } + if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && + pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009) + xhci->quirks |= XHCI_BROKEN_STREAMS; + if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 474b5fa14900..1f3f981fe7f8 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -37,27 +37,32 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { .start = xhci_plat_start, }; -static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) +static void xhci_priv_plat_start(struct usb_hcd *hcd) +{ + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (priv->plat_start) + priv->plat_start(hcd); +} + +static int xhci_priv_init_quirk(struct usb_hcd *hcd) { - struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); + + if (!priv->init_quirk) + return 0; + return priv->init_quirk(hcd); +} + +static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) +{ /* * As of now platform drivers don't provide MSI support so we ensure * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ xhci->quirks |= XHCI_PLAT; - - /* - * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set - * to 1. However, these SoCs don't support 64-bit address memory - * pointers. So, this driver clears the AC64 bit of xhci->hcc_params - * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in - * xhci_gen_setup(). - */ - if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) || - xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) - xhci->quirks |= XHCI_NO_64BIT_SUPPORT; } /* called during probe() after chip reset completes */ @@ -65,38 +70,35 @@ static int xhci_plat_setup(struct usb_hcd *hcd) { int ret; - if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) || - xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) { - ret = xhci_rcar_init_quirk(hcd); - if (ret) - return ret; - } + + ret = xhci_priv_init_quirk(hcd); + if (ret) + return ret; return xhci_gen_setup(hcd, xhci_plat_quirks); } static int xhci_plat_start(struct usb_hcd *hcd) { - if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) || - xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) - xhci_rcar_start(hcd); - + xhci_priv_plat_start(hcd); return xhci_run(hcd); } #ifdef CONFIG_OF static const struct xhci_plat_priv xhci_plat_marvell_armada = { - .type = XHCI_PLAT_TYPE_MARVELL_ARMADA, + .init_quirk = xhci_mvebu_mbus_init_quirk, }; static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { - .type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2, .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, + .init_quirk = xhci_rcar_init_quirk, + .plat_start = xhci_rcar_start, }; static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { - .type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3, .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2, + .init_quirk = xhci_rcar_init_quirk, + .plat_start = xhci_rcar_start, }; static const struct of_device_id usb_xhci_of_match[] = { @@ -194,6 +196,9 @@ static int xhci_plat_probe(struct platform_device *pdev) ret = clk_prepare_enable(clk); if (ret) goto put_hcd; + } else if (PTR_ERR(clk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto put_hcd; } xhci = hcd_to_xhci(hcd); @@ -207,12 +212,6 @@ static int xhci_plat_probe(struct platform_device *pdev) *priv = *priv_match; } - if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) { - ret = xhci_mvebu_mbus_init_quirk(pdev); - if (ret) - goto disable_clk; - } - device_wakeup_enable(hcd->self.controller); xhci->clk = clk; diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h index 529c3c40f901..9af0cb48053f 100644 --- a/drivers/usb/host/xhci-plat.h +++ b/drivers/usb/host/xhci-plat.h @@ -13,27 +13,11 @@ #include "xhci.h" /* for hcd_to_xhci() */ -enum xhci_plat_type { - XHCI_PLAT_TYPE_MARVELL_ARMADA = 1, - XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2, - XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3, -}; - struct xhci_plat_priv { - enum xhci_plat_type type; const char *firmware_name; + void (*plat_start)(struct usb_hcd *); + int (*init_quirk)(struct usb_hcd *); }; #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) - -static inline bool xhci_plat_type_is(struct usb_hcd *hcd, - enum xhci_plat_type type) -{ - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); - - if (priv && priv->type == type) - return true; - else - return false; -} #endif /* _XHCI_PLAT_H */ diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 623100e9385e..0e4535e632ec 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -11,6 +11,7 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <linux/usb/phy.h> #include "xhci.h" @@ -76,6 +77,24 @@ static void xhci_rcar_start_gen2(struct usb_hcd *hcd) writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL); } +static int xhci_rcar_is_gen2(struct device *dev) +{ + struct device_node *node = dev->of_node; + + return of_device_is_compatible(node, "renesas,xhci-r8a7790") || + of_device_is_compatible(node, "renesas,xhci-r8a7791") || + of_device_is_compatible(node, "renesas,xhci-r8a7793") || + of_device_is_compatible(node, "renensas,rcar-gen2-xhci"); +} + +static int xhci_rcar_is_gen3(struct device *dev) +{ + struct device_node *node = dev->of_node; + + return of_device_is_compatible(node, "renesas,xhci-r8a7795") || + of_device_is_compatible(node, "renesas,rcar-gen3-xhci"); +} + void xhci_rcar_start(struct usb_hcd *hcd) { u32 temp; @@ -85,7 +104,7 @@ void xhci_rcar_start(struct usb_hcd *hcd) temp = readl(hcd->regs + RCAR_USB3_INT_ENA); temp |= RCAR_USB3_INT_ENA_VAL; writel(temp, hcd->regs + RCAR_USB3_INT_ENA); - if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2)) + if (xhci_rcar_is_gen2(hcd->self.controller)) xhci_rcar_start_gen2(hcd); } } @@ -156,9 +175,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) /* This function needs to initialize a "phy" of usb before */ int xhci_rcar_init_quirk(struct usb_hcd *hcd) { + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + /* If hcd->regs is NULL, we don't just call the following function */ if (!hcd->regs) return 0; + /* + * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set + * to 1. However, these SoCs don't support 64-bit address memory + * pointers. So, this driver clears the AC64 bit of xhci->hcc_params + * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in + * xhci_gen_setup(). + */ + if (xhci_rcar_is_gen2(hcd->self.controller) || + xhci_rcar_is_gen3(hcd->self.controller)) + xhci->quirks |= XHCI_NO_64BIT_SUPPORT; + return xhci_rcar_download_firmware(hcd); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 99b4ff42f7a0..d7d502578d79 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -290,6 +290,14 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; + + /* + * Writing the CMD_RING_ABORT bit should cause a cmd completion event, + * however on some host hw the CMD_RING_RUNNING bit is correctly cleared + * but the completion event in never sent. Use the cmd timeout timer to + * handle those cases. Use twice the time to cover the bit polling retry + */ + mod_timer(&xhci->cmd_timer, jiffies + (2 * XHCI_CMD_DEFAULT_TIMEOUT)); xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); @@ -314,6 +322,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) xhci_err(xhci, "Stopped the command ring failed, " "maybe the host is dead\n"); + del_timer(&xhci->cmd_timer); xhci->xhc_state |= XHCI_STATE_DYING; xhci_quiesce(xhci); xhci_halt(xhci); @@ -373,7 +382,11 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, } } -static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, +/* Get the right ring for the given slot_id, ep_index and stream_id. + * If the endpoint supports streams, boundary check the URB's stream ID. + * If the endpoint doesn't support streams, return the singular endpoint ring. + */ +struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id) { @@ -405,17 +418,6 @@ static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, return NULL; } -/* Get the right ring for the given URB. - * If the endpoint supports streams, boundary check the URB's stream ID. - * If the endpoint doesn't support streams, return the singular endpoint ring. - */ -static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, - struct urb *urb) -{ - return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id, - xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id); -} - /* * Move the xHC's endpoint ring dequeue pointer past cur_td. * Record the new state of the xHC's endpoint ring dequeue segment, @@ -1253,22 +1255,21 @@ void xhci_handle_command_timeout(unsigned long data) int ret; unsigned long flags; u64 hw_ring_state; - struct xhci_command *cur_cmd = NULL; + bool second_timeout = false; xhci = (struct xhci_hcd *) data; /* mark this command to be cancelled */ spin_lock_irqsave(&xhci->lock, flags); if (xhci->current_cmd) { - cur_cmd = xhci->current_cmd; - cur_cmd->status = COMP_CMD_ABORT; + if (xhci->current_cmd->status == COMP_CMD_ABORT) + second_timeout = true; + xhci->current_cmd->status = COMP_CMD_ABORT; } - /* Make sure command ring is running before aborting it */ hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && (hw_ring_state & CMD_RING_RUNNING)) { - spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "Command timeout\n"); ret = xhci_abort_cmd_ring(xhci); @@ -1280,6 +1281,15 @@ void xhci_handle_command_timeout(unsigned long data) } return; } + + /* command ring failed to restart, or host removed. Bail out */ + if (second_timeout || xhci->xhc_state & XHCI_STATE_REMOVING) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "command timed out twice, ring start fail?\n"); + xhci_cleanup_command_queue(xhci); + return; + } + /* command timeout on stopped ring, ring can't be aborted */ xhci_dbg(xhci, "Command timeout on stopped ring\n"); xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); @@ -1768,7 +1778,7 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, if (trb_comp_code == COMP_TX_ERR || trb_comp_code == COMP_BABBLE || trb_comp_code == COMP_SPLIT_ERR) - /* The 0.96 spec says a babbling control endpoint + /* The 0.95 spec says a babbling control endpoint * is not halted. The 0.96 spec says it is. Some HW * claims to be 0.95 compliant, but it halts the control * endpoint anyway. Check if a babble halted the @@ -2728,7 +2738,8 @@ hw_died: writel(irq_pending, &xhci->ir_set->irq_pending); } - if (xhci->xhc_state & XHCI_STATE_DYING) { + if (xhci->xhc_state & XHCI_STATE_DYING || + xhci->xhc_state & XHCI_STATE_HALTED) { xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " "Shouldn't IRQs be disabled?\n"); /* Clear the event handler busy flag (RW1C); @@ -2938,46 +2949,55 @@ static int prepare_transfer(struct xhci_hcd *xhci, return 0; } -static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) +static unsigned int count_trbs(u64 addr, u64 len) +{ + unsigned int num_trbs; + + num_trbs = DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFF_SIZE - 1)), + TRB_MAX_BUFF_SIZE); + if (num_trbs == 0) + num_trbs++; + + return num_trbs; +} + +static inline unsigned int count_trbs_needed(struct urb *urb) +{ + return count_trbs(urb->transfer_dma, urb->transfer_buffer_length); +} + +static unsigned int count_sg_trbs_needed(struct urb *urb) { - int num_sgs, num_trbs, running_total, temp, i; struct scatterlist *sg; + unsigned int i, len, full_len, num_trbs = 0; - sg = NULL; - num_sgs = urb->num_mapped_sgs; - temp = urb->transfer_buffer_length; + full_len = urb->transfer_buffer_length; - num_trbs = 0; - for_each_sg(urb->sg, sg, num_sgs, i) { - unsigned int len = sg_dma_len(sg); - - /* Scatter gather list entries may cross 64KB boundaries */ - running_total = TRB_MAX_BUFF_SIZE - - (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1)); - running_total &= TRB_MAX_BUFF_SIZE - 1; - if (running_total != 0) - num_trbs++; - - /* How many more 64KB chunks to transfer, how many more TRBs? */ - while (running_total < sg_dma_len(sg) && running_total < temp) { - num_trbs++; - running_total += TRB_MAX_BUFF_SIZE; - } - len = min_t(int, len, temp); - temp -= len; - if (temp == 0) + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { + len = sg_dma_len(sg); + num_trbs += count_trbs(sg_dma_address(sg), len); + len = min_t(unsigned int, len, full_len); + full_len -= len; + if (full_len == 0) break; } + return num_trbs; } -static void check_trb_math(struct urb *urb, int num_trbs, int running_total) +static unsigned int count_isoc_trbs_needed(struct urb *urb, int i) { - if (num_trbs != 0) - dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of " - "TRBs, %d left\n", __func__, - urb->ep->desc.bEndpointAddress, num_trbs); - if (running_total != urb->transfer_buffer_length) + u64 addr, len; + + addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset); + len = urb->iso_frame_desc[i].length; + + return count_trbs(addr, len); +} + +static void check_trb_math(struct urb *urb, int running_total) +{ + if (unlikely(running_total != urb->transfer_buffer_length)) dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, " "queued %#x (%d), asked for %#x (%d)\n", __func__, @@ -3003,26 +3023,20 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); } -/* - * xHCI uses normal TRBs for both bulk and interrupt. When the interrupt - * endpoint is to be serviced, the xHC will consume (at most) one TD. A TD - * (comprised of sg list entries) can take several service intervals to - * transmit. - */ -int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) +static void check_interval(struct xhci_hcd *xhci, struct urb *urb, + struct xhci_ep_ctx *ep_ctx) { - struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, - xhci->devs[slot_id]->out_ctx, ep_index); int xhci_interval; int ep_interval; xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); ep_interval = urb->interval; + /* Convert to microframes */ if (urb->dev->speed == USB_SPEED_LOW || urb->dev->speed == USB_SPEED_FULL) ep_interval *= 8; + /* FIXME change this to a warning and a suggestion to use the new API * to set the polling interval (once the API is added). */ @@ -3037,6 +3051,22 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb->dev->speed == USB_SPEED_FULL) urb->interval /= 8; } +} + +/* + * xHCI uses normal TRBs for both bulk and interrupt. When the interrupt + * endpoint is to be serviced, the xHC will consume (at most) one TD. A TD + * (comprised of sg list entries) can take several service intervals to + * transmit. + */ +int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) +{ + struct xhci_ep_ctx *ep_ctx; + + ep_ctx = xhci_get_ep_ctx(xhci, xhci->devs[slot_id]->out_ctx, ep_index); + check_interval(xhci, urb, ep_ctx); + return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index); } @@ -3086,44 +3116,47 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred, return (total_packet_count - ((transferred + trb_buff_len) / maxp)); } - -static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, +/* This is very similar to what ehci-q.c qtd_fill() does */ +int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) { struct xhci_ring *ep_ring; - unsigned int num_trbs; struct urb_priv *urb_priv; struct xhci_td *td; - struct scatterlist *sg; - int num_sgs; - int trb_buff_len, this_sg_len, running_total, ret; - unsigned int total_packet_count; + struct xhci_generic_trb *start_trb; + struct scatterlist *sg = NULL; + bool more_trbs_coming; bool zero_length_needed; - bool first_trb; - int last_trb_num; + unsigned int num_trbs, last_trb_num, i; + unsigned int start_cycle, num_sgs = 0; + unsigned int running_total, block_len, trb_buff_len; + unsigned int full_len; + int ret; + u32 field, length_field, remainder; u64 addr; - bool more_trbs_coming; - - struct xhci_generic_trb *start_trb; - int start_cycle; ep_ring = xhci_urb_to_transfer_ring(xhci, urb); if (!ep_ring) return -EINVAL; - num_trbs = count_sg_trbs_needed(xhci, urb); - num_sgs = urb->num_mapped_sgs; - total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, - usb_endpoint_maxp(&urb->ep->desc)); + /* If we have scatter/gather list, we use it. */ + if (urb->num_sgs) { + num_sgs = urb->num_mapped_sgs; + sg = urb->sg; + num_trbs = count_sg_trbs_needed(urb); + } else + num_trbs = count_trbs_needed(urb); ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb, 0, mem_flags); - if (ret < 0) + if (unlikely(ret < 0)) return ret; urb_priv = urb->hcpriv; + last_trb_num = num_trbs - 1; + /* Deal with URB_ZERO_PACKET - need one more td/trb */ zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length == 2; @@ -3133,7 +3166,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, 1, urb, 1, mem_flags); - if (ret < 0) + if (unlikely(ret < 0)) return ret; } @@ -3147,228 +3180,58 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, start_trb = &ep_ring->enqueue->generic; start_cycle = ep_ring->cycle_state; + full_len = urb->transfer_buffer_length; running_total = 0; - /* - * How much data is in the first TRB? - * - * There are three forces at work for TRB buffer pointers and lengths: - * 1. We don't want to walk off the end of this sg-list entry buffer. - * 2. The transfer length that the driver requested may be smaller than - * the amount of memory allocated for this scatter-gather list. - * 3. TRBs buffers can't cross 64KB boundaries. - */ - sg = urb->sg; - addr = (u64) sg_dma_address(sg); - this_sg_len = sg_dma_len(sg); - trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); - trb_buff_len = min_t(int, trb_buff_len, this_sg_len); - if (trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = urb->transfer_buffer_length; - - first_trb = true; - last_trb_num = zero_length_needed ? 2 : 1; - /* Queue the first TRB, even if it's zero-length */ - do { - u32 field = 0; - u32 length_field = 0; - u32 remainder = 0; - - /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) { - first_trb = false; - if (start_cycle == 0) - field |= 0x1; - } else - field |= ep_ring->cycle_state; - - /* Chain all the TRBs together; clear the chain bit in the last - * TRB to indicate it's the last TRB in the chain. - */ - if (num_trbs > last_trb_num) { - field |= TRB_CHAIN; - } else if (num_trbs == last_trb_num) { - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - } else if (zero_length_needed && num_trbs == 1) { - trb_buff_len = 0; - urb_priv->td[1]->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - } - - /* Only set interrupt on short packet for IN endpoints */ - if (usb_urb_dir_in(urb)) - field |= TRB_ISP; + block_len = 0; - if (TRB_MAX_BUFF_SIZE - - (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) { - xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n"); - xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n", - (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), - (unsigned int) addr + trb_buff_len); - } - - /* Set the TRB length, TD size, and interrupter fields. */ - remainder = xhci_td_remainder(xhci, running_total, trb_buff_len, - urb->transfer_buffer_length, - urb, num_trbs - 1); - - length_field = TRB_LEN(trb_buff_len) | - TRB_TD_SIZE(remainder) | - TRB_INTR_TARGET(0); + /* Queue the TRBs, even if they are zero-length */ + for (i = 0; i < num_trbs; i++) { + field = TRB_TYPE(TRB_NORMAL); - if (num_trbs > 1) - more_trbs_coming = true; - else - more_trbs_coming = false; - queue_trb(xhci, ep_ring, more_trbs_coming, - lower_32_bits(addr), - upper_32_bits(addr), - length_field, - field | TRB_TYPE(TRB_NORMAL)); - --num_trbs; - running_total += trb_buff_len; - - /* Calculate length for next transfer -- - * Are we done queueing all the TRBs for this sg entry? - */ - this_sg_len -= trb_buff_len; - if (this_sg_len == 0) { - --num_sgs; - if (num_sgs == 0) - break; - sg = sg_next(sg); - addr = (u64) sg_dma_address(sg); - this_sg_len = sg_dma_len(sg); + if (block_len == 0) { + /* A new contiguous block. */ + if (sg) { + addr = (u64) sg_dma_address(sg); + block_len = sg_dma_len(sg); + } else { + addr = (u64) urb->transfer_dma; + block_len = full_len; + } + /* TRB buffer should not cross 64KB boundaries */ + trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr); + trb_buff_len = min_t(unsigned int, + trb_buff_len, + block_len); } else { - addr += trb_buff_len; + /* Further through the contiguous block. */ + trb_buff_len = block_len; + if (trb_buff_len > TRB_MAX_BUFF_SIZE) + trb_buff_len = TRB_MAX_BUFF_SIZE; } - trb_buff_len = TRB_MAX_BUFF_SIZE - - (addr & (TRB_MAX_BUFF_SIZE - 1)); - trb_buff_len = min_t(int, trb_buff_len, this_sg_len); - if (running_total + trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = - urb->transfer_buffer_length - running_total; - } while (num_trbs > 0); - - check_trb_math(urb, num_trbs, running_total); - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb); - return 0; -} - -/* This is very similar to what ehci-q.c qtd_fill() does */ -int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ring *ep_ring; - struct urb_priv *urb_priv; - struct xhci_td *td; - int num_trbs; - struct xhci_generic_trb *start_trb; - bool first_trb; - int last_trb_num; - bool more_trbs_coming; - bool zero_length_needed; - int start_cycle; - u32 field, length_field; - - int running_total, trb_buff_len, ret; - unsigned int total_packet_count; - u64 addr; - - if (urb->num_sgs) - return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); - - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) - return -EINVAL; - - num_trbs = 0; - /* How much data is (potentially) left before the 64KB boundary? */ - running_total = TRB_MAX_BUFF_SIZE - - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); - running_total &= TRB_MAX_BUFF_SIZE - 1; - - /* If there's some data on this 64KB chunk, or we have to send a - * zero-length transfer, we need at least one TRB - */ - if (running_total != 0 || urb->transfer_buffer_length == 0) - num_trbs++; - /* How many more 64KB chunks to transfer, how many more TRBs? */ - while (running_total < urb->transfer_buffer_length) { - num_trbs++; - running_total += TRB_MAX_BUFF_SIZE; - } - - ret = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); - if (ret < 0) - return ret; - - urb_priv = urb->hcpriv; - - /* Deal with URB_ZERO_PACKET - need one more td/trb */ - zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && - urb_priv->length == 2; - if (zero_length_needed) { - num_trbs++; - xhci_dbg(xhci, "Creating zero length td.\n"); - ret = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - 1, urb, 1, mem_flags); - if (ret < 0) - return ret; - } - - td = urb_priv->td[0]; - - /* - * Don't give the first TRB to the hardware (by toggling the cycle bit) - * until we've finished creating all the other TRBs. The ring's cycle - * state may change as we enqueue the other TRBs, so save it too. - */ - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; - - running_total = 0; - total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, - usb_endpoint_maxp(&urb->ep->desc)); - /* How much data is in the first TRB? */ - addr = (u64) urb->transfer_dma; - trb_buff_len = TRB_MAX_BUFF_SIZE - - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); - if (trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = urb->transfer_buffer_length; - - first_trb = true; - last_trb_num = zero_length_needed ? 2 : 1; - /* Queue the first TRB, even if it's zero-length */ - do { - u32 remainder = 0; - field = 0; + if (running_total + trb_buff_len > full_len) + trb_buff_len = full_len - running_total; /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) { - first_trb = false; + if (i == 0) { if (start_cycle == 0) - field |= 0x1; + field |= TRB_CYCLE; } else field |= ep_ring->cycle_state; /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > last_trb_num) { + if (i < last_trb_num) { field |= TRB_CHAIN; - } else if (num_trbs == last_trb_num) { - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - } else if (zero_length_needed && num_trbs == 1) { - trb_buff_len = 0; - urb_priv->td[1]->last_trb = ep_ring->enqueue; + } else { field |= TRB_IOC; + if (i == last_trb_num) + td->last_trb = ep_ring->enqueue; + else if (zero_length_needed) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + } } /* Only set interrupt on short packet for IN endpoints */ @@ -3376,15 +3239,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_ISP; /* Set the TRB length, TD size, and interrupter fields. */ - remainder = xhci_td_remainder(xhci, running_total, trb_buff_len, - urb->transfer_buffer_length, - urb, num_trbs - 1); + remainder = xhci_td_remainder(xhci, running_total, + trb_buff_len, full_len, + urb, num_trbs - i - 1); length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) | TRB_INTR_TARGET(0); - if (num_trbs > 1) + if (i < num_trbs - 1) more_trbs_coming = true; else more_trbs_coming = false; @@ -3392,18 +3255,24 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, lower_32_bits(addr), upper_32_bits(addr), length_field, - field | TRB_TYPE(TRB_NORMAL)); - --num_trbs; - running_total += trb_buff_len; + field); - /* Calculate length for next transfer */ + running_total += trb_buff_len; addr += trb_buff_len; - trb_buff_len = urb->transfer_buffer_length - running_total; - if (trb_buff_len > TRB_MAX_BUFF_SIZE) - trb_buff_len = TRB_MAX_BUFF_SIZE; - } while (num_trbs > 0); + block_len -= trb_buff_len; + + if (sg) { + if (block_len == 0) { + /* New sg entry */ + --num_sgs; + if (num_sgs == 0) + break; + sg = sg_next(sg); + } + } + } - check_trb_math(urb, num_trbs, running_total); + check_trb_math(urb, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); return 0; @@ -3532,23 +3401,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return 0; } -static int count_isoc_trbs_needed(struct xhci_hcd *xhci, - struct urb *urb, int i) -{ - int num_trbs = 0; - u64 addr, td_len; - - addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset); - td_len = urb->iso_frame_desc[i].length; - - num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)), - TRB_MAX_BUFF_SIZE); - if (num_trbs == 0) - num_trbs++; - - return num_trbs; -} - /* * The transfer burst count field of the isochronous TRB defines the number of * bursts that are required to move all packets in this TD. Only SuperSpeed @@ -3746,7 +3598,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci, urb, total_pkt_count); - trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); + trbs_per_td = count_isoc_trbs_needed(urb, i); ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, trbs_per_td, urb, i, mem_flags); @@ -3807,8 +3659,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_BEI; } /* Calculate TRB length */ - trb_buff_len = TRB_MAX_BUFF_SIZE - - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); + trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr); if (trb_buff_len > td_remain_len) trb_buff_len = td_remain_len; @@ -3897,8 +3748,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_ring *ep_ring; struct xhci_ep_ctx *ep_ctx; int start_frame; - int xhci_interval; - int ep_interval; int num_tds, num_trbs, i; int ret; struct xhci_virt_ep *xep; @@ -3912,7 +3761,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs = 0; num_tds = urb->number_of_packets; for (i = 0; i < num_tds; i++) - num_trbs += count_isoc_trbs_needed(xhci, urb, i); + num_trbs += count_isoc_trbs_needed(urb, i); /* Check the ring to guarantee there is enough room for the whole urb. * Do not insert any td of the urb to the ring if the check failed. @@ -3926,26 +3775,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * Check interval value. This should be done before we start to * calculate the start frame value. */ - xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); - ep_interval = urb->interval; - /* Convert to microframes */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - ep_interval *= 8; - /* FIXME change this to a warning and a suggestion to use the new API - * to set the polling interval (once the API is added). - */ - if (xhci_interval != ep_interval) { - dev_dbg_ratelimited(&urb->dev->dev, - "Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n", - ep_interval, ep_interval == 1 ? "" : "s", - xhci_interval, xhci_interval == 1 ? "" : "s"); - urb->interval = xhci_interval; - /* Convert back to frames for LS/FS devices */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->interval /= 8; - } + check_interval(xhci, urb, ep_ctx); /* Calculate the start frame and put it in urb->start_frame. */ if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) { diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c new file mode 100644 index 000000000000..0f53ae0f464e --- /dev/null +++ b/drivers/usb/host/xhci-tegra.c @@ -0,0 +1,1331 @@ +/* + * NVIDIA Tegra xHCI host controller driver + * + * Copyright (C) 2014 NVIDIA Corporation + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/phy/tegra/xusb.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/slab.h> + +#include "xhci.h" + +#define TEGRA_XHCI_SS_HIGH_SPEED 120000000 +#define TEGRA_XHCI_SS_LOW_SPEED 12000000 + +/* FPCI CFG registers */ +#define XUSB_CFG_1 0x004 +#define XUSB_IO_SPACE_EN BIT(0) +#define XUSB_MEM_SPACE_EN BIT(1) +#define XUSB_BUS_MASTER_EN BIT(2) +#define XUSB_CFG_4 0x010 +#define XUSB_BASE_ADDR_SHIFT 15 +#define XUSB_BASE_ADDR_MASK 0x1ffff +#define XUSB_CFG_ARU_C11_CSBRANGE 0x41c +#define XUSB_CFG_CSB_BASE_ADDR 0x800 + +/* FPCI mailbox registers */ +#define XUSB_CFG_ARU_MBOX_CMD 0x0e4 +#define MBOX_DEST_FALC BIT(27) +#define MBOX_DEST_PME BIT(28) +#define MBOX_DEST_SMI BIT(29) +#define MBOX_DEST_XHCI BIT(30) +#define MBOX_INT_EN BIT(31) +#define XUSB_CFG_ARU_MBOX_DATA_IN 0x0e8 +#define CMD_DATA_SHIFT 0 +#define CMD_DATA_MASK 0xffffff +#define CMD_TYPE_SHIFT 24 +#define CMD_TYPE_MASK 0xff +#define XUSB_CFG_ARU_MBOX_DATA_OUT 0x0ec +#define XUSB_CFG_ARU_MBOX_OWNER 0x0f0 +#define MBOX_OWNER_NONE 0 +#define MBOX_OWNER_FW 1 +#define MBOX_OWNER_SW 2 +#define XUSB_CFG_ARU_SMI_INTR 0x428 +#define MBOX_SMI_INTR_FW_HANG BIT(1) +#define MBOX_SMI_INTR_EN BIT(3) + +/* IPFS registers */ +#define IPFS_XUSB_HOST_CONFIGURATION_0 0x180 +#define IPFS_EN_FPCI BIT(0) +#define IPFS_XUSB_HOST_INTR_MASK_0 0x188 +#define IPFS_IP_INT_MASK BIT(16) +#define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0 0x1bc + +#define CSB_PAGE_SELECT_MASK 0x7fffff +#define CSB_PAGE_SELECT_SHIFT 9 +#define CSB_PAGE_OFFSET_MASK 0x1ff +#define CSB_PAGE_SELECT(addr) ((addr) >> (CSB_PAGE_SELECT_SHIFT) & \ + CSB_PAGE_SELECT_MASK) +#define CSB_PAGE_OFFSET(addr) ((addr) & CSB_PAGE_OFFSET_MASK) + +/* Falcon CSB registers */ +#define XUSB_FALC_CPUCTL 0x100 +#define CPUCTL_STARTCPU BIT(1) +#define CPUCTL_STATE_HALTED BIT(4) +#define CPUCTL_STATE_STOPPED BIT(5) +#define XUSB_FALC_BOOTVEC 0x104 +#define XUSB_FALC_DMACTL 0x10c +#define XUSB_FALC_IMFILLRNG1 0x154 +#define IMFILLRNG1_TAG_MASK 0xffff +#define IMFILLRNG1_TAG_LO_SHIFT 0 +#define IMFILLRNG1_TAG_HI_SHIFT 16 +#define XUSB_FALC_IMFILLCTL 0x158 + +/* MP CSB registers */ +#define XUSB_CSB_MP_ILOAD_ATTR 0x101a00 +#define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04 +#define XUSB_CSB_MP_ILOAD_BASE_HI 0x101a08 +#define XUSB_CSB_MP_L2IMEMOP_SIZE 0x101a10 +#define L2IMEMOP_SIZE_SRC_OFFSET_SHIFT 8 +#define L2IMEMOP_SIZE_SRC_OFFSET_MASK 0x3ff +#define L2IMEMOP_SIZE_SRC_COUNT_SHIFT 24 +#define L2IMEMOP_SIZE_SRC_COUNT_MASK 0xff +#define XUSB_CSB_MP_L2IMEMOP_TRIG 0x101a14 +#define L2IMEMOP_ACTION_SHIFT 24 +#define L2IMEMOP_INVALIDATE_ALL (0x40 << L2IMEMOP_ACTION_SHIFT) +#define L2IMEMOP_LOAD_LOCKED_RESULT (0x11 << L2IMEMOP_ACTION_SHIFT) +#define XUSB_CSB_MP_APMAP 0x10181c +#define APMAP_BOOTPATH BIT(31) + +#define IMEM_BLOCK_SIZE 256 + +struct tegra_xusb_fw_header { + u32 boot_loadaddr_in_imem; + u32 boot_codedfi_offset; + u32 boot_codetag; + u32 boot_codesize; + u32 phys_memaddr; + u16 reqphys_memsize; + u16 alloc_phys_memsize; + u32 rodata_img_offset; + u32 rodata_section_start; + u32 rodata_section_end; + u32 main_fnaddr; + u32 fwimg_cksum; + u32 fwimg_created_time; + u32 imem_resident_start; + u32 imem_resident_end; + u32 idirect_start; + u32 idirect_end; + u32 l2_imem_start; + u32 l2_imem_end; + u32 version_id; + u8 init_ddirect; + u8 reserved[3]; + u32 phys_addr_log_buffer; + u32 total_log_entries; + u32 dequeue_ptr; + u32 dummy_var[2]; + u32 fwimg_len; + u8 magic[8]; + u32 ss_low_power_entry_timeout; + u8 num_hsic_port; + u8 padding[139]; /* Pad to 256 bytes */ +}; + +struct tegra_xusb_phy_type { + const char *name; + unsigned int num; +}; + +struct tegra_xusb_soc { + const char *firmware; + const char * const *supply_names; + unsigned int num_supplies; + const struct tegra_xusb_phy_type *phy_types; + unsigned int num_types; + + struct { + struct { + unsigned int offset; + unsigned int count; + } usb2, ulpi, hsic, usb3; + } ports; + + bool scale_ss_clock; +}; + +struct tegra_xusb { + struct device *dev; + void __iomem *regs; + struct usb_hcd *hcd; + + struct mutex lock; + + int xhci_irq; + int mbox_irq; + + void __iomem *ipfs_base; + void __iomem *fpci_base; + + const struct tegra_xusb_soc *soc; + + struct regulator_bulk_data *supplies; + + struct tegra_xusb_padctl *padctl; + + struct clk *host_clk; + struct clk *falcon_clk; + struct clk *ss_clk; + struct clk *ss_src_clk; + struct clk *hs_src_clk; + struct clk *fs_src_clk; + struct clk *pll_u_480m; + struct clk *clk_m; + struct clk *pll_e; + + struct reset_control *host_rst; + struct reset_control *ss_rst; + + struct phy **phys; + unsigned int num_phys; + + /* Firmware loading related */ + struct { + size_t size; + void *virt; + dma_addr_t phys; + } fw; +}; + +static struct hc_driver __read_mostly tegra_xhci_hc_driver; + +static inline u32 fpci_readl(struct tegra_xusb *tegra, unsigned int offset) +{ + return readl(tegra->fpci_base + offset); +} + +static inline void fpci_writel(struct tegra_xusb *tegra, u32 value, + unsigned int offset) +{ + writel(value, tegra->fpci_base + offset); +} + +static inline u32 ipfs_readl(struct tegra_xusb *tegra, unsigned int offset) +{ + return readl(tegra->ipfs_base + offset); +} + +static inline void ipfs_writel(struct tegra_xusb *tegra, u32 value, + unsigned int offset) +{ + writel(value, tegra->ipfs_base + offset); +} + +static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset) +{ + u32 page = CSB_PAGE_SELECT(offset); + u32 ofs = CSB_PAGE_OFFSET(offset); + + fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE); + + return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + ofs); +} + +static void csb_writel(struct tegra_xusb *tegra, u32 value, + unsigned int offset) +{ + u32 page = CSB_PAGE_SELECT(offset); + u32 ofs = CSB_PAGE_OFFSET(offset); + + fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE); + fpci_writel(tegra, value, XUSB_CFG_CSB_BASE_ADDR + ofs); +} + +static int tegra_xusb_set_ss_clk(struct tegra_xusb *tegra, + unsigned long rate) +{ + unsigned long new_parent_rate, old_parent_rate; + struct clk *clk = tegra->ss_src_clk; + unsigned int div; + int err; + + if (clk_get_rate(clk) == rate) + return 0; + + switch (rate) { + case TEGRA_XHCI_SS_HIGH_SPEED: + /* + * Reparent to PLLU_480M. Set divider first to avoid + * overclocking. + */ + old_parent_rate = clk_get_rate(clk_get_parent(clk)); + new_parent_rate = clk_get_rate(tegra->pll_u_480m); + div = new_parent_rate / rate; + + err = clk_set_rate(clk, old_parent_rate / div); + if (err) + return err; + + err = clk_set_parent(clk, tegra->pll_u_480m); + if (err) + return err; + + /* + * The rate should already be correct, but set it again just + * to be sure. + */ + err = clk_set_rate(clk, rate); + if (err) + return err; + + break; + + case TEGRA_XHCI_SS_LOW_SPEED: + /* Reparent to CLK_M */ + err = clk_set_parent(clk, tegra->clk_m); + if (err) + return err; + + err = clk_set_rate(clk, rate); + if (err) + return err; + + break; + + default: + dev_err(tegra->dev, "Invalid SS rate: %lu Hz\n", rate); + return -EINVAL; + } + + if (clk_get_rate(clk) != rate) { + dev_err(tegra->dev, "SS clock doesn't match requested rate\n"); + return -EINVAL; + } + + return 0; +} + +static unsigned long extract_field(u32 value, unsigned int start, + unsigned int count) +{ + return (value >> start) & ((1 << count) - 1); +} + +/* Command requests from the firmware */ +enum tegra_xusb_mbox_cmd { + MBOX_CMD_MSG_ENABLED = 1, + MBOX_CMD_INC_FALC_CLOCK, + MBOX_CMD_DEC_FALC_CLOCK, + MBOX_CMD_INC_SSPI_CLOCK, + MBOX_CMD_DEC_SSPI_CLOCK, + MBOX_CMD_SET_BW, /* no ACK/NAK required */ + MBOX_CMD_SET_SS_PWR_GATING, + MBOX_CMD_SET_SS_PWR_UNGATING, + MBOX_CMD_SAVE_DFE_CTLE_CTX, + MBOX_CMD_AIRPLANE_MODE_ENABLED, /* unused */ + MBOX_CMD_AIRPLANE_MODE_DISABLED, /* unused */ + MBOX_CMD_START_HSIC_IDLE, + MBOX_CMD_STOP_HSIC_IDLE, + MBOX_CMD_DBC_WAKE_STACK, /* unused */ + MBOX_CMD_HSIC_PRETEND_CONNECT, + MBOX_CMD_RESET_SSPI, + MBOX_CMD_DISABLE_SS_LFPS_DETECTION, + MBOX_CMD_ENABLE_SS_LFPS_DETECTION, + + MBOX_CMD_MAX, + + /* Response message to above commands */ + MBOX_CMD_ACK = 128, + MBOX_CMD_NAK +}; + +static const char * const mbox_cmd_name[] = { + [ 1] = "MSG_ENABLE", + [ 2] = "INC_FALCON_CLOCK", + [ 3] = "DEC_FALCON_CLOCK", + [ 4] = "INC_SSPI_CLOCK", + [ 5] = "DEC_SSPI_CLOCK", + [ 6] = "SET_BW", + [ 7] = "SET_SS_PWR_GATING", + [ 8] = "SET_SS_PWR_UNGATING", + [ 9] = "SAVE_DFE_CTLE_CTX", + [ 10] = "AIRPLANE_MODE_ENABLED", + [ 11] = "AIRPLANE_MODE_DISABLED", + [ 12] = "START_HSIC_IDLE", + [ 13] = "STOP_HSIC_IDLE", + [ 14] = "DBC_WAKE_STACK", + [ 15] = "HSIC_PRETEND_CONNECT", + [ 16] = "RESET_SSPI", + [ 17] = "DISABLE_SS_LFPS_DETECTION", + [ 18] = "ENABLE_SS_LFPS_DETECTION", + [128] = "ACK", + [129] = "NAK", +}; + +struct tegra_xusb_mbox_msg { + u32 cmd; + u32 data; +}; + +static inline u32 tegra_xusb_mbox_pack(const struct tegra_xusb_mbox_msg *msg) +{ + return (msg->cmd & CMD_TYPE_MASK) << CMD_TYPE_SHIFT | + (msg->data & CMD_DATA_MASK) << CMD_DATA_SHIFT; +} +static inline void tegra_xusb_mbox_unpack(struct tegra_xusb_mbox_msg *msg, + u32 value) +{ + msg->cmd = (value >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK; + msg->data = (value >> CMD_DATA_SHIFT) & CMD_DATA_MASK; +} + +static bool tegra_xusb_mbox_cmd_requires_ack(enum tegra_xusb_mbox_cmd cmd) +{ + switch (cmd) { + case MBOX_CMD_SET_BW: + case MBOX_CMD_ACK: + case MBOX_CMD_NAK: + return false; + + default: + return true; + } +} + +static int tegra_xusb_mbox_send(struct tegra_xusb *tegra, + const struct tegra_xusb_mbox_msg *msg) +{ + bool wait_for_idle = false; + u32 value; + + /* + * Acquire the mailbox. The firmware still owns the mailbox for + * ACK/NAK messages. + */ + if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) { + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + if (value != MBOX_OWNER_NONE) { + dev_err(tegra->dev, "mailbox is busy\n"); + return -EBUSY; + } + + fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER); + + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + if (value != MBOX_OWNER_SW) { + dev_err(tegra->dev, "failed to acquire mailbox\n"); + return -EBUSY; + } + + wait_for_idle = true; + } + + value = tegra_xusb_mbox_pack(msg); + fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_DATA_IN); + + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); + value |= MBOX_INT_EN | MBOX_DEST_FALC; + fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); + + if (wait_for_idle) { + unsigned long timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + if (value == MBOX_OWNER_NONE) + break; + + usleep_range(10, 20); + } + + if (time_after(jiffies, timeout)) + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + + if (value != MBOX_OWNER_NONE) + return -ETIMEDOUT; + } + + return 0; +} + +static irqreturn_t tegra_xusb_mbox_irq(int irq, void *data) +{ + struct tegra_xusb *tegra = data; + u32 value; + + /* clear mailbox interrupts */ + value = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR); + fpci_writel(tegra, value, XUSB_CFG_ARU_SMI_INTR); + + if (value & MBOX_SMI_INTR_FW_HANG) + dev_err(tegra->dev, "controller firmware hang\n"); + + return IRQ_WAKE_THREAD; +} + +static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra, + const struct tegra_xusb_mbox_msg *msg) +{ + struct tegra_xusb_padctl *padctl = tegra->padctl; + const struct tegra_xusb_soc *soc = tegra->soc; + struct device *dev = tegra->dev; + struct tegra_xusb_mbox_msg rsp; + unsigned long mask; + unsigned int port; + bool idle, enable; + int err; + + memset(&rsp, 0, sizeof(rsp)); + + switch (msg->cmd) { + case MBOX_CMD_INC_FALC_CLOCK: + case MBOX_CMD_DEC_FALC_CLOCK: + rsp.data = clk_get_rate(tegra->falcon_clk) / 1000; + if (rsp.data != msg->data) + rsp.cmd = MBOX_CMD_NAK; + else + rsp.cmd = MBOX_CMD_ACK; + + break; + + case MBOX_CMD_INC_SSPI_CLOCK: + case MBOX_CMD_DEC_SSPI_CLOCK: + if (tegra->soc->scale_ss_clock) { + err = tegra_xusb_set_ss_clk(tegra, msg->data * 1000); + if (err < 0) + rsp.cmd = MBOX_CMD_NAK; + else + rsp.cmd = MBOX_CMD_ACK; + + rsp.data = clk_get_rate(tegra->ss_src_clk) / 1000; + } else { + rsp.cmd = MBOX_CMD_ACK; + rsp.data = msg->data; + } + + break; + + case MBOX_CMD_SET_BW: + /* + * TODO: Request bandwidth once EMC scaling is supported. + * Ignore for now since ACK/NAK is not required for SET_BW + * messages. + */ + break; + + case MBOX_CMD_SAVE_DFE_CTLE_CTX: + err = tegra_xusb_padctl_usb3_save_context(padctl, msg->data); + if (err < 0) { + dev_err(dev, "failed to save context for USB3#%u: %d\n", + msg->data, err); + rsp.cmd = MBOX_CMD_NAK; + } else { + rsp.cmd = MBOX_CMD_ACK; + } + + rsp.data = msg->data; + break; + + case MBOX_CMD_START_HSIC_IDLE: + case MBOX_CMD_STOP_HSIC_IDLE: + if (msg->cmd == MBOX_CMD_STOP_HSIC_IDLE) + idle = false; + else + idle = true; + + mask = extract_field(msg->data, 1 + soc->ports.hsic.offset, + soc->ports.hsic.count); + + for_each_set_bit(port, &mask, 32) { + err = tegra_xusb_padctl_hsic_set_idle(padctl, port, + idle); + if (err < 0) + break; + } + + if (err < 0) { + dev_err(dev, "failed to set HSIC#%u %s: %d\n", port, + idle ? "idle" : "busy", err); + rsp.cmd = MBOX_CMD_NAK; + } else { + rsp.cmd = MBOX_CMD_ACK; + } + + rsp.data = msg->data; + break; + + case MBOX_CMD_DISABLE_SS_LFPS_DETECTION: + case MBOX_CMD_ENABLE_SS_LFPS_DETECTION: + if (msg->cmd == MBOX_CMD_DISABLE_SS_LFPS_DETECTION) + enable = false; + else + enable = true; + + mask = extract_field(msg->data, 1 + soc->ports.usb3.offset, + soc->ports.usb3.count); + + for_each_set_bit(port, &mask, soc->ports.usb3.count) { + err = tegra_xusb_padctl_usb3_set_lfps_detect(padctl, + port, + enable); + if (err < 0) + break; + } + + if (err < 0) { + dev_err(dev, + "failed to %s LFPS detection on USB3#%u: %d\n", + enable ? "enable" : "disable", port, err); + rsp.cmd = MBOX_CMD_NAK; + } else { + rsp.cmd = MBOX_CMD_ACK; + } + + rsp.data = msg->data; + break; + + default: + dev_warn(dev, "unknown message: %#x\n", msg->cmd); + break; + } + + if (rsp.cmd) { + const char *cmd = (rsp.cmd == MBOX_CMD_ACK) ? "ACK" : "NAK"; + + err = tegra_xusb_mbox_send(tegra, &rsp); + if (err < 0) + dev_err(dev, "failed to send %s: %d\n", cmd, err); + } +} + +static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data) +{ + struct tegra_xusb *tegra = data; + struct tegra_xusb_mbox_msg msg; + u32 value; + + mutex_lock(&tegra->lock); + + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT); + tegra_xusb_mbox_unpack(&msg, value); + + value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); + value &= ~MBOX_DEST_SMI; + fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); + + /* clear mailbox owner if no ACK/NAK is required */ + if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd)) + fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER); + + tegra_xusb_mbox_handle(tegra, &msg); + + mutex_unlock(&tegra->lock); + return IRQ_HANDLED; +} + +static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra, + struct resource *regs) +{ + u32 value; + + value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); + value |= IPFS_EN_FPCI; + ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); + + usleep_range(10, 20); + + /* Program BAR0 space */ + value = fpci_readl(tegra, XUSB_CFG_4); + value &= ~(XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); + value |= regs->start & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT); + fpci_writel(tegra, value, XUSB_CFG_4); + + usleep_range(100, 200); + + /* Enable bus master */ + value = fpci_readl(tegra, XUSB_CFG_1); + value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN; + fpci_writel(tegra, value, XUSB_CFG_1); + + /* Enable interrupt assertion */ + value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); + value |= IPFS_IP_INT_MASK; + ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); + + /* Set hysteresis */ + ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); +} + +static int tegra_xusb_clk_enable(struct tegra_xusb *tegra) +{ + int err; + + err = clk_prepare_enable(tegra->pll_e); + if (err < 0) + return err; + + err = clk_prepare_enable(tegra->host_clk); + if (err < 0) + goto disable_plle; + + err = clk_prepare_enable(tegra->ss_clk); + if (err < 0) + goto disable_host; + + err = clk_prepare_enable(tegra->falcon_clk); + if (err < 0) + goto disable_ss; + + err = clk_prepare_enable(tegra->fs_src_clk); + if (err < 0) + goto disable_falc; + + err = clk_prepare_enable(tegra->hs_src_clk); + if (err < 0) + goto disable_fs_src; + + if (tegra->soc->scale_ss_clock) { + err = tegra_xusb_set_ss_clk(tegra, TEGRA_XHCI_SS_HIGH_SPEED); + if (err < 0) + goto disable_hs_src; + } + + return 0; + +disable_hs_src: + clk_disable_unprepare(tegra->hs_src_clk); +disable_fs_src: + clk_disable_unprepare(tegra->fs_src_clk); +disable_falc: + clk_disable_unprepare(tegra->falcon_clk); +disable_ss: + clk_disable_unprepare(tegra->ss_clk); +disable_host: + clk_disable_unprepare(tegra->host_clk); +disable_plle: + clk_disable_unprepare(tegra->pll_e); + return err; +} + +static void tegra_xusb_clk_disable(struct tegra_xusb *tegra) +{ + clk_disable_unprepare(tegra->pll_e); + clk_disable_unprepare(tegra->host_clk); + clk_disable_unprepare(tegra->ss_clk); + clk_disable_unprepare(tegra->falcon_clk); + clk_disable_unprepare(tegra->fs_src_clk); + clk_disable_unprepare(tegra->hs_src_clk); +} + +static int tegra_xusb_phy_enable(struct tegra_xusb *tegra) +{ + unsigned int i; + int err; + + for (i = 0; i < tegra->num_phys; i++) { + err = phy_init(tegra->phys[i]); + if (err) + goto disable_phy; + + err = phy_power_on(tegra->phys[i]); + if (err) { + phy_exit(tegra->phys[i]); + goto disable_phy; + } + } + + return 0; + +disable_phy: + while (i--) { + phy_power_off(tegra->phys[i]); + phy_exit(tegra->phys[i]); + } + + return err; +} + +static void tegra_xusb_phy_disable(struct tegra_xusb *tegra) +{ + unsigned int i; + + for (i = 0; i < tegra->num_phys; i++) { + phy_power_off(tegra->phys[i]); + phy_exit(tegra->phys[i]); + } +} + +static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) +{ + unsigned int code_tag_blocks, code_size_blocks, code_blocks; + struct tegra_xusb_fw_header *header; + struct device *dev = tegra->dev; + const struct firmware *fw; + unsigned long timeout; + time_t timestamp; + struct tm time; + u64 address; + u32 value; + int err; + + err = request_firmware(&fw, tegra->soc->firmware, tegra->dev); + if (err < 0) { + dev_err(tegra->dev, "failed to request firmware: %d\n", err); + return err; + } + + /* Load Falcon controller with its firmware. */ + header = (struct tegra_xusb_fw_header *)fw->data; + tegra->fw.size = le32_to_cpu(header->fwimg_len); + + tegra->fw.virt = dma_alloc_coherent(tegra->dev, tegra->fw.size, + &tegra->fw.phys, GFP_KERNEL); + if (!tegra->fw.virt) { + dev_err(tegra->dev, "failed to allocate memory for firmware\n"); + release_firmware(fw); + return -ENOMEM; + } + + header = (struct tegra_xusb_fw_header *)tegra->fw.virt; + memcpy(tegra->fw.virt, fw->data, tegra->fw.size); + release_firmware(fw); + + if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) { + dev_info(dev, "Firmware already loaded, Falcon state %#x\n", + csb_readl(tegra, XUSB_FALC_CPUCTL)); + return 0; + } + + /* Program the size of DFI into ILOAD_ATTR. */ + csb_writel(tegra, tegra->fw.size, XUSB_CSB_MP_ILOAD_ATTR); + + /* + * Boot code of the firmware reads the ILOAD_BASE registers + * to get to the start of the DFI in system memory. + */ + address = tegra->fw.phys + sizeof(*header); + csb_writel(tegra, address >> 32, XUSB_CSB_MP_ILOAD_BASE_HI); + csb_writel(tegra, address, XUSB_CSB_MP_ILOAD_BASE_LO); + + /* Set BOOTPATH to 1 in APMAP. */ + csb_writel(tegra, APMAP_BOOTPATH, XUSB_CSB_MP_APMAP); + + /* Invalidate L2IMEM. */ + csb_writel(tegra, L2IMEMOP_INVALIDATE_ALL, XUSB_CSB_MP_L2IMEMOP_TRIG); + + /* + * Initiate fetch of bootcode from system memory into L2IMEM. + * Program bootcode location and size in system memory. + */ + code_tag_blocks = DIV_ROUND_UP(le32_to_cpu(header->boot_codetag), + IMEM_BLOCK_SIZE); + code_size_blocks = DIV_ROUND_UP(le32_to_cpu(header->boot_codesize), + IMEM_BLOCK_SIZE); + code_blocks = code_tag_blocks + code_size_blocks; + + value = ((code_tag_blocks & L2IMEMOP_SIZE_SRC_OFFSET_MASK) << + L2IMEMOP_SIZE_SRC_OFFSET_SHIFT) | + ((code_size_blocks & L2IMEMOP_SIZE_SRC_COUNT_MASK) << + L2IMEMOP_SIZE_SRC_COUNT_SHIFT); + csb_writel(tegra, value, XUSB_CSB_MP_L2IMEMOP_SIZE); + + /* Trigger L2IMEM load operation. */ + csb_writel(tegra, L2IMEMOP_LOAD_LOCKED_RESULT, + XUSB_CSB_MP_L2IMEMOP_TRIG); + + /* Setup Falcon auto-fill. */ + csb_writel(tegra, code_size_blocks, XUSB_FALC_IMFILLCTL); + + value = ((code_tag_blocks & IMFILLRNG1_TAG_MASK) << + IMFILLRNG1_TAG_LO_SHIFT) | + ((code_blocks & IMFILLRNG1_TAG_MASK) << + IMFILLRNG1_TAG_HI_SHIFT); + csb_writel(tegra, value, XUSB_FALC_IMFILLRNG1); + + csb_writel(tegra, 0, XUSB_FALC_DMACTL); + + msleep(50); + + csb_writel(tegra, le32_to_cpu(header->boot_codetag), + XUSB_FALC_BOOTVEC); + + /* Boot Falcon CPU and wait for it to enter the STOPPED (idle) state. */ + timeout = jiffies + msecs_to_jiffies(5); + + csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); + + while (time_before(jiffies, timeout)) { + if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_STOPPED) + break; + + usleep_range(100, 200); + } + + if (csb_readl(tegra, XUSB_FALC_CPUCTL) != CPUCTL_STATE_STOPPED) { + dev_err(dev, "Falcon failed to start, state: %#x\n", + csb_readl(tegra, XUSB_FALC_CPUCTL)); + return -EIO; + } + + timestamp = le32_to_cpu(header->fwimg_created_time); + time_to_tm(timestamp, 0, &time); + + dev_info(dev, "Firmware timestamp: %ld-%02d-%02d %02d:%02d:%02d UTC\n", + time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + + return 0; +} + +static int tegra_xusb_probe(struct platform_device *pdev) +{ + struct tegra_xusb_mbox_msg msg; + struct resource *res, *regs; + struct tegra_xusb *tegra; + struct xhci_hcd *xhci; + unsigned int i, j, k; + struct phy *phy; + int err; + + BUILD_BUG_ON(sizeof(struct tegra_xusb_fw_header) != 256); + + tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); + if (!tegra) + return -ENOMEM; + + tegra->soc = of_device_get_match_data(&pdev->dev); + mutex_init(&tegra->lock); + tegra->dev = &pdev->dev; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tegra->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(tegra->regs)) + return PTR_ERR(tegra->regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->fpci_base)) + return PTR_ERR(tegra->fpci_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(tegra->ipfs_base)) + return PTR_ERR(tegra->ipfs_base); + + tegra->xhci_irq = platform_get_irq(pdev, 0); + if (tegra->xhci_irq < 0) + return tegra->xhci_irq; + + tegra->mbox_irq = platform_get_irq(pdev, 1); + if (tegra->mbox_irq < 0) + return tegra->mbox_irq; + + tegra->padctl = tegra_xusb_padctl_get(&pdev->dev); + if (IS_ERR(tegra->padctl)) + return PTR_ERR(tegra->padctl); + + tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host"); + if (IS_ERR(tegra->host_rst)) { + err = PTR_ERR(tegra->host_rst); + dev_err(&pdev->dev, "failed to get xusb_host reset: %d\n", err); + goto put_padctl; + } + + tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss"); + if (IS_ERR(tegra->ss_rst)) { + err = PTR_ERR(tegra->ss_rst); + dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n", err); + goto put_padctl; + } + + tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host"); + if (IS_ERR(tegra->host_clk)) { + err = PTR_ERR(tegra->host_clk); + dev_err(&pdev->dev, "failed to get xusb_host: %d\n", err); + goto put_padctl; + } + + tegra->falcon_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src"); + if (IS_ERR(tegra->falcon_clk)) { + err = PTR_ERR(tegra->falcon_clk); + dev_err(&pdev->dev, "failed to get xusb_falcon_src: %d\n", err); + goto put_padctl; + } + + tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss"); + if (IS_ERR(tegra->ss_clk)) { + err = PTR_ERR(tegra->ss_clk); + dev_err(&pdev->dev, "failed to get xusb_ss: %d\n", err); + goto put_padctl; + } + + tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src"); + if (IS_ERR(tegra->ss_src_clk)) { + err = PTR_ERR(tegra->ss_src_clk); + dev_err(&pdev->dev, "failed to get xusb_ss_src: %d\n", err); + goto put_padctl; + } + + tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src"); + if (IS_ERR(tegra->hs_src_clk)) { + err = PTR_ERR(tegra->hs_src_clk); + dev_err(&pdev->dev, "failed to get xusb_hs_src: %d\n", err); + goto put_padctl; + } + + tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src"); + if (IS_ERR(tegra->fs_src_clk)) { + err = PTR_ERR(tegra->fs_src_clk); + dev_err(&pdev->dev, "failed to get xusb_fs_src: %d\n", err); + goto put_padctl; + } + + tegra->pll_u_480m = devm_clk_get(&pdev->dev, "pll_u_480m"); + if (IS_ERR(tegra->pll_u_480m)) { + err = PTR_ERR(tegra->pll_u_480m); + dev_err(&pdev->dev, "failed to get pll_u_480m: %d\n", err); + goto put_padctl; + } + + tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m"); + if (IS_ERR(tegra->clk_m)) { + err = PTR_ERR(tegra->clk_m); + dev_err(&pdev->dev, "failed to get clk_m: %d\n", err); + goto put_padctl; + } + + tegra->pll_e = devm_clk_get(&pdev->dev, "pll_e"); + if (IS_ERR(tegra->pll_e)) { + err = PTR_ERR(tegra->pll_e); + dev_err(&pdev->dev, "failed to get pll_e: %d\n", err); + goto put_padctl; + } + + tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies, + sizeof(*tegra->supplies), GFP_KERNEL); + if (!tegra->supplies) { + err = -ENOMEM; + goto put_padctl; + } + + for (i = 0; i < tegra->soc->num_supplies; i++) + tegra->supplies[i].supply = tegra->soc->supply_names[i]; + + err = devm_regulator_bulk_get(&pdev->dev, tegra->soc->num_supplies, + tegra->supplies); + if (err) { + dev_err(&pdev->dev, "failed to get regulators: %d\n", err); + goto put_padctl; + } + + for (i = 0; i < tegra->soc->num_types; i++) + tegra->num_phys += tegra->soc->phy_types[i].num; + + tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys, + sizeof(*tegra->phys), GFP_KERNEL); + if (!tegra->phys) { + dev_err(&pdev->dev, "failed to allocate PHY array\n"); + err = -ENOMEM; + goto put_padctl; + } + + for (i = 0, k = 0; i < tegra->soc->num_types; i++) { + char prop[8]; + + for (j = 0; j < tegra->soc->phy_types[i].num; j++) { + snprintf(prop, sizeof(prop), "%s-%d", + tegra->soc->phy_types[i].name, j); + + phy = devm_phy_optional_get(&pdev->dev, prop); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, + "failed to get PHY %s: %ld\n", prop, + PTR_ERR(phy)); + err = PTR_ERR(phy); + goto put_padctl; + } + + tegra->phys[k++] = phy; + } + } + + err = tegra_xusb_clk_enable(tegra); + if (err) { + dev_err(&pdev->dev, "failed to enable clocks: %d\n", err); + goto put_padctl; + } + + err = regulator_bulk_enable(tegra->soc->num_supplies, tegra->supplies); + if (err) { + dev_err(&pdev->dev, "failed to enable regulators: %d\n", err); + goto disable_clk; + } + + err = tegra_xusb_phy_enable(tegra); + if (err < 0) { + dev_err(&pdev->dev, "failed to enable PHYs: %d\n", err); + goto disable_regulator; + } + + tegra_xusb_ipfs_config(tegra, regs); + + err = tegra_xusb_load_firmware(tegra); + if (err < 0) { + dev_err(&pdev->dev, "failed to load firmware: %d\n", err); + goto disable_phy; + } + + tegra->hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!tegra->hcd) { + err = -ENOMEM; + goto disable_phy; + } + + /* + * This must happen after usb_create_hcd(), because usb_create_hcd() + * will overwrite the drvdata of the device with the hcd it creates. + */ + platform_set_drvdata(pdev, tegra); + + tegra->hcd->regs = tegra->regs; + tegra->hcd->rsrc_start = regs->start; + tegra->hcd->rsrc_len = resource_size(regs); + + err = usb_add_hcd(tegra->hcd, tegra->xhci_irq, IRQF_SHARED); + if (err < 0) { + dev_err(&pdev->dev, "failed to add USB HCD: %d\n", err); + goto put_usb2; + } + + device_wakeup_enable(tegra->hcd->self.controller); + + xhci = hcd_to_xhci(tegra->hcd); + + xhci->shared_hcd = usb_create_shared_hcd(&tegra_xhci_hc_driver, + &pdev->dev, + dev_name(&pdev->dev), + tegra->hcd); + if (!xhci->shared_hcd) { + dev_err(&pdev->dev, "failed to create shared HCD\n"); + goto remove_usb2; + } + + err = usb_add_hcd(xhci->shared_hcd, tegra->xhci_irq, IRQF_SHARED); + if (err < 0) { + dev_err(&pdev->dev, "failed to add shared HCD: %d\n", err); + goto put_usb3; + } + + mutex_lock(&tegra->lock); + + /* Enable firmware messages from controller. */ + msg.cmd = MBOX_CMD_MSG_ENABLED; + msg.data = 0; + + err = tegra_xusb_mbox_send(tegra, &msg); + if (err < 0) { + dev_err(&pdev->dev, "failed to enable messages: %d\n", err); + mutex_unlock(&tegra->lock); + goto remove_usb3; + } + + mutex_unlock(&tegra->lock); + + err = devm_request_threaded_irq(&pdev->dev, tegra->mbox_irq, + tegra_xusb_mbox_irq, + tegra_xusb_mbox_thread, 0, + dev_name(&pdev->dev), tegra); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); + goto remove_usb3; + } + + return 0; + +remove_usb3: + usb_remove_hcd(xhci->shared_hcd); +put_usb3: + usb_put_hcd(xhci->shared_hcd); +remove_usb2: + usb_remove_hcd(tegra->hcd); +put_usb2: + usb_put_hcd(tegra->hcd); +disable_phy: + tegra_xusb_phy_disable(tegra); +disable_regulator: + regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); +disable_clk: + tegra_xusb_clk_disable(tegra); +put_padctl: + tegra_xusb_padctl_put(tegra->padctl); + return err; +} + +static int tegra_xusb_remove(struct platform_device *pdev) +{ + struct tegra_xusb *tegra = platform_get_drvdata(pdev); + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); + + usb_remove_hcd(xhci->shared_hcd); + usb_put_hcd(xhci->shared_hcd); + usb_remove_hcd(tegra->hcd); + usb_put_hcd(tegra->hcd); + + dma_free_coherent(&pdev->dev, tegra->fw.size, tegra->fw.virt, + tegra->fw.phys); + + tegra_xusb_phy_disable(tegra); + regulator_bulk_disable(tegra->soc->num_supplies, tegra->supplies); + tegra_xusb_clk_disable(tegra); + + tegra_xusb_padctl_put(tegra->padctl); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int tegra_xusb_suspend(struct device *dev) +{ + struct tegra_xusb *tegra = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); + bool wakeup = device_may_wakeup(dev); + + /* TODO: Powergate controller across suspend/resume. */ + return xhci_suspend(xhci, wakeup); +} + +static int tegra_xusb_resume(struct device *dev) +{ + struct tegra_xusb *tegra = dev_get_drvdata(dev); + struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd); + + return xhci_resume(xhci, 0); +} +#endif + +static const struct dev_pm_ops tegra_xusb_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_xusb_suspend, tegra_xusb_resume) +}; + +static const char * const tegra124_supply_names[] = { + "avddio-pex", + "dvddio-pex", + "avdd-usb", + "avdd-pll-utmip", + "avdd-pll-erefe", + "avdd-usb-ss-pll", + "hvdd-usb-ss", + "hvdd-usb-ss-pll-e", +}; + +static const struct tegra_xusb_phy_type tegra124_phy_types[] = { + { .name = "usb3", .num = 2, }, + { .name = "usb2", .num = 3, }, + { .name = "hsic", .num = 2, }, +}; + +static const struct tegra_xusb_soc tegra124_soc = { + .firmware = "nvidia/tegra124/xusb.bin", + .supply_names = tegra124_supply_names, + .num_supplies = ARRAY_SIZE(tegra124_supply_names), + .phy_types = tegra124_phy_types, + .num_types = ARRAY_SIZE(tegra124_phy_types), + .ports = { + .usb2 = { .offset = 4, .count = 4, }, + .hsic = { .offset = 6, .count = 2, }, + .usb3 = { .offset = 0, .count = 2, }, + }, + .scale_ss_clock = true, +}; +MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); + +static const char * const tegra210_supply_names[] = { + "dvddio-pex", + "hvddio-pex", + "avdd-usb", + "avdd-pll-utmip", + "avdd-pll-uerefe", + "dvdd-pex-pll", + "hvdd-pex-pll-e", +}; + +static const struct tegra_xusb_phy_type tegra210_phy_types[] = { + { .name = "usb3", .num = 4, }, + { .name = "usb2", .num = 4, }, + { .name = "hsic", .num = 1, }, +}; + +static const struct tegra_xusb_soc tegra210_soc = { + .firmware = "nvidia/tegra210/xusb.bin", + .supply_names = tegra210_supply_names, + .num_supplies = ARRAY_SIZE(tegra210_supply_names), + .phy_types = tegra210_phy_types, + .num_types = ARRAY_SIZE(tegra210_phy_types), + .ports = { + .usb2 = { .offset = 4, .count = 4, }, + .hsic = { .offset = 8, .count = 1, }, + .usb3 = { .offset = 0, .count = 4, }, + }, + .scale_ss_clock = false, +}; +MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); + +static const struct of_device_id tegra_xusb_of_match[] = { + { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, + { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); + +static struct platform_driver tegra_xusb_driver = { + .probe = tegra_xusb_probe, + .remove = tegra_xusb_remove, + .driver = { + .name = "tegra-xusb", + .pm = &tegra_xusb_pm_ops, + .of_match_table = tegra_xusb_of_match, + }, +}; + +static void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci) +{ + xhci->quirks |= XHCI_PLAT; +} + +static int tegra_xhci_setup(struct usb_hcd *hcd) +{ + return xhci_gen_setup(hcd, tegra_xhci_quirks); +} + +static const struct xhci_driver_overrides tegra_xhci_overrides __initconst = { + .extra_priv_size = sizeof(struct xhci_hcd), + .reset = tegra_xhci_setup, +}; + +static int __init tegra_xusb_init(void) +{ + xhci_init_driver(&tegra_xhci_hc_driver, &tegra_xhci_overrides); + + return platform_driver_register(&tegra_xusb_driver); +} +module_init(tegra_xusb_init); + +static void __exit tegra_xusb_exit(void) +{ + platform_driver_unregister(&tegra_xusb_driver); +} +module_exit(tegra_xusb_exit); + +MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); +MODULE_DESCRIPTION("NVIDIA Tegra XUSB xHCI host-controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9e71c96ad74a..f2f9518c53ab 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -685,20 +685,23 @@ void xhci_stop(struct usb_hcd *hcd) u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_HALTED) - return; - mutex_lock(&xhci->mutex); - spin_lock_irq(&xhci->lock); - xhci->xhc_state |= XHCI_STATE_HALTED; - xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; - /* Make sure the xHC is halted for a USB3 roothub - * (xhci_stop() could be called as part of failed init). - */ - xhci_halt(xhci); - xhci_reset(xhci); - spin_unlock_irq(&xhci->lock); + if (!(xhci->xhc_state & XHCI_STATE_HALTED)) { + spin_lock_irq(&xhci->lock); + + xhci->xhc_state |= XHCI_STATE_HALTED; + xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; + xhci_halt(xhci); + xhci_reset(xhci); + + spin_unlock_irq(&xhci->lock); + } + + if (!usb_hcd_is_primary_hcd(hcd)) { + mutex_unlock(&xhci->mutex); + return; + } xhci_cleanup_msix(xhci); @@ -1459,47 +1462,6 @@ free_priv: return ret; } -/* Get the right ring for the given URB. - * If the endpoint supports streams, boundary check the URB's stream ID. - * If the endpoint doesn't support streams, return the singular endpoint ring. - */ -static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, - struct urb *urb) -{ - unsigned int slot_id; - unsigned int ep_index; - unsigned int stream_id; - struct xhci_virt_ep *ep; - - slot_id = urb->dev->slot_id; - ep_index = xhci_get_endpoint_index(&urb->ep->desc); - stream_id = urb->stream_id; - ep = &xhci->devs[slot_id]->eps[ep_index]; - /* Common case: no streams */ - if (!(ep->ep_state & EP_HAS_STREAMS)) - return ep->ring; - - if (stream_id == 0) { - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has streams, " - "but URB has no stream ID.\n", - slot_id, ep_index); - return NULL; - } - - if (stream_id < ep->stream_info->num_streams) - return ep->stream_info->stream_rings[stream_id]; - - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has " - "stream IDs 1 to %u allocated, " - "but stream ID %u is requested.\n", - slot_id, ep_index, - ep->stream_info->num_streams - 1, - stream_id); - return NULL; -} - /* * Remove the URB's TD from the endpoint ring. This may cause the HC to stop * USB transfers, potentially stopping in the middle of a TRB buffer. The HC @@ -4927,7 +4889,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); xhci_print_registers(xhci); - xhci->quirks = quirks; + xhci->quirks |= quirks; get_quirks(dev, xhci); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6c629c97f8ad..b0b8d0f8791a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1338,6 +1338,9 @@ union xhci_trb { /* TRB buffer pointers can't cross 64KB boundaries */ #define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) +/* How much data is left before the 64KB boundary? */ +#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \ + (addr & (TRB_MAX_BUFF_SIZE - 1))) struct xhci_segment { union xhci_trb *trbs; @@ -1965,4 +1968,15 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_ struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); +struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, + unsigned int slot_id, unsigned int ep_index, + unsigned int stream_id); +static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, + struct urb *urb) +{ + return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id, + xhci_get_endpoint_index(&urb->ep->desc), + urb->stream_id); +} + #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c index 264be4d21706..9535b2872183 100644 --- a/drivers/usb/isp1760/isp1760-if.c +++ b/drivers/usb/isp1760/isp1760-if.c @@ -163,7 +163,7 @@ static void isp1761_pci_shutdown(struct pci_dev *dev) printk(KERN_ERR "ips1761_pci_shutdown\n"); } -static const struct pci_device_id isp1760_plx [] = { +static const struct pci_device_id isp1760_plx[] = { { .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = ~0, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index f7a7fc21be8a..e9e5ae521fa6 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -268,3 +268,29 @@ config USB_CHAOSKEY To compile this driver as a module, choose M here: the module will be called chaoskey. + +config UCSI + tristate "USB Type-C Connector System Software Interface driver" + depends on ACPI + help + UCSI driver is meant to be used as a convenience tool for desktop and + server systems that are not equipped to handle USB in device mode. It + will always select USB host role for the USB Type-C ports on systems + that provide UCSI interface. + + USB Type-C Connector System Software Interface (UCSI) is a + specification for an interface that allows the Operating System to + control the USB Type-C ports on a system. Things the need controlling + include the USB Data Role (host or device), and when USB Power + Delivery is supported, the Power Role (source or sink). With USB + Type-C connectors, when two dual role capable devices are attached + together, the data role is selected randomly. Therefore it is + important to give the OS a way to select the role. Otherwise the user + would have to unplug and replug in order in order to attempt to swap + the data and power roles. + + The UCSI specification can be downloaded from: + http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html + + To compile the driver as a module, choose M here: the module will be + called ucsi. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 45fd4ac39d3e..2769cf6351b4 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o +obj-$(CONFIG_UCSI) += ucsi.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index a22de52cb083..15666ad7c772 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2420,7 +2420,7 @@ static int sisusb_open(struct inode *inode, struct file *file) if (!sisusb->devinit) { if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH || - sisusb->sisusb_dev->speed == USB_SPEED_SUPER) { + sisusb->sisusb_dev->speed >= USB_SPEED_SUPER) { if (sisusb_init_gfxdevice(sisusb, 0)) { mutex_unlock(&sisusb->lock); dev_err(&sisusb->sisusb_dev->dev, @@ -3127,7 +3127,7 @@ static int sisusb_probe(struct usb_interface *intf, sisusb->present = 1; - if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) { + if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) { int initscreen = 1; #ifdef INCL_SISUSB_CON if (sisusb_first_vc > 0 && sisusb_last_vc > 0 && diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index ace343088915..afa853209f1d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -601,7 +601,7 @@ sisusbcon_save_screen(struct vc_data *c) /* interface routine */ static int -sisusbcon_set_palette(struct vc_data *c, unsigned char *table) +sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) { struct sisusb_usb_data *sisusb; int i, j; diff --git a/drivers/usb/misc/ucsi.c b/drivers/usb/misc/ucsi.c new file mode 100644 index 000000000000..07397bddefa3 --- /dev/null +++ b/drivers/usb/misc/ucsi.c @@ -0,0 +1,478 @@ +/* + * USB Type-C Connector System Software Interface driver + * + * Copyright (C) 2016, Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.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/platform_device.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/acpi.h> + +#include "ucsi.h" + +/* Double the time defined by MIN_TIME_TO_RESPOND_WITH_BUSY */ +#define UCSI_TIMEOUT_MS 20 + +enum ucsi_status { + UCSI_IDLE = 0, + UCSI_BUSY, + UCSI_ERROR, +}; + +struct ucsi_connector { + int num; + struct ucsi *ucsi; + struct work_struct work; + struct ucsi_connector_capability cap; +}; + +struct ucsi { + struct device *dev; + struct ucsi_data __iomem *data; + + enum ucsi_status status; + struct completion complete; + struct ucsi_capability cap; + struct ucsi_connector *connector; + + /* device lock */ + spinlock_t dev_lock; + + /* PPM Communication lock */ + struct mutex ppm_lock; + + /* PPM communication flags */ + unsigned long flags; +#define EVENT_PENDING 0 +#define COMMAND_PENDING 1 +}; + +static int ucsi_acpi_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl) +{ + uuid_le uuid = UUID_LE(0x6f8398c2, 0x7ca4, 0x11e4, + 0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f); + union acpi_object *obj; + + ucsi->data->ctrl.raw_cmd = ctrl->raw_cmd; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(ucsi->dev), uuid.b, 1, 1, NULL); + if (!obj) { + dev_err(ucsi->dev, "%s: failed to evaluate _DSM\n", __func__); + return -EIO; + } + + ACPI_FREE(obj); + return 0; +} + +static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + struct ucsi *ucsi = data; + struct ucsi_cci *cci; + + spin_lock(&ucsi->dev_lock); + + ucsi->status = UCSI_IDLE; + cci = &ucsi->data->cci; + + /* + * REVISIT: This is not documented behavior, but all known PPMs ACK + * asynchronous events by sending notification with cleared CCI. + */ + if (!ucsi->data->raw_cci) { + if (test_bit(EVENT_PENDING, &ucsi->flags)) + complete(&ucsi->complete); + else + dev_WARN(ucsi->dev, "spurious notification\n"); + goto out_unlock; + } + + if (test_bit(COMMAND_PENDING, &ucsi->flags)) { + if (cci->busy) { + ucsi->status = UCSI_BUSY; + complete(&ucsi->complete); + + goto out_unlock; + } else if (cci->ack_complete || cci->cmd_complete) { + /* Error Indication is only valid with commands */ + if (cci->error && cci->cmd_complete) + ucsi->status = UCSI_ERROR; + + ucsi->data->ctrl.raw_cmd = 0; + complete(&ucsi->complete); + } + } + + if (cci->connector_change) { + struct ucsi_connector *con; + + /* + * This is workaround for buggy PPMs that create asynchronous + * event notifications before OPM has enabled them. + */ + if (!ucsi->connector) + goto out_unlock; + + con = ucsi->connector + (cci->connector_change - 1); + + /* + * PPM will not clear the connector specific bit in Connector + * Change Indication field of CCI until the driver has ACK it, + * and the driver can not ACK it before it has been processed. + * The PPM will not generate new events before the first has + * been acknowledged, even if they are for an other connector. + * So only one event at a time. + */ + if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags)) + schedule_work(&con->work); + } +out_unlock: + spin_unlock(&ucsi->dev_lock); +} + +static int ucsi_ack(struct ucsi *ucsi, u8 cmd) +{ + struct ucsi_control ctrl; + int ret; + + ctrl.cmd.cmd = UCSI_ACK_CC_CI; + ctrl.cmd.length = 0; + ctrl.cmd.data = cmd; + ret = ucsi_acpi_cmd(ucsi, &ctrl); + if (ret) + return ret; + + /* Waiting for ACK also with ACK CMD for now */ + ret = wait_for_completion_timeout(&ucsi->complete, + msecs_to_jiffies(UCSI_TIMEOUT_MS)); + if (!ret) + return -ETIMEDOUT; + return 0; +} + +static int ucsi_run_cmd(struct ucsi *ucsi, struct ucsi_control *ctrl, + void *data, size_t size) +{ + u16 err_value = 0; + int ret; + + set_bit(COMMAND_PENDING, &ucsi->flags); + + ret = ucsi_acpi_cmd(ucsi, ctrl); + if (ret) + goto err_clear_flag; + + ret = wait_for_completion_timeout(&ucsi->complete, + msecs_to_jiffies(UCSI_TIMEOUT_MS)); + if (!ret) { + ret = -ETIMEDOUT; + goto err_clear_flag; + } + + switch (ucsi->status) { + case UCSI_IDLE: + if (data) + memcpy(data, ucsi->data->message_in, size); + + ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + break; + case UCSI_BUSY: + /* The caller decides whether to cancel or not */ + ret = -EBUSY; + goto err_clear_flag; + case UCSI_ERROR: + ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + if (ret) + goto err_clear_flag; + + ctrl->cmd.cmd = UCSI_GET_ERROR_STATUS; + ctrl->cmd.length = 0; + ctrl->cmd.data = 0; + ret = ucsi_acpi_cmd(ucsi, ctrl); + if (ret) + goto err_clear_flag; + + ret = wait_for_completion_timeout(&ucsi->complete, + msecs_to_jiffies(UCSI_TIMEOUT_MS)); + if (!ret) { + ret = -ETIMEDOUT; + goto err_clear_flag; + } + + memcpy(&err_value, ucsi->data->message_in, sizeof(err_value)); + + /* Something has really gone wrong */ + if (WARN_ON(ucsi->status == UCSI_ERROR)) { + ret = -ENODEV; + goto err_clear_flag; + } + + ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + if (ret) + goto err_clear_flag; + + switch (err_value) { + case UCSI_ERROR_INCOMPATIBLE_PARTNER: + ret = -EOPNOTSUPP; + break; + case UCSI_ERROR_CC_COMMUNICATION_ERR: + ret = -ECOMM; + break; + case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL: + ret = -EIO; + break; + case UCSI_ERROR_DEAD_BATTERY: + dev_warn(ucsi->dev, "Dead battery condition!\n"); + ret = -EPERM; + break; + /* The following mean a bug in this driver */ + case UCSI_ERROR_INVALID_CON_NUM: + case UCSI_ERROR_UNREGONIZED_CMD: + case UCSI_ERROR_INVALID_CMD_ARGUMENT: + default: + dev_warn(ucsi->dev, + "%s: possible UCSI driver bug - error %hu\n", + __func__, err_value); + ret = -EINVAL; + break; + } + break; + } + ctrl->raw_cmd = 0; +err_clear_flag: + clear_bit(COMMAND_PENDING, &ucsi->flags); + return ret; +} + +static void ucsi_connector_change(struct work_struct *work) +{ + struct ucsi_connector *con = container_of(work, struct ucsi_connector, + work); + struct ucsi_connector_status constat; + struct ucsi *ucsi = con->ucsi; + struct ucsi_control ctrl; + int ret; + + mutex_lock(&ucsi->ppm_lock); + + ctrl.cmd.cmd = UCSI_GET_CONNECTOR_STATUS; + ctrl.cmd.length = 0; + ctrl.cmd.data = con->num; + ret = ucsi_run_cmd(con->ucsi, &ctrl, &constat, sizeof(constat)); + if (ret) { + dev_err(ucsi->dev, "%s: failed to read connector status (%d)\n", + __func__, ret); + goto out_ack_event; + } + + /* Ignoring disconnections and Alternate Modes */ + if (!constat.connected || !(constat.change & + (UCSI_CONSTAT_PARTNER_CHANGE | UCSI_CONSTAT_CONNECT_CHANGE)) || + constat.partner_flags & UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE) + goto out_ack_event; + + /* If the partner got USB Host role, attempting swap */ + if (constat.partner_type & UCSI_CONSTAT_PARTNER_TYPE_DFP) { + ctrl.uor.cmd = UCSI_SET_UOR; + ctrl.uor.con_num = con->num; + ctrl.uor.role = UCSI_UOR_ROLE_DFP; + + ret = ucsi_run_cmd(con->ucsi, &ctrl, NULL, 0); + if (ret) + dev_err(ucsi->dev, "%s: failed to swap role (%d)\n", + __func__, ret); + } +out_ack_event: + ucsi_ack(ucsi, UCSI_ACK_EVENT); + clear_bit(EVENT_PENDING, &ucsi->flags); + mutex_unlock(&ucsi->ppm_lock); +} + +static int ucsi_reset_ppm(struct ucsi *ucsi) +{ + int timeout = UCSI_TIMEOUT_MS; + struct ucsi_control ctrl; + int ret; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.cmd.cmd = UCSI_PPM_RESET; + ret = ucsi_acpi_cmd(ucsi, &ctrl); + if (ret) + return ret; + + /* There is no quarantee the PPM will ever set the RESET_COMPLETE bit */ + while (!ucsi->data->cci.reset_complete && timeout--) + usleep_range(1000, 2000); + return 0; +} + +static int ucsi_init(struct ucsi *ucsi) +{ + struct ucsi_connector *con; + struct ucsi_control ctrl; + int ret; + int i; + + init_completion(&ucsi->complete); + spin_lock_init(&ucsi->dev_lock); + mutex_init(&ucsi->ppm_lock); + + /* Reset the PPM */ + ret = ucsi_reset_ppm(ucsi); + if (ret) + return ret; + + /* + * REVISIT: Executing second reset to WA an issue seen on some of the + * Broxton based platforms, where the first reset puts the PPM into a + * state where it's unable to recognise some of the commands. + */ + ret = ucsi_reset_ppm(ucsi); + if (ret) + return ret; + + mutex_lock(&ucsi->ppm_lock); + + /* Enable basic notifications */ + ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE; + ctrl.cmd.length = 0; + ctrl.cmd.data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; + ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0); + if (ret) + goto err_reset; + + /* Get PPM capabilities */ + ctrl.cmd.cmd = UCSI_GET_CAPABILITY; + ret = ucsi_run_cmd(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap)); + if (ret) + goto err_reset; + + if (!ucsi->cap.num_connectors) { + ret = -ENODEV; + goto err_reset; + } + + ucsi->connector = devm_kcalloc(ucsi->dev, ucsi->cap.num_connectors, + sizeof(*ucsi->connector), GFP_KERNEL); + if (!ucsi->connector) { + ret = -ENOMEM; + goto err_reset; + } + + for (i = 1, con = ucsi->connector; i < ucsi->cap.num_connectors + 1; + i++, con++) { + /* Get connector capability */ + ctrl.cmd.cmd = UCSI_GET_CONNECTOR_CAPABILITY; + ctrl.cmd.data = i; + ret = ucsi_run_cmd(ucsi, &ctrl, &con->cap, sizeof(con->cap)); + if (ret) + goto err_reset; + + con->num = i; + con->ucsi = ucsi; + INIT_WORK(&con->work, ucsi_connector_change); + } + + /* Enable all notifications */ + ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE; + ctrl.cmd.data = UCSI_ENABLE_NTFY_ALL; + ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0); + if (ret < 0) + goto err_reset; + + mutex_unlock(&ucsi->ppm_lock); + return 0; +err_reset: + ucsi_reset_ppm(ucsi); + mutex_unlock(&ucsi->ppm_lock); + return ret; +} + +static int ucsi_acpi_probe(struct platform_device *pdev) +{ + struct resource *res; + acpi_status status; + struct ucsi *ucsi; + int ret; + + ucsi = devm_kzalloc(&pdev->dev, sizeof(*ucsi), GFP_KERNEL); + if (!ucsi) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + /* + * NOTE: ACPI has claimed the memory region as it's also an Operation + * Region. It's not possible to request it in the driver. + */ + ucsi->data = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!ucsi->data) + return -ENOMEM; + + ucsi->dev = &pdev->dev; + + status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, + ucsi_acpi_notify, ucsi); + if (ACPI_FAILURE(status)) + return -ENODEV; + + ret = ucsi_init(ucsi); + if (ret) { + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, + ucsi_acpi_notify); + return ret; + } + + platform_set_drvdata(pdev, ucsi); + return 0; +} + +static int ucsi_acpi_remove(struct platform_device *pdev) +{ + struct ucsi *ucsi = platform_get_drvdata(pdev); + + acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), + ACPI_ALL_NOTIFY, ucsi_acpi_notify); + + /* Make sure there are no events in the middle of being processed */ + if (wait_on_bit_timeout(&ucsi->flags, EVENT_PENDING, + TASK_UNINTERRUPTIBLE, + msecs_to_jiffies(UCSI_TIMEOUT_MS))) + dev_WARN(ucsi->dev, "%s: Events still pending\n", __func__); + + ucsi_reset_ppm(ucsi); + return 0; +} + +static const struct acpi_device_id ucsi_acpi_match[] = { + { "PNP0CA0", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match); + +static struct platform_driver ucsi_acpi_platform_driver = { + .driver = { + .name = "ucsi_acpi", + .acpi_match_table = ACPI_PTR(ucsi_acpi_match), + }, + .probe = ucsi_acpi_probe, + .remove = ucsi_acpi_remove, +}; + +module_platform_driver(ucsi_acpi_platform_driver); + +MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("USB Type-C System Software Interface (UCSI) driver"); diff --git a/drivers/usb/misc/ucsi.h b/drivers/usb/misc/ucsi.h new file mode 100644 index 000000000000..6dd11d1fe225 --- /dev/null +++ b/drivers/usb/misc/ucsi.h @@ -0,0 +1,215 @@ + +#include <linux/types.h> + +/* -------------------------------------------------------------------------- */ + +/* Command Status and Connector Change Indication (CCI) data structure */ +struct ucsi_cci { + unsigned int RESERVED1:1; + unsigned int connector_change:7; + u8 data_length; + unsigned int RESERVED9:9; + unsigned int not_supported:1; + unsigned int cancel_complete:1; + unsigned int reset_complete:1; + unsigned int busy:1; + unsigned int ack_complete:1; + unsigned int error:1; + unsigned int cmd_complete:1; +} __packed; + +/* Default fields in CONTROL data structure */ +struct ucsi_command { + u8 cmd; + u8 length; + u64 data:48; +} __packed; + +/* Set USB Operation Mode Command structure */ +struct ucsi_uor_cmd { + u8 cmd; + u8 length; + u64 con_num:7; + u64 role:3; +#define UCSI_UOR_ROLE_DFP BIT(0) +#define UCSI_UOR_ROLE_UFP BIT(1) +#define UCSI_UOR_ROLE_DRP BIT(2) + u64 data:38; +} __packed; + +struct ucsi_control { + union { + u64 raw_cmd; + struct ucsi_command cmd; + struct ucsi_uor_cmd uor; + }; +}; + +struct ucsi_data { + u16 version; + u16 RESERVED; + union { + u32 raw_cci; + struct ucsi_cci cci; + }; + struct ucsi_control ctrl; + u32 message_in[4]; + u32 message_out[4]; +} __packed; + +/* Commands */ +#define UCSI_PPM_RESET 0x01 +#define UCSI_CANCEL 0x02 +#define UCSI_CONNECTOR_RESET 0x03 +#define UCSI_ACK_CC_CI 0x04 +#define UCSI_SET_NOTIFICATION_ENABLE 0x05 +#define UCSI_GET_CAPABILITY 0x06 +#define UCSI_GET_CONNECTOR_CAPABILITY 0x07 +#define UCSI_SET_UOM 0x08 +#define UCSI_SET_UOR 0x09 +#define UCSI_SET_PDM 0x0A +#define UCSI_SET_PDR 0x0B +#define UCSI_GET_ALTERNATE_MODES 0x0C +#define UCSI_GET_CAM_SUPPORTED 0x0D +#define UCSI_GET_CURRENT_CAM 0x0E +#define UCSI_SET_NEW_CAM 0x0F +#define UCSI_GET_PDOS 0x10 +#define UCSI_GET_CABLE_PROPERTY 0x11 +#define UCSI_GET_CONNECTOR_STATUS 0x12 +#define UCSI_GET_ERROR_STATUS 0x13 + +/* ACK_CC_CI commands */ +#define UCSI_ACK_EVENT 1 +#define UCSI_ACK_CMD 2 + +/* Bits for SET_NOTIFICATION_ENABLE command */ +#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(0) +#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(1) +#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(2) +#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(5) +#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(6) +#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(7) +#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(8) +#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(9) +#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(11) +#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(12) +#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(14) +#define UCSI_ENABLE_NTFY_ERROR BIT(15) +#define UCSI_ENABLE_NTFY_ALL 0xdbe7 + +/* Error information returned by PPM in response to GET_ERROR_STATUS command. */ +#define UCSI_ERROR_UNREGONIZED_CMD BIT(0) +#define UCSI_ERROR_INVALID_CON_NUM BIT(1) +#define UCSI_ERROR_INVALID_CMD_ARGUMENT BIT(2) +#define UCSI_ERROR_INCOMPATIBLE_PARTNER BIT(3) +#define UCSI_ERROR_CC_COMMUNICATION_ERR BIT(4) +#define UCSI_ERROR_DEAD_BATTERY BIT(5) +#define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL BIT(6) + +/* Data structure filled by PPM in response to GET_CAPABILITY command. */ +struct ucsi_capability { + u32 attributes; +#define UCSI_CAP_ATTR_DISABLE_STATE BIT(0) +#define UCSI_CAP_ATTR_BATTERY_CHARGING BIT(1) +#define UCSI_CAP_ATTR_USB_PD BIT(2) +#define UCSI_CAP_ATTR_TYPEC_CURRENT BIT(6) +#define UCSI_CAP_ATTR_POWER_AC_SUPPLY BIT(8) +#define UCSI_CAP_ATTR_POWER_OTHER BIT(10) +#define UCSI_CAP_ATTR_POWER_VBUS BIT(14) + u8 num_connectors; + u32 features:24; +#define UCSI_CAP_SET_UOM BIT(0) +#define UCSI_CAP_SET_PDM BIT(1) +#define UCSI_CAP_ALT_MODE_DETAILS BIT(2) +#define UCSI_CAP_ALT_MODE_OVERRIDE BIT(3) +#define UCSI_CAP_PDO_DETAILS BIT(4) +#define UCSI_CAP_CABLE_DETAILS BIT(5) +#define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS BIT(6) +#define UCSI_CAP_PD_RESET BIT(7) + u8 num_alt_modes; + u8 RESERVED; + u16 bc_version; + u16 pd_version; + u16 typec_version; +} __packed; + +/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */ +struct ucsi_connector_capability { + u8 op_mode; +#define UCSI_CONCAP_OPMODE_DFP BIT(0) +#define UCSI_CONCAP_OPMODE_UFP BIT(1) +#define UCSI_CONCAP_OPMODE_DRP BIT(2) +#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3) +#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4) +#define UCSI_CONCAP_OPMODE_USB2 BIT(5) +#define UCSI_CONCAP_OPMODE_USB3 BIT(6) +#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7) + u8 provider:1; + u8 consumer:1; +} __packed; + +/* Data structure filled by PPM in response to GET_CABLE_PROPERTY command. */ +struct ucsi_cable_property { + u16 speed_supported; + u8 current_capability; + u8 vbus_in_cable:1; + u8 active_cable:1; + u8 directionality:1; + u8 plug_type:2; +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2 +#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3 + u8 mode_support:1; + u8 RESERVED_2:2; + u8 latency:4; + u8 RESERVED_4:4; +} __packed; + +/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */ +struct ucsi_connector_status { + u16 change; +#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1) +#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2) +#define UCSI_CONSTAT_PDOS_CHANGE BIT(5) +#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6) +#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7) +#define UCSI_CONSTAT_CAM_CHANGE BIT(8) +#define UCSI_CONSTAT_BC_CHANGE BIT(9) +#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11) +#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12) +#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14) +#define UCSI_CONSTAT_ERROR BIT(15) + u16 pwr_op_mode:3; +#define UCSI_CONSTAT_PWR_OPMODE_NONE 0 +#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1 +#define UCSI_CONSTAT_PWR_OPMODE_BC 2 +#define UCSI_CONSTAT_PWR_OPMODE_PD 3 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_3 4 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5 + u16 connected:1; + u16 pwr_dir:1; + u16 partner_flags:8; +#define UCSI_CONSTAT_PARTNER_FLAG_USB BIT(0) +#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE BIT(1) + u16 partner_type:3; +#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1 +#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2 +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_NO_UFP 3 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5 +#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 + u32 request_data_obj; + u8 bc_status:2; +#define UCSI_CONSTAT_BC_NOT_CHARGING 0 +#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 +#define UCSI_CONSTAT_BC_SLOW_CHARGING 2 +#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 + u8 provider_cap_limit_reason:4; +#define UCSI_CONSTAT_CAP_PWR_LOWERED 0 +#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1 + u8 RESERVED:2; +} __packed; + +/* -------------------------------------------------------------------------- */ + diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 92fdb6e9faff..6b978f04b8d7 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -287,6 +287,9 @@ static struct urb *usbtest_alloc_urb( if (usb_pipein(pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; + if ((bytes + offset) == 0) + return urb; + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset, GFP_KERNEL, &urb->transfer_dma); @@ -529,6 +532,7 @@ static struct scatterlist * alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe) { struct scatterlist *sg; + unsigned int n_size = 0; unsigned i; unsigned size = max; unsigned maxpacket = @@ -561,7 +565,8 @@ alloc_sglist(int nents, int max, int vary, struct usbtest_dev *dev, int pipe) break; case 1: for (j = 0; j < size; j++) - *buf++ = (u8) ((j % maxpacket) % 63); + *buf++ = (u8) (((j + n_size) % maxpacket) % 63); + n_size += size; break; } diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 39fd95833eb8..f824336def5c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1090,29 +1090,6 @@ void musb_stop(struct musb *musb) musb_platform_try_idle(musb, 0); } -static void musb_shutdown(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - unsigned long flags; - - pm_runtime_get_sync(musb->controller); - - musb_host_cleanup(musb); - musb_gadget_cleanup(musb); - - spin_lock_irqsave(&musb->lock, flags); - musb_platform_disable(musb); - musb_generic_disable(musb); - spin_unlock_irqrestore(&musb->lock, flags); - - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_platform_exit(musb); - - pm_runtime_put(musb->controller); - /* FIXME power down */ -} - - /*-------------------------------------------------------------------------*/ /* @@ -1702,7 +1679,7 @@ EXPORT_SYMBOL_GPL(musb_dma_completion); #define use_dma 0 #endif -static void (*musb_phy_callback)(enum musb_vbus_id_status status); +static int (*musb_phy_callback)(enum musb_vbus_id_status status); /* * musb_mailbox - optional phy notifier function @@ -1711,11 +1688,12 @@ static void (*musb_phy_callback)(enum musb_vbus_id_status status); * Optionally gets called from the USB PHY. Note that the USB PHY must be * disabled at the point the phy_callback is registered or unregistered. */ -void musb_mailbox(enum musb_vbus_id_status status) +int musb_mailbox(enum musb_vbus_id_status status) { if (musb_phy_callback) - musb_phy_callback(status); + return musb_phy_callback(status); + return -ENODEV; }; EXPORT_SYMBOL_GPL(musb_mailbox); @@ -2028,11 +2006,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_readl = musb_default_readl; musb_writel = musb_default_writel; - /* We need musb_read/write functions initialized for PM */ - pm_runtime_use_autosuspend(musb->controller); - pm_runtime_set_autosuspend_delay(musb->controller, 200); - pm_runtime_enable(musb->controller); - /* The musb_platform_init() call: * - adjusts musb->mregs * - sets the musb->isr @@ -2134,6 +2107,16 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (musb->ops->phy_callback) musb_phy_callback = musb->ops->phy_callback; + /* + * We need musb_read/write functions initialized for PM. + * Note that at least 2430 glue needs autosuspend delay + * somewhere above 300 ms for the hardware to idle properly + * after disconnecting the cable in host mode. Let's use + * 500 ms for some margin. + */ + pm_runtime_use_autosuspend(musb->controller); + pm_runtime_set_autosuspend_delay(musb->controller, 500); + pm_runtime_enable(musb->controller); pm_runtime_get_sync(musb->controller); status = usb_phy_init(musb->xceiv); @@ -2237,13 +2220,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (status) goto fail5; - pm_runtime_put(musb->controller); - - /* - * For why this is currently needed, see commit 3e43a0725637 - * ("usb: musb: core: add pm_runtime_irq_safe()") - */ - pm_runtime_irq_safe(musb->controller); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return 0; @@ -2265,7 +2243,9 @@ fail2_5: usb_phy_shutdown(musb->xceiv); err_usb_phy_init: + pm_runtime_dont_use_autosuspend(musb->controller); pm_runtime_put_sync(musb->controller); + pm_runtime_disable(musb->controller); fail2: if (musb->irq_wake) @@ -2273,7 +2253,6 @@ fail2: musb_platform_exit(musb); fail1: - pm_runtime_disable(musb->controller); dev_err(musb->controller, "musb_init_controller failed with status %d\n", status); @@ -2312,6 +2291,7 @@ static int musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); + unsigned long flags; /* this gets called on rmmod. * - Host mode: host may still be active @@ -2319,17 +2299,26 @@ static int musb_remove(struct platform_device *pdev) * - OTG mode: both roles are deactivated (or never-activated) */ musb_exit_debugfs(musb); - musb_shutdown(pdev); - musb_phy_callback = NULL; - - if (musb->dma_controller) - musb_dma_controller_destroy(musb->dma_controller); - - usb_phy_shutdown(musb->xceiv); cancel_work_sync(&musb->irq_work); cancel_delayed_work_sync(&musb->finish_resume_work); cancel_delayed_work_sync(&musb->deassert_reset_work); + pm_runtime_get_sync(musb->controller); + musb_host_cleanup(musb); + musb_gadget_cleanup(musb); + spin_lock_irqsave(&musb->lock, flags); + musb_platform_disable(musb); + musb_generic_disable(musb); + spin_unlock_irqrestore(&musb->lock, flags); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + pm_runtime_dont_use_autosuspend(musb->controller); + pm_runtime_put_sync(musb->controller); + pm_runtime_disable(musb->controller); + musb_platform_exit(musb); + musb_phy_callback = NULL; + if (musb->dma_controller) + musb_dma_controller_destroy(musb->dma_controller); + usb_phy_shutdown(musb->xceiv); musb_free(musb); device_init_wakeup(dev, 0); return 0; @@ -2429,7 +2418,8 @@ static void musb_restore_context(struct musb *musb) musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); - musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); + if (musb->context.devctl & MUSB_DEVCTL_SESSION) + musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { struct musb_hw_ep *hw_ep; @@ -2612,7 +2602,6 @@ static struct platform_driver musb_driver = { }, .probe = musb_probe, .remove = musb_remove, - .shutdown = musb_shutdown, }; module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b6afe9e43305..b55a776b03eb 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -215,7 +215,7 @@ struct musb_platform_ops { dma_addr_t *dma_addr, u32 *len); void (*pre_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb); - void (*phy_callback)(enum musb_vbus_id_status status); + int (*phy_callback)(enum musb_vbus_id_status status); }; /* @@ -312,6 +312,7 @@ struct musb { struct work_struct irq_work; struct delayed_work deassert_reset_work; struct delayed_work finish_resume_work; + struct delayed_work gadget_work; u16 hwvers; u16 intrrxe; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 152865b36522..af2a3a7addf9 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1656,6 +1656,20 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) return usb_phy_set_power(musb->xceiv, mA); } +static void musb_gadget_work(struct work_struct *work) +{ + struct musb *musb; + unsigned long flags; + + musb = container_of(work, struct musb, gadget_work.work); + pm_runtime_get_sync(musb->controller); + spin_lock_irqsave(&musb->lock, flags); + musb_pullup(musb, musb->softconnect); + spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); +} + static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) { struct musb *musb = gadget_to_musb(gadget); @@ -1663,20 +1677,16 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) is_on = !!is_on; - pm_runtime_get_sync(musb->controller); - /* NOTE: this assumes we are sensing vbus; we'd rather * not pullup unless the B-session is active. */ spin_lock_irqsave(&musb->lock, flags); if (is_on != musb->softconnect) { musb->softconnect = is_on; - musb_pullup(musb, is_on); + schedule_delayed_work(&musb->gadget_work, 0); } spin_unlock_irqrestore(&musb->lock, flags); - pm_runtime_put(musb->controller); - return 0; } @@ -1845,7 +1855,7 @@ int musb_gadget_setup(struct musb *musb) #elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) musb->g.is_otg = 0; #endif - + INIT_DELAYED_WORK(&musb->gadget_work, musb_gadget_work); musb_g_init_endpoints(musb); musb->is_active = 0; @@ -1866,6 +1876,8 @@ void musb_gadget_cleanup(struct musb *musb) { if (musb->port_mode == MUSB_PORT_MODE_HOST) return; + + cancel_delayed_work_sync(&musb->gadget_work); usb_del_gadget_udc(&musb->g); } @@ -1914,8 +1926,8 @@ static int musb_gadget_start(struct usb_gadget *g, if (musb->xceiv->last_event == USB_EVENT_ID) musb_platform_set_vbus(musb, 1); - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return 0; @@ -1934,8 +1946,7 @@ static int musb_gadget_stop(struct usb_gadget *g) struct musb *musb = gadget_to_musb(g); unsigned long flags; - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_get_sync(musb->controller); + pm_runtime_get_sync(musb->controller); /* * REVISIT always use otg_set_peripheral() here too; @@ -1963,7 +1974,8 @@ static int musb_gadget_stop(struct usb_gadget *g) * that currently misbehaves. */ - pm_runtime_put(musb->controller); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return 0; } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 2f8ad7f1f482..d227a71d85e1 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -434,7 +434,13 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, } } - if (qh != NULL && qh->is_ready) { + /* + * The pipe must be broken if current urb->status is set, so don't + * start next urb. + * TODO: to minimize the risk of regression, only check urb->status + * for RX, until we have a test case to understand the behavior of TX. + */ + if ((!status || !is_in) && qh && qh->is_ready) { dev_dbg(musb->controller, "... next ep%d %cX urb %p\n", hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); musb_start_urb(musb, is_in, qh); @@ -594,14 +600,13 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum) musb_writew(ep->regs, MUSB_TXCSR, 0); /* scrub all previous state, clearing toggle */ - } else { - csr = musb_readw(ep->regs, MUSB_RXCSR); - if (csr & MUSB_RXCSR_RXPKTRDY) - WARNING("rx%d, packet/%d ready?\n", ep->epnum, - musb_readw(ep->regs, MUSB_RXCOUNT)); - - musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); } + csr = musb_readw(ep->regs, MUSB_RXCSR); + if (csr & MUSB_RXCSR_RXPKTRDY) + WARNING("rx%d, packet/%d ready?\n", ep->epnum, + musb_readw(ep->regs, MUSB_RXCOUNT)); + + musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); /* target addr and (for multipoint) hub addr/port */ if (musb->is_multipoint) { @@ -627,7 +632,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, u8 epnum) ep->rx_reinit = 0; } -static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma, +static void musb_tx_dma_set_mode_mentor(struct dma_controller *dma, struct musb_hw_ep *hw_ep, struct musb_qh *qh, struct urb *urb, u32 offset, u32 *length, u8 *mode) @@ -664,23 +669,18 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma, } channel->desired_mode = *mode; musb_writew(epio, MUSB_TXCSR, csr); - - return 0; } -static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma, - struct musb_hw_ep *hw_ep, - struct musb_qh *qh, - struct urb *urb, - u32 offset, - u32 *length, - u8 *mode) +static void musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma, + struct musb_hw_ep *hw_ep, + struct musb_qh *qh, + struct urb *urb, + u32 offset, + u32 *length, + u8 *mode) { struct dma_channel *channel = hw_ep->tx_channel; - if (!is_cppi_enabled(hw_ep->musb) && !tusb_dma_omap(hw_ep->musb)) - return -ENODEV; - channel->actual_len = 0; /* @@ -688,8 +688,6 @@ static int musb_tx_dma_set_mode_cppi_tusb(struct dma_controller *dma, * to identify the zero-length-final-packet case. */ *mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; - - return 0; } static bool musb_tx_dma_program(struct dma_controller *dma, @@ -699,15 +697,14 @@ static bool musb_tx_dma_program(struct dma_controller *dma, struct dma_channel *channel = hw_ep->tx_channel; u16 pkt_size = qh->maxpacket; u8 mode; - int res; if (musb_dma_inventra(hw_ep->musb) || musb_dma_ux500(hw_ep->musb)) - res = musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, - offset, &length, &mode); + musb_tx_dma_set_mode_mentor(dma, hw_ep, qh, urb, offset, + &length, &mode); + else if (is_cppi_enabled(hw_ep->musb) || tusb_dma_omap(hw_ep->musb)) + musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, offset, + &length, &mode); else - res = musb_tx_dma_set_mode_cppi_tusb(dma, hw_ep, qh, urb, - offset, &length, &mode); - if (res) return false; qh->segsize = length; @@ -995,9 +992,15 @@ static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep, if (is_in) { dma = is_dma_capable() ? ep->rx_channel : NULL; - /* clear nak timeout bit */ + /* + * Need to stop the transaction by clearing REQPKT first + * then the NAK Timeout bit ref MUSBMHDRC USB 2.0 HIGH-SPEED + * DUAL-ROLE CONTROLLER Programmer's Guide, section 9.2.2 + */ rx_csr = musb_readw(epio, MUSB_RXCSR); rx_csr |= MUSB_RXCSR_H_WZC_BITS; + rx_csr &= ~MUSB_RXCSR_H_REQPKT; + musb_writew(epio, MUSB_RXCSR, rx_csr); rx_csr &= ~MUSB_RXCSR_DATAERROR; musb_writew(epio, MUSB_RXCSR, rx_csr); @@ -1551,7 +1554,7 @@ static int musb_rx_dma_iso_cppi41(struct dma_controller *dma, struct urb *urb, size_t len) { - struct dma_channel *channel = hw_ep->tx_channel; + struct dma_channel *channel = hw_ep->rx_channel; void __iomem *epio = hw_ep->regs; dma_addr_t *buf; u32 length, res; @@ -1870,6 +1873,9 @@ void musb_host_rx(struct musb *musb, u8 epnum) status = -EPROTO; musb_writeb(epio, MUSB_RXINTERVAL, 0); + rx_csr &= ~MUSB_RXCSR_H_ERROR; + musb_writew(epio, MUSB_RXCSR, rx_csr); + } else if (rx_csr & MUSB_RXCSR_DATAERROR) { if (USB_ENDPOINT_XFER_ISOC != qh->type) { diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index c84e0322c108..0b4cec940386 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -49,97 +49,14 @@ struct omap2430_glue { enum musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; struct device *control_otghs; + bool cable_connected; + bool enabled; + bool powered; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) static struct omap2430_glue *_glue; -static struct timer_list musb_idle_timer; - -static void musb_do_idle(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - unsigned long flags; - u8 power; - u8 devctl; - - spin_lock_irqsave(&musb->lock, flags); - - switch (musb->xceiv->otg->state) { - case OTG_STATE_A_WAIT_BCON: - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->otg->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); - } else { - musb->xceiv->otg->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - } - break; - case OTG_STATE_A_SUSPEND: - /* finish RESUME signaling? */ - if (musb->port1_status & MUSB_PORT_STAT_RESUME) { - power = musb_readb(musb->mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power); - musb_writeb(musb->mregs, MUSB_POWER, power); - musb->is_active = 1; - musb->port1_status &= ~(USB_PORT_STAT_SUSPEND - | MUSB_PORT_STAT_RESUME); - musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; - usb_hcd_poll_rh_status(musb->hcd); - /* NOTE: it might really be A_WAIT_BCON ... */ - musb->xceiv->otg->state = OTG_STATE_A_HOST; - } - break; - case OTG_STATE_A_HOST: - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - musb->xceiv->otg->state = OTG_STATE_B_IDLE; - else - musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - - -static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - unsigned long default_timeout = jiffies + msecs_to_jiffies(3); - static unsigned long last_timer; - - if (timeout == 0) - timeout = default_timeout; - - /* Never idle if active, or when VBUS timeout is not set as host */ - if (musb->is_active || ((musb->a_wait_bcon == 0) - && (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON))) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->otg->state)); - del_timer(&musb_idle_timer); - last_timer = jiffies; - return; - } - - if (time_after(last_timer, timeout)) { - if (!timer_pending(&musb_idle_timer)) - last_timer = timeout; - else { - dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n"); - return; - } - } - last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - usb_otg_state_string(musb->xceiv->otg->state), - (unsigned long)jiffies_to_msecs(timeout - jiffies)); - mod_timer(&musb_idle_timer, timeout); -} - static void omap2430_musb_set_vbus(struct musb *musb, int is_on) { struct usb_otg *otg = musb->xceiv->otg; @@ -205,16 +122,6 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) musb_readb(musb->mregs, MUSB_DEVCTL)); } -static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - - return 0; -} - static inline void omap2430_low_level_exit(struct musb *musb) { u32 l; @@ -234,22 +141,63 @@ static inline void omap2430_low_level_init(struct musb *musb) musb_writel(musb->mregs, OTG_FORCESTDBY, l); } -static void omap2430_musb_mailbox(enum musb_vbus_id_status status) +/* + * We can get multiple cable events so we need to keep track + * of the power state. Only keep power enabled if USB cable is + * connected and a gadget is started. + */ +static void omap2430_set_power(struct musb *musb, bool enabled, bool cable) +{ + struct device *dev = musb->controller; + struct omap2430_glue *glue = dev_get_drvdata(dev->parent); + bool power_up; + int res; + + if (glue->enabled != enabled) + glue->enabled = enabled; + + if (glue->cable_connected != cable) + glue->cable_connected = cable; + + power_up = glue->enabled && glue->cable_connected; + if (power_up == glue->powered) { + dev_warn(musb->controller, "power state already %i\n", + power_up); + return; + } + + glue->powered = power_up; + + if (power_up) { + res = pm_runtime_get_sync(musb->controller); + if (res < 0) { + dev_err(musb->controller, "could not enable: %i", res); + glue->powered = false; + } + } else { + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); + } +} + +static int omap2430_musb_mailbox(enum musb_vbus_id_status status) { struct omap2430_glue *glue = _glue; if (!glue) { pr_err("%s: musb core is not yet initialized\n", __func__); - return; + return -EPROBE_DEFER; } glue->status = status; if (!glue_to_musb(glue)) { pr_err("%s: musb core is not yet ready\n", __func__); - return; + return -EPROBE_DEFER; } schedule_work(&glue->omap_musb_mailbox_work); + + return 0; } static void omap_musb_set_mailbox(struct omap2430_glue *glue) @@ -259,6 +207,13 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; struct usb_otg *otg = musb->xceiv->otg; + bool cable_connected; + + cable_connected = ((glue->status == MUSB_ID_GROUND) || + (glue->status == MUSB_VBUS_VALID)); + + if (cable_connected) + omap2430_set_power(musb, glue->enabled, cable_connected); switch (glue->status) { case MUSB_ID_GROUND: @@ -268,7 +223,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) musb->xceiv->otg->state = OTG_STATE_A_IDLE; musb->xceiv->last_event = USB_EVENT_ID; if (musb->gadget_driver) { - pm_runtime_get_sync(dev); omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); omap2430_musb_set_vbus(musb, 1); @@ -281,8 +235,6 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) otg->default_a = false; musb->xceiv->otg->state = OTG_STATE_B_IDLE; musb->xceiv->last_event = USB_EVENT_VBUS; - if (musb->gadget_driver) - pm_runtime_get_sync(dev); omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; @@ -291,11 +243,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) dev_dbg(dev, "VBUS Disconnect\n"); musb->xceiv->last_event = USB_EVENT_NONE; - if (musb->gadget_driver) { + if (musb->gadget_driver) omap2430_musb_set_vbus(musb, 0); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - } if (data->interface_type == MUSB_INTERFACE_UTMI) otg_set_vbus(musb->xceiv->otg, 0); @@ -307,6 +256,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) dev_dbg(dev, "ID float\n"); } + if (!cable_connected) + omap2430_set_power(musb, glue->enabled, cable_connected); + atomic_notifier_call_chain(&musb->xceiv->notifier, musb->xceiv->last_event, NULL); } @@ -316,13 +268,8 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work) { struct omap2430_glue *glue = container_of(mailbox_work, struct omap2430_glue, omap_musb_mailbox_work); - struct musb *musb = glue_to_musb(glue); - struct device *dev = musb->controller; - pm_runtime_get_sync(dev); omap_musb_set_mailbox(glue); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); } static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) @@ -389,23 +336,7 @@ static int omap2430_musb_init(struct musb *musb) return PTR_ERR(musb->phy); } musb->isr = omap2430_musb_interrupt; - - /* - * Enable runtime PM for musb parent (this driver). We can't - * do it earlier as struct musb is not yet allocated and we - * need to touch the musb registers for runtime PM. - */ - pm_runtime_enable(glue->dev); - status = pm_runtime_get_sync(glue->dev); - if (status < 0) - goto err1; - - status = pm_runtime_get_sync(dev); - if (status < 0) { - dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); - pm_runtime_put_sync(glue->dev); - goto err1; - } + phy_init(musb->phy); l = musb_readl(musb->mregs, OTG_INTERFSEL); @@ -427,20 +358,10 @@ static int omap2430_musb_init(struct musb *musb) musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); - setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); - if (glue->status != MUSB_UNKNOWN) omap_musb_set_mailbox(glue); - phy_init(musb->phy); - phy_power_on(musb->phy); - - pm_runtime_put_noidle(musb->controller); - pm_runtime_put_noidle(glue->dev); return 0; - -err1: - return status; } static void omap2430_musb_enable(struct musb *musb) @@ -452,6 +373,11 @@ static void omap2430_musb_enable(struct musb *musb) struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); struct omap_musb_board_data *data = pdata->board_data; + if (!WARN_ON(!musb->phy)) + phy_power_on(musb->phy); + + omap2430_set_power(musb, true, glue->cable_connected); + switch (glue->status) { case MUSB_ID_GROUND: @@ -487,18 +413,25 @@ static void omap2430_musb_disable(struct musb *musb) struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); + if (!WARN_ON(!musb->phy)) + phy_power_off(musb->phy); + if (glue->status != MUSB_UNKNOWN) omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DISCONNECT); + + omap2430_set_power(musb, false, glue->cable_connected); } static int omap2430_musb_exit(struct musb *musb) { - del_timer_sync(&musb_idle_timer); + struct device *dev = musb->controller; + struct omap2430_glue *glue = dev_get_drvdata(dev->parent); omap2430_low_level_exit(musb); - phy_power_off(musb->phy); phy_exit(musb->phy); + musb->phy = NULL; + cancel_work_sync(&glue->omap_musb_mailbox_work); return 0; } @@ -512,9 +445,6 @@ static const struct musb_platform_ops omap2430_ops = { .init = omap2430_musb_init, .exit = omap2430_musb_exit, - .set_mode = omap2430_musb_set_mode, - .try_idle = omap2430_musb_try_idle, - .set_vbus = omap2430_musb_set_vbus, .enable = omap2430_musb_enable, @@ -639,11 +569,9 @@ static int omap2430_probe(struct platform_device *pdev) goto err2; } - /* - * Note that we cannot enable PM runtime yet for this - * driver as we need struct musb initialized first. - * See omap2430_musb_init above. - */ + pm_runtime_enable(glue->dev); + pm_runtime_use_autosuspend(glue->dev); + pm_runtime_set_autosuspend_delay(glue->dev, 500); ret = platform_device_add(musb); if (ret) { @@ -662,12 +590,14 @@ err0: static int omap2430_remove(struct platform_device *pdev) { - struct omap2430_glue *glue = platform_get_drvdata(pdev); + struct omap2430_glue *glue = platform_get_drvdata(pdev); + struct musb *musb = glue_to_musb(glue); pm_runtime_get_sync(glue->dev); - cancel_work_sync(&glue->omap_musb_mailbox_work); platform_device_unregister(glue->musb); + omap2430_set_power(musb, false, false); pm_runtime_put_sync(glue->dev); + pm_runtime_dont_use_autosuspend(glue->dev); pm_runtime_disable(glue->dev); return 0; @@ -680,12 +610,13 @@ static int omap2430_runtime_suspend(struct device *dev) struct omap2430_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); - if (musb) { - musb->context.otg_interfsel = musb_readl(musb->mregs, - OTG_INTERFSEL); + if (!musb) + return 0; - omap2430_low_level_exit(musb); - } + musb->context.otg_interfsel = musb_readl(musb->mregs, + OTG_INTERFSEL); + + omap2430_low_level_exit(musb); return 0; } @@ -696,7 +627,7 @@ static int omap2430_runtime_resume(struct device *dev) struct musb *musb = glue_to_musb(glue); if (!musb) - return -EPROBE_DEFER; + return 0; omap2430_low_level_init(musb); musb_writel(musb->mregs, OTG_INTERFSEL, @@ -738,18 +669,8 @@ static struct platform_driver omap2430_driver = { }, }; +module_platform_driver(omap2430_driver); + MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer"); MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); - -static int __init omap2430_init(void) -{ - return platform_driver_register(&omap2430_driver); -} -subsys_initcall(omap2430_init); - -static void __exit omap2430_exit(void) -{ - platform_driver_unregister(&omap2430_driver); -} -module_exit(omap2430_exit); diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index fdab4232cfbf..76500515dd8b 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -80,7 +80,8 @@ static struct musb *sunxi_musb; struct sunxi_glue { struct device *dev; - struct platform_device *musb; + struct musb *musb; + struct platform_device *musb_pdev; struct clk *clk; struct reset_control *rst; struct phy *phy; @@ -102,7 +103,7 @@ static void sunxi_musb_work(struct work_struct *work) return; if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { - struct musb *musb = platform_get_drvdata(glue->musb); + struct musb *musb = glue->musb; unsigned long flags; u8 devctl; @@ -112,7 +113,7 @@ static void sunxi_musb_work(struct work_struct *work) if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); musb->xceiv->otg->default_a = 1; - musb->xceiv->otg->state = OTG_STATE_A_IDLE; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; MUSB_HST_MODE(musb); devctl |= MUSB_DEVCTL_SESSION; } else { @@ -145,10 +146,12 @@ static void sunxi_musb_set_vbus(struct musb *musb, int is_on) { struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); - if (is_on) + if (is_on) { set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); - else + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; + } else { clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + } schedule_work(&glue->work); } @@ -264,15 +267,6 @@ static int sunxi_musb_init(struct musb *musb) if (ret) goto error_unregister_notifier; - if (musb->port_mode == MUSB_PORT_MODE_HOST) { - ret = phy_power_on(glue->phy); - if (ret) - goto error_phy_exit; - set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); - /* Stop musb work from turning vbus off again */ - set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); - } - musb->isr = sunxi_musb_interrupt; /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ @@ -280,8 +274,6 @@ static int sunxi_musb_init(struct musb *musb) return 0; -error_phy_exit: - phy_exit(glue->phy); error_unregister_notifier: if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, @@ -323,10 +315,31 @@ static int sunxi_musb_exit(struct musb *musb) return 0; } +static int sunxi_set_mode(struct musb *musb, u8 mode) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + int ret; + + if (mode == MUSB_HOST) { + ret = phy_power_on(glue->phy); + if (ret) + return ret; + + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + /* Stop musb work from turning vbus off again */ + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; + } + + return 0; +} + static void sunxi_musb_enable(struct musb *musb) { struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + glue->musb = musb; + /* musb_core does not call us in a balanced manner */ if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) return; @@ -569,6 +582,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { .exit = sunxi_musb_exit, .enable = sunxi_musb_enable, .disable = sunxi_musb_disable, + .set_mode = sunxi_set_mode, .fifo_offset = sunxi_musb_fifo_offset, .ep_offset = sunxi_musb_ep_offset, .busctl_offset = sunxi_musb_busctl_offset, @@ -721,9 +735,9 @@ static int sunxi_musb_probe(struct platform_device *pdev) pinfo.data = &pdata; pinfo.size_data = sizeof(pdata); - glue->musb = platform_device_register_full(&pinfo); - if (IS_ERR(glue->musb)) { - ret = PTR_ERR(glue->musb); + glue->musb_pdev = platform_device_register_full(&pinfo); + if (IS_ERR(glue->musb_pdev)) { + ret = PTR_ERR(glue->musb_pdev); dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); goto err_unregister_usb_phy; } @@ -740,7 +754,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) struct sunxi_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; - platform_device_unregister(glue->musb); /* Frees glue ! */ + platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); return 0; diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index 3d7af85aecb9..d8593adb3621 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -240,10 +240,7 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch", GPIOD_OUT_LOW); - if (IS_ERR(qphy->switch_gpio)) - return PTR_ERR(qphy->switch_gpio); - - return 0; + return PTR_ERR_OR_ZERO(qphy->switch_gpio); } static int phy_8x16_reboot_notify(struct notifier_block *this, diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 014dbbd72132..a72e8d670adc 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -97,6 +97,9 @@ struct twl6030_usb { struct regulator *usb3v3; + /* used to check initial cable status after probe */ + struct delayed_work get_status_work; + /* used to set vbus, in atomic path */ struct work_struct set_vbus_work; @@ -155,13 +158,13 @@ static int twl6030_start_srp(struct phy_companion *comparator) static int twl6030_usb_ldo_init(struct twl6030_usb *twl) { /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); + twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG); /* Program CFG_LDO_PD2 register and set VUSB bit */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2); + twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2); /* Program MISC2 register and set bit VUSB_IN_VBAT */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); + twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2); twl->usb3v3 = regulator_get(twl->dev, twl->regulator); if (IS_ERR(twl->usb3v3)) @@ -227,12 +230,16 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) twl->asleep = 1; status = MUSB_VBUS_VALID; twl->linkstat = status; - musb_mailbox(status); + ret = musb_mailbox(status); + if (ret) + twl->linkstat = MUSB_UNKNOWN; } else { if (twl->linkstat != MUSB_UNKNOWN) { status = MUSB_VBUS_OFF; twl->linkstat = status; - musb_mailbox(status); + ret = musb_mailbox(status); + if (ret) + twl->linkstat = MUSB_UNKNOWN; if (twl->asleep) { regulator_disable(twl->usb3v3); twl->asleep = 0; @@ -264,7 +271,9 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET); status = MUSB_ID_GROUND; twl->linkstat = status; - musb_mailbox(status); + ret = musb_mailbox(status); + if (ret) + twl->linkstat = MUSB_UNKNOWN; } else { twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR); twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); @@ -274,6 +283,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) return IRQ_HANDLED; } +static void twl6030_status_work(struct work_struct *work) +{ + struct twl6030_usb *twl = container_of(work, struct twl6030_usb, + get_status_work.work); + + twl6030_usb_irq(twl->irq2, twl); + twl6030_usbotg_irq(twl->irq1, twl); +} + static int twl6030_enable_irq(struct twl6030_usb *twl) { twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET); @@ -284,8 +302,6 @@ static int twl6030_enable_irq(struct twl6030_usb *twl) REG_INT_MSK_LINE_C); twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, REG_INT_MSK_STS_C); - twl6030_usb_irq(twl->irq2, twl); - twl6030_usbotg_irq(twl->irq1, twl); return 0; } @@ -301,10 +317,10 @@ static void otg_set_vbus_work(struct work_struct *data) */ if (twl->vbus_enable) - twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, + twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40, CHARGERUSB_CTRL1); else - twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, + twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00, CHARGERUSB_CTRL1); } @@ -371,6 +387,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not create sysfs file\n"); INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); + INIT_DELAYED_WORK(&twl->get_status_work, twl6030_status_work); status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -395,6 +412,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) twl->asleep = 0; twl6030_enable_irq(twl); + schedule_delayed_work(&twl->get_status_work, HZ); dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); return 0; @@ -404,6 +422,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); + cancel_delayed_work(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 000f9750149f..7be4e7d57ace 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -799,8 +799,10 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); + struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); - return info->dma_map_ctrl(pkt, map); + return info->dma_map_ctrl(chan->device->dev, pkt, map); } static void usbhsf_dma_complete(void *arg); @@ -881,12 +883,12 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) if (!fifo) goto usbhsf_pio_prepare_push; - if (usbhsf_dma_map(pkt) < 0) - goto usbhsf_pio_prepare_push; - ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) - goto usbhsf_pio_prepare_push_unmap; + goto usbhsf_pio_prepare_push; + + if (usbhsf_dma_map(pkt) < 0) + goto usbhsf_pio_prepare_push_unselect; pkt->trans = len; @@ -896,8 +898,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) return 0; -usbhsf_pio_prepare_push_unmap: - usbhsf_dma_unmap(pkt); +usbhsf_pio_prepare_push_unselect: + usbhsf_fifo_unselect(pipe, fifo); usbhsf_pio_prepare_push: /* * change handler to PIO diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 53d104b56ef1..30345c2d01be 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -191,13 +191,12 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, /* * dma map/unmap */ -static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, + int map) { struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; struct usbhs_pipe *pipe = pkt->pipe; - struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); enum dma_data_direction dir; int ret = 0; @@ -207,13 +206,13 @@ static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) /* it can not use scatter/gather */ WARN_ON(req->num_sgs); - ret = usb_gadget_map_request(&gpriv->gadget, req, dir); + ret = usb_gadget_map_request_by_dev(dma_dev, req, dir); if (ret < 0) return ret; pkt->dma = req->dma; } else { - usb_gadget_unmap_request(&gpriv->gadget, req, dir); + usb_gadget_unmap_request_by_dev(dma_dev, req, dir); } return ret; diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 1a8e4c45c4c5..3bf0b72eb359 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -929,7 +929,8 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, /* * dma map functions */ -static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +static int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, + int map) { if (map) { struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 78e9dba701c4..c238772b9e9e 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -391,9 +391,8 @@ void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) /* * pipe setup */ -static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, - int is_host, - int dir_in) +static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, + int dir_in, u16 *pipecfg) { u16 type = 0; u16 bfre = 0; @@ -451,14 +450,14 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, /* EPNUM */ epnum = 0; /* see usbhs_pipe_config_update() */ - - return type | - bfre | - dblb | - cntmd | - dir | - shtnak | - epnum; + *pipecfg = type | + bfre | + dblb | + cntmd | + dir | + shtnak | + epnum; + return 0; } static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) @@ -655,7 +654,8 @@ static void usbhsp_put_pipe(struct usbhs_pipe *pipe) } void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) + int (*dma_map_ctrl)(struct device *dma_dev, + struct usbhs_pkt *pkt, int map)) { struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct usbhs_pipe *pipe; @@ -702,7 +702,11 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, return NULL; } - pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in); + if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { + dev_err(dev, "can't setup pipe\n"); + return NULL; + } + pipebuf = usbhsp_setup_pipebuff(pipe); usbhsp_pipe_select(pipe); diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 7835747f9803..95185fdb29b1 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -47,7 +47,8 @@ struct usbhs_pipe_info { struct usbhs_pipe *pipe; int size; /* array size of "pipe" */ - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map); + int (*dma_map_ctrl)(struct device *dma_dev, struct usbhs_pkt *pkt, + int map); }; /* @@ -84,7 +85,8 @@ int usbhs_pipe_is_running(struct usbhs_pipe *pipe); void usbhs_pipe_running(struct usbhs_pipe *pipe, int running); void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); + int (*dma_map_ctrl)(struct device *dma_dev, + struct usbhs_pkt *pkt, int map)); int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); void usbhs_pipe_clear(struct usbhs_pipe *pipe); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index a66b01bb1fa1..8967715fe6fc 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -127,7 +127,7 @@ static int usb_console_setup(struct console *co, char *options) info->port = port; ++port->port.count; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { + if (!tty_port_initialized(&port->port)) { if (serial->type->set_termios) { /* * allocate a fake tty so the driver can initialize @@ -168,7 +168,7 @@ static int usb_console_setup(struct console *co, char *options) tty_port_tty_set(&port->port, NULL); tty_kref_put(tty); } - set_bit(ASYNCB_INITIALIZED, &port->port.flags); + tty_port_set_initialized(&port->port, 1); } /* Now that any required fake tty operations are completed restore * the tty port count */ diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 7c9f25e9c422..96a70789b4c2 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -331,6 +331,42 @@ struct cp210x_comm_status { */ #define PURGE_ALL 0x000f +/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */ +struct cp210x_flow_ctl { + __le32 ulControlHandshake; + __le32 ulFlowReplace; + __le32 ulXonLimit; + __le32 ulXoffLimit; +} __packed; + +/* cp210x_flow_ctl::ulControlHandshake */ +#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0) +#define CP210X_SERIAL_DTR_SHIFT(_mode) (_mode) +#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3) +#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4) +#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5) +#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6) + +/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */ +#define CP210X_SERIAL_DTR_INACTIVE 0 +#define CP210X_SERIAL_DTR_ACTIVE 1 +#define CP210X_SERIAL_DTR_FLOW_CTL 2 + +/* cp210x_flow_ctl::ulFlowReplace */ +#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0) +#define CP210X_SERIAL_AUTO_RECEIVE BIT(1) +#define CP210X_SERIAL_ERROR_CHAR BIT(2) +#define CP210X_SERIAL_NULL_STRIPPING BIT(3) +#define CP210X_SERIAL_BREAK_CHAR BIT(4) +#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6) +#define CP210X_SERIAL_RTS_SHIFT(_mode) (_mode << 6) +#define CP210X_SERIAL_XOFF_CONTINUE BIT(31) + +/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */ +#define CP210X_SERIAL_RTS_INACTIVE 0 +#define CP210X_SERIAL_RTS_ACTIVE 1 +#define CP210X_SERIAL_RTS_FLOW_CTL 2 + /* * Reads a variable-sized block of CP210X_ registers, identified by req. * Returns data into buf in native USB byte order. @@ -698,9 +734,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, { struct device *dev = &port->dev; unsigned int cflag; - u8 modem_ctl[16]; + struct cp210x_flow_ctl flow_ctl; u32 baud; u16 bits; + u32 ctl_hs; cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud); @@ -796,9 +833,10 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, break; } - cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl, - sizeof(modem_ctl)); - if (modem_ctl[0] & 0x08) { + cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, + sizeof(flow_ctl)); + ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); + if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) { dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); cflag |= CRTSCTS; } else { @@ -867,7 +905,6 @@ static void cp210x_set_termios(struct tty_struct *tty, struct device *dev = &port->dev; unsigned int cflag, old_cflag; u16 bits; - u8 modem_ctl[16]; cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; @@ -951,35 +988,44 @@ static void cp210x_set_termios(struct tty_struct *tty, } if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - - /* Only bytes 0, 4 and 7 out of first 8 have functional bits */ - - cp210x_read_reg_block(port, CP210X_GET_FLOW, modem_ctl, - sizeof(modem_ctl)); - dev_dbg(dev, "%s - read modem controls = %02x .. .. .. %02x .. .. %02x\n", - __func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]); - + struct cp210x_flow_ctl flow_ctl; + u32 ctl_hs; + u32 flow_repl; + + cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, + sizeof(flow_ctl)); + ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); + flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); + dev_dbg(dev, "%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n", + __func__, ctl_hs, flow_repl); + + ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE; + ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE; + ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY; + ctl_hs &= ~CP210X_SERIAL_DTR_MASK; + ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE); if (cflag & CRTSCTS) { - modem_ctl[0] &= ~0x7B; - modem_ctl[0] |= 0x09; - modem_ctl[4] = 0x80; - /* FIXME - why clear reserved bits just read? */ - modem_ctl[5] = 0; - modem_ctl[6] = 0; - modem_ctl[7] = 0; + ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE; + + flow_repl &= ~CP210X_SERIAL_RTS_MASK; + flow_repl |= CP210X_SERIAL_RTS_SHIFT( + CP210X_SERIAL_RTS_FLOW_CTL); dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); } else { - modem_ctl[0] &= ~0x7B; - modem_ctl[0] |= 0x01; - /* FIXME - OR here instead of assignment looks wrong */ - modem_ctl[4] |= 0x40; + ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE; + + flow_repl &= ~CP210X_SERIAL_RTS_MASK; + flow_repl |= CP210X_SERIAL_RTS_SHIFT( + CP210X_SERIAL_RTS_ACTIVE); dev_dbg(dev, "%s - flow control = NONE\n", __func__); } - dev_dbg(dev, "%s - write modem controls = %02x .. .. .. %02x .. .. %02x\n", - __func__, modem_ctl[0], modem_ctl[4], modem_ctl[7]); - cp210x_write_reg_block(port, CP210X_SET_FLOW, modem_ctl, - sizeof(modem_ctl)); + dev_dbg(dev, "%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n", + __func__, ctl_hs, flow_repl); + flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs); + flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); + cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl, + sizeof(flow_ctl)); } } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 16e8e37b3b36..6a1df9e824ca 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -699,8 +699,7 @@ static void digi_set_termios(struct tty_struct *tty, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!C_CRTSCTS(tty) || - !test_bit(TTY_THROTTLED, &tty->flags)) + if (!C_CRTSCTS(tty) || !tty_throttled(tty)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3a814e802dee..00820809139a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -93,27 +93,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); -static struct ftdi_sio_quirk ftdi_jtag_quirk = { +static const struct ftdi_sio_quirk ftdi_jtag_quirk = { .probe = ftdi_jtag_probe, }; -static struct ftdi_sio_quirk ftdi_NDI_device_quirk = { +static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = { .probe = ftdi_NDI_device_setup, }; -static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { +static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; -static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { +static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { .port_probe = ftdi_HE_TIRA1_setup, }; -static struct ftdi_sio_quirk ftdi_stmclite_quirk = { +static const struct ftdi_sio_quirk ftdi_stmclite_quirk = { .probe = ftdi_stmclite_probe, }; -static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { +static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = { .probe = ftdi_8u2232c_probe, }; @@ -1775,7 +1775,7 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) static int ftdi_sio_probe(struct usb_serial *serial, const struct usb_device_id *id) { - struct ftdi_sio_quirk *quirk = + const struct ftdi_sio_quirk *quirk = (struct ftdi_sio_quirk *)id->driver_info; if (quirk && quirk->probe) { @@ -1792,7 +1792,7 @@ static int ftdi_sio_probe(struct usb_serial *serial, static int ftdi_sio_port_probe(struct usb_serial_port *port) { struct ftdi_private *priv; - struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); + const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 54e170dd3dad..ae8c0365abd6 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -473,7 +473,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. */ - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) return true; spin_lock_irqsave(&port->lock, flags); @@ -503,7 +503,7 @@ 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 && !test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!ret && !tty_port_initialized(&port->port)) ret = -EIO; return ret; @@ -606,7 +606,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; if (port->bulk_in_size) { diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f3007ecdd1b4..11c05ce2f35f 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2849,14 +2849,16 @@ static int edge_startup(struct usb_serial *serial) /* not set up yet, so do it now */ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->interrupt_read_urb) - return -ENOMEM; + if (!edge_serial->interrupt_read_urb) { + response = -ENOMEM; + break; + } edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!edge_serial->interrupt_in_buffer) { - usb_free_urb(edge_serial->interrupt_read_urb); - return -ENOMEM; + response = -ENOMEM; + break; } edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress; @@ -2884,14 +2886,16 @@ static int edge_startup(struct usb_serial *serial) /* not set up yet, so do it now */ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->read_urb) - return -ENOMEM; + if (!edge_serial->read_urb) { + response = -ENOMEM; + break; + } edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!edge_serial->bulk_in_buffer) { - usb_free_urb(edge_serial->read_urb); - return -ENOMEM; + response = -ENOMEM; + break; } edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress; @@ -2917,9 +2921,22 @@ static int edge_startup(struct usb_serial *serial) } } - if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) { - dev_err(ddev, "Error - the proper endpoints were not found!\n"); - return -ENODEV; + if (response || !interrupt_in_found || !bulk_in_found || + !bulk_out_found) { + if (!response) { + dev_err(ddev, "expected endpoints not found\n"); + response = -ENODEV; + } + + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + + kfree(edge_serial); + + return response; } /* start interrupt read for this edgeport this interrupt will @@ -2942,16 +2959,9 @@ static void edge_disconnect(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - /* stop reads and writes on all ports */ - /* free up our endpoint stuff */ if (edge_serial->is_epic) { usb_kill_urb(edge_serial->interrupt_read_urb); - usb_free_urb(edge_serial->interrupt_read_urb); - kfree(edge_serial->interrupt_in_buffer); - usb_kill_urb(edge_serial->read_urb); - usb_free_urb(edge_serial->read_urb); - kfree(edge_serial->bulk_in_buffer); } } @@ -2964,6 +2974,16 @@ static void edge_release(struct usb_serial *serial) { struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + if (edge_serial->is_epic) { + usb_kill_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_kill_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + kfree(edge_serial); } diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index b6bd8e4a6486..1f9414bdd649 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -255,7 +255,7 @@ static int keyspan_write(struct tty_struct *tty, return count; } - dev_dbg(&port->dev, "%s - endpoint %d flip %d\n", + dev_dbg(&port->dev, "%s - endpoint %x flip %d\n", __func__, usb_pipeendpoint(this_urb->pipe), flip); if (this_urb->status == -EINPROGRESS) { @@ -300,7 +300,7 @@ static void usa26_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", __func__, status, endpoint); return; } @@ -393,7 +393,8 @@ static void usa26_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } if (urb->actual_length != 9) { @@ -452,7 +453,7 @@ static void usa28_indat_callback(struct urb *urb) do { if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", __func__, status, usb_pipeendpoint(urb->pipe)); return; } @@ -511,7 +512,8 @@ static void usa28_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } @@ -591,7 +593,8 @@ static void usa49_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } @@ -646,7 +649,7 @@ static void usa49_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", + dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", __func__, status, endpoint); return; } @@ -698,7 +701,8 @@ static void usa49wg_indat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } @@ -774,8 +778,8 @@ static void usa90_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n", - __func__, status, endpoint); + dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", + __func__, status, endpoint); return; } @@ -847,7 +851,8 @@ static void usa90_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } if (urb->actual_length < 14) { @@ -912,7 +917,8 @@ static void usa67_instat_callback(struct urb *urb) serial = urb->context; if (status) { - dev_dbg(&urb->dev->dev, "%s - nonzero status: %x\n", __func__, status); + dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", + __func__, status); return; } @@ -1082,12 +1088,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) return 0; } -static inline void stop_urb(struct urb *urb) -{ - if (urb && urb->status == -EINPROGRESS) - usb_kill_urb(urb); -} - static void keyspan_dtr_rts(struct usb_serial_port *port, int on) { struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); @@ -1114,10 +1114,10 @@ static void keyspan_close(struct usb_serial_port *port) p_priv->out_flip = 0; p_priv->in_flip = 0; - stop_urb(p_priv->inack_urb); + usb_kill_urb(p_priv->inack_urb); for (i = 0; i < 2; i++) { - stop_urb(p_priv->in_urbs[i]); - stop_urb(p_priv->out_urbs[i]); + usb_kill_urb(p_priv->in_urbs[i]); + usb_kill_urb(p_priv->out_urbs[i]); } } @@ -1221,8 +1221,8 @@ static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *se if (ep->bEndpointAddress == endpoint) return ep; } - dev_warn(&serial->interface->dev, "found no endpoint descriptor for " - "endpoint %x\n", endpoint); + dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n", + endpoint); return NULL; } @@ -1237,7 +1237,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, if (endpoint == -1) return NULL; /* endpoint not needed */ - dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint); + dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n", + __func__, endpoint); urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ if (!urb) return NULL; @@ -1572,7 +1573,8 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, return -1; } - dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); + dev_dbg(&port->dev, "%s - endpoint %x\n", + __func__, usb_pipeendpoint(this_urb->pipe)); /* Save reset port val for resend. Don't overwrite resend for open/close condition. */ @@ -1838,7 +1840,7 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, return -1; } - dev_dbg(&port->dev, "%s - endpoint %d (%d)\n", + dev_dbg(&port->dev, "%s - endpoint %x (%d)\n", __func__, usb_pipeendpoint(this_urb->pipe), device_port); /* Save reset port val for resend. @@ -2365,9 +2367,9 @@ static void keyspan_disconnect(struct usb_serial *serial) s_priv = usb_get_serial_data(serial); - stop_urb(s_priv->instat_urb); - stop_urb(s_priv->glocont_urb); - stop_urb(s_priv->indat_urb); + usb_kill_urb(s_priv->instat_urb); + usb_kill_urb(s_priv->glocont_urb); + usb_kill_urb(s_priv->indat_urb); } static void keyspan_release(struct usb_serial *serial) @@ -2376,6 +2378,10 @@ static void keyspan_release(struct usb_serial *serial) s_priv = usb_get_serial_data(serial); + /* Make sure to unlink the URBs submitted in attach. */ + usb_kill_urb(s_priv->instat_urb); + usb_kill_urb(s_priv->indat_urb); + usb_free_urb(s_priv->instat_urb); usb_free_urb(s_priv->indat_urb); usb_free_urb(s_priv->glocont_urb); @@ -2491,11 +2497,11 @@ static int keyspan_port_remove(struct usb_serial_port *port) p_priv = usb_get_serial_port_data(port); - stop_urb(p_priv->inack_urb); - stop_urb(p_priv->outcont_urb); + usb_kill_urb(p_priv->inack_urb); + usb_kill_urb(p_priv->outcont_urb); for (i = 0; i < 2; i++) { - stop_urb(p_priv->in_urbs[i]); - stop_urb(p_priv->out_urbs[i]); + usb_kill_urb(p_priv->in_urbs[i]); + usb_kill_urb(p_priv->out_urbs[i]); } usb_free_urb(p_priv->inack_urb); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 2eddbe538cda..5608af4a369d 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -2007,6 +2007,7 @@ static void mos7720_release(struct usb_serial *serial) urblist_entry) usb_unlink_urb(urbtrack->urb); spin_unlock_irqrestore(&mos_parport->listlock, flags); + parport_del_port(mos_parport->pp); kref_put(&mos_parport->ref_count, destroy_mos_parport); } diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 31a8b47f1ac6..c88215a0fa3d 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -503,7 +503,7 @@ static void mxuport_process_read_urb_demux_data(struct urb *urb) return; } - if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + if (tty_port_initialized(&demux_port->port)) { ch = data + HEADER_SIZE; mxuport_process_read_urb_data(demux_port, ch, rcv_len); } else { @@ -544,7 +544,7 @@ static void mxuport_process_read_urb_demux_event(struct urb *urb) } demux_port = serial->port[rcv_port]; - if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { + if (tty_port_initialized(&demux_port->port)) { ch = data + HEADER_SIZE; rcv_event = get_unaligned_be16(data + 2); mxuport_process_read_urb_event(demux_port, ch, @@ -1259,6 +1259,15 @@ static int mxuport_attach(struct usb_serial *serial) return 0; } +static void mxuport_release(struct usb_serial *serial) +{ + struct usb_serial_port *port0 = serial->port[0]; + struct usb_serial_port *port1 = serial->port[1]; + + usb_serial_generic_close(port1); + usb_serial_generic_close(port0); +} + static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port) { struct mxuport_port *mxport = usb_get_serial_port_data(port); @@ -1339,7 +1348,7 @@ static int mxuport_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; r = usb_serial_generic_write_start(port, GFP_NOIO); @@ -1361,6 +1370,7 @@ static struct usb_serial_driver mxuport_device = { .probe = mxuport_probe, .port_probe = mxuport_port_probe, .attach = mxuport_attach, + .release = mxuport_release, .calc_num_ports = mxuport_calc_num_ports, .open = mxuport_open, .close = mxuport_close, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c6f497f16526..d96d423d00e6 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -375,18 +375,22 @@ static void option_instat_callback(struct urb *urb); #define HAIER_PRODUCT_CE81B 0x10f8 #define HAIER_PRODUCT_CE100 0x2009 -/* Cinterion (formerly Siemens) products */ -#define SIEMENS_VENDOR_ID 0x0681 -#define CINTERION_VENDOR_ID 0x1e2d +/* Gemalto's Cinterion products (formerly Siemens) */ +#define SIEMENS_VENDOR_ID 0x0681 +#define CINTERION_VENDOR_ID 0x1e2d +#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 #define CINTERION_PRODUCT_HC25_MDM 0x0047 -#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 +#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ #define CINTERION_PRODUCT_HC28_MDM 0x004C -#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ #define CINTERION_PRODUCT_EU3_E 0x0051 #define CINTERION_PRODUCT_EU3_P 0x0052 #define CINTERION_PRODUCT_PH8 0x0053 #define CINTERION_PRODUCT_AHXX 0x0055 #define CINTERION_PRODUCT_PLXX 0x0060 +#define CINTERION_PRODUCT_PH8_2RMNET 0x0082 +#define CINTERION_PRODUCT_PH8_AUDIO 0x0083 +#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084 +#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -633,6 +637,10 @@ static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { .reserved = BIT(1) | BIT(2) | BIT(3), }; +static const struct option_blacklist_info cinterion_rmnet2_blacklist = { + .reserved = BIT(4) | BIT(5), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1602,7 +1610,79 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff42, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff43, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff44, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff45, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff46, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff47, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff48, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff49, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4a, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff4f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff50, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff51, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff52, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff53, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff54, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff55, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff56, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff57, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff58, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff59, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5a, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff5f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff60, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff61, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff62, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff63, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff64, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff65, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff66, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff67, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff68, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff69, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6a, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff6f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff70, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff71, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff72, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff73, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff74, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff75, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff76, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff77, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff78, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff79, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7a, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7b, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7c, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7d, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7e, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff7f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff80, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff81, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff82, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff83, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff84, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff85, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff86, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff87, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff88, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff89, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8a, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) }, @@ -1613,6 +1693,61 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff9f, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa0, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa1, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa2, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa3, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa4, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa5, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa6, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa7, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa8, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffa9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaa, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffab, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffac, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffae, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffaf, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb0, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb1, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb2, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb3, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb4, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb5, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb6, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb7, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb8, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffb9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffba, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbb, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbc, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbd, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbe, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffbf, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc0, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc1, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc2, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc3, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc4, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc5, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc6, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc7, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc8, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffc9, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffca, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcb, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcc, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcd, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffce, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffcf, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd0, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd1, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd2, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd3, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd4, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffd5, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffec, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffee, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xfff6, 0xff, 0xff, 0xff) }, @@ -1712,7 +1847,13 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_2RMNET, 0xff), + .driver_info = (kernel_ulong_t)&cinterion_rmnet2_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8_AUDIO, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) }, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 2df8ad5ede89..85acb50a7ee2 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -141,6 +141,7 @@ static void qt2_release(struct usb_serial *serial) serial_priv = usb_get_serial_data(serial); + usb_kill_urb(serial_priv->read_urb); usb_free_urb(serial_priv->read_urb); kfree(serial_priv->read_buffer); kfree(serial_priv); diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 07d1ecd564f7..e1994e264cc0 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -776,7 +776,7 @@ static void sierra_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to ASYNC_INITIALIZED. + * resumed, but no need to hold it due to initialized */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) @@ -1039,7 +1039,7 @@ static int sierra_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; err = sierra_submit_delayed_urbs(port); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 2694df2f4559..e7dbbef2af2a 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -80,6 +80,7 @@ struct ti_device { int td_open_port_count; struct usb_serial *td_serial; int td_is_3410; + bool td_rs485_only; int td_urb_error; }; @@ -160,6 +161,11 @@ static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, { } /* terminator */ }; @@ -193,6 +199,11 @@ static const struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) }, + { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) }, { } /* terminator */ }; @@ -277,6 +288,11 @@ MODULE_FIRMWARE("mts_gsm.fw"); MODULE_FIRMWARE("mts_edge.fw"); MODULE_FIRMWARE("mts_mt9234mu.fw"); MODULE_FIRMWARE("mts_mt9234zba.fw"); +MODULE_FIRMWARE("moxa/moxa-1110.fw"); +MODULE_FIRMWARE("moxa/moxa-1130.fw"); +MODULE_FIRMWARE("moxa/moxa-1131.fw"); +MODULE_FIRMWARE("moxa/moxa-1150.fw"); +MODULE_FIRMWARE("moxa/moxa-1151.fw"); module_param(closing_wait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(closing_wait, @@ -292,6 +308,9 @@ static int ti_startup(struct usb_serial *serial) { struct ti_device *tdev; struct usb_device *dev = serial->dev; + struct usb_host_interface *cur_altsetting; + int num_endpoints; + u16 vid, pid; int status; dev_dbg(&dev->dev, @@ -315,8 +334,22 @@ static int ti_startup(struct usb_serial *serial) dev_dbg(&dev->dev, "%s - device type is %s\n", __func__, tdev->td_is_3410 ? "3410" : "5052"); - /* if we have only 1 configuration, download firmware */ - if (dev->descriptor.bNumConfigurations == 1) { + vid = le16_to_cpu(dev->descriptor.idVendor); + pid = le16_to_cpu(dev->descriptor.idProduct); + if (vid == MXU1_VENDOR_ID) { + switch (pid) { + case MXU1_1130_PRODUCT_ID: + case MXU1_1131_PRODUCT_ID: + tdev->td_rs485_only = true; + break; + } + } + + cur_altsetting = serial->interface->cur_altsetting; + num_endpoints = cur_altsetting->desc.bNumEndpoints; + + /* if we have only 1 configuration and 1 endpoint, download firmware */ + if (dev->descriptor.bNumConfigurations == 1 && num_endpoints == 1) { status = ti_download_firmware(tdev); if (status != 0) @@ -371,7 +404,11 @@ static int ti_port_probe(struct usb_serial_port *port) port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); tport->tp_port = port; tport->tp_tdev = usb_get_serial_data(port->serial); - tport->tp_uart_mode = 0; /* default is RS232 */ + + if (tport->tp_tdev->td_rs485_only) + tport->tp_uart_mode = TI_UART_485_RECEIVER_DISABLED; + else + tport->tp_uart_mode = TI_UART_232; usb_set_serial_port_data(port, tport); @@ -1450,6 +1487,16 @@ static int ti_download_firmware(struct ti_device *tdev) const struct firmware *fw_p; char buf[32]; + if (le16_to_cpu(dev->descriptor.idVendor) == MXU1_VENDOR_ID) { + snprintf(buf, + sizeof(buf), + "moxa/moxa-%04x.fw", + le16_to_cpu(dev->descriptor.idProduct)); + + status = request_firmware(&fw_p, buf, &dev->dev); + goto check_firmware; + } + /* try ID specific firmware first, then try generic firmware */ sprintf(buf, "ti_usb-v%04x-p%04x.fw", le16_to_cpu(dev->descriptor.idVendor), @@ -1487,6 +1534,8 @@ static int ti_download_firmware(struct ti_device *tdev) } status = request_firmware(&fw_p, buf, &dev->dev); } + +check_firmware: if (status) { dev_err(&dev->dev, "%s - firmware not found\n", __func__); return -ENOENT; diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 98f35c656c02..bbfd3a184600 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -60,6 +60,14 @@ #define HONEYWELL_VENDOR_ID 0x10ac #define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */ +/* Moxa UPORT 11x0 vendor and product IDs */ +#define MXU1_VENDOR_ID 0x110a +#define MXU1_1110_PRODUCT_ID 0x1110 +#define MXU1_1130_PRODUCT_ID 0x1130 +#define MXU1_1131_PRODUCT_ID 0x1131 +#define MXU1_1150_PRODUCT_ID 0x1150 +#define MXU1_1151_PRODUCT_ID 0x1151 + /* Commands */ #define TI_GET_VERSION 0x01 #define TI_GET_PORT_STATUS 0x02 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 46f1f13b41f1..b1b9bac44016 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -96,7 +96,8 @@ static int allocate_minors(struct usb_serial *serial, int num_ports) mutex_lock(&table_lock); for (i = 0; i < num_ports; ++i) { port = serial->port[i]; - minor = idr_alloc(&serial_minors, port, 0, 0, GFP_KERNEL); + minor = idr_alloc(&serial_minors, port, 0, + USB_SERIAL_TTY_MINORS, GFP_KERNEL); if (minor < 0) goto error; port->minor = minor; @@ -254,7 +255,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) * * Shut down a USB serial port. Serialized against activate by the * tport mutex and kept to matching open/close pairs - * of calls by the ASYNCB_INITIALIZED flag. + * of calls by the initialized flag. * * Not called if tty is console. */ @@ -815,7 +816,7 @@ static int usb_serial_probe(struct usb_interface *interface, } } -#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) +#if IS_ENABLED(CONFIG_USB_SERIAL_PL2303) /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) && diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index be9cb61b4d19..3dfdfc81254b 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -464,7 +464,7 @@ void usb_wwan_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to ASYNC_INITIALIZED. + * resumed, but no need to hold it due to initialized */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) @@ -682,7 +682,7 @@ int usb_wwan_resume(struct usb_serial *serial) for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + if (!tty_port_initialized(&port->port)) continue; portdata = usb_get_serial_port_data(port); diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 171fa7d793bc..1d8b03c81030 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -829,8 +829,10 @@ static int alauda_write_lba(struct us_data *us, u16 lba, pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset]; if (pba == 1) { - /* Maybe it is impossible to write to PBA 1. - Fake success, but don't do anything. */ + /* + * Maybe it is impossible to write to PBA 1. + * Fake success, but don't do anything. + */ printk(KERN_WARNING "alauda_write_lba: avoid writing to pba 1\n"); return USB_STOR_TRANSPORT_GOOD; @@ -977,10 +979,12 @@ static int alauda_read_data(struct us_data *us, unsigned long address, usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", pages, lba, page); - /* This is not really an error. It just means - that the block has never been written. - Instead of returning USB_STOR_TRANSPORT_ERROR - it is better to return all zero data. */ + /* + * This is not really an error. It just means + * that the block has never been written. + * Instead of returning USB_STOR_TRANSPORT_ERROR + * it is better to return all zero data. + */ memset(buffer, 0, len); } else { @@ -1222,8 +1226,10 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - /* sure. whatever. not like we can stop the user from popping - the media out of the device (no locking doors, etc) */ + /* + * sure. whatever. not like we can stop the user from popping + * the media out of the device (no locking doors, etc) + */ return USB_STOR_TRANSPORT_GOOD; } diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index c80d3dec9a34..5e4af44d7d9f 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -110,13 +110,17 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) /* first build the ATACB command */ srb->cmd_len = 16; - srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command - this value can change, but most(all ?) manufacturers - keep the cypress default : 0x24 */ + srb->cmnd[0] = 0x24; /* + * bVSCBSignature : vendor-specific command + * this value can change, but most(all ?) manufacturers + * keep the cypress default : 0x24 + */ srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */ - srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med - lba high, device, command are valid */ + srb->cmnd[3] = 0xff - 1; /* + * features, sector count, lba low, lba med + * lba high, device, command are valid + */ srb->cmnd[4] = 1; /* TransferBlockCount : 512 */ if (save_cmnd[0] == ATA_16) { @@ -155,8 +159,7 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) usb_stor_transparent_scsi_command(srb, us); - /* if the device doesn't support ATACB - */ + /* if the device doesn't support ATACB */ if (srb->result == SAM_STAT_CHECK_CONDITION && memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB, sizeof(usb_stor_sense_invalidCDB)) == 0) { @@ -164,7 +167,8 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) goto end; } - /* if ck_cond flags is set, and there wasn't critical error, + /* + * if ck_cond flags is set, and there wasn't critical error, * build the special sense */ if ((srb->result != (DID_ERROR << 16) && @@ -176,11 +180,11 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) unsigned char *desc = sb + 8; int tmp_result; - /* build the command for - * reading the ATA registers */ + /* build the command for reading the ATA registers */ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs)); - /* we use the same command as before, but we set + /* + * we use the same command as before, but we set * the read taskfile bit, for not executing atacb command, * but reading register selected in srb->cmnd[4] */ @@ -204,10 +208,11 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */ sb[3] = 0x1D; - /* XXX we should generate sk, asc, ascq from status and error + /* + * XXX we should generate sk, asc, ascq from status and error * regs * (see 11.1 Error translation ATA device error to SCSI error - * map, and ata_to_sense_error from libata.) + * map, and ata_to_sense_error from libata.) */ /* Sense data is current and format is descriptor. */ @@ -258,7 +263,8 @@ static int cypress_probe(struct usb_interface *intf, if (result) return result; - /* Among CY7C68300 chips, the A revision does not support Cypress ATACB + /* + * Among CY7C68300 chips, the A revision does not support Cypress ATACB * Filter out this revision from EEPROM default descriptor values */ device = interface_to_usbdev(intf); diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index aa4f51944a4a..723197af6ec5 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -1,4 +1,5 @@ -/* Driver for Datafab USB Compact Flash reader +/* + * Driver for Datafab USB Compact Flash reader * * datafab driver v0.1: * @@ -693,18 +694,23 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from - // popping the media out of the device (no locking doors, etc) - // + /* + * sure. whatever. not like we can stop the user from + * popping the media out of the device (no locking doors, etc) + */ return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == START_STOP) { - /* this is used by sd.c'check_scsidisk_media_change to detect - media change */ + /* + * this is used by sd.c'check_scsidisk_media_change to detect + * media change + */ usb_stor_dbg(us, "START_STOP\n"); - /* the first datafab_id_device after a media change returns - an error (determined experimentally) */ + /* + * the first datafab_id_device after a media change returns + * an error (determined experimentally) + */ rc = datafab_id_device(us, info); if (rc == USB_STOR_TRANSPORT_GOOD) { info->sense_key = NO_SENSE; diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c index 5a12c03138f8..8d20804a59e6 100644 --- a/drivers/usb/storage/debug.c +++ b/drivers/usb/storage/debug.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * * Current development and maintenance by: diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index 6b365ce4e610..8ab73299b650 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Debugging Functions Header File * * Current development and maintenance by: diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index d3a17c65a702..02bdaa912164 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -560,8 +560,10 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) /* check bulk status */ residue = le32_to_cpu(bcs->Residue); - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ + /* + * try to compute the actual residue, based on how much data + * was really transferred and what the device tells us + */ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { residue = min(residue, transfer_length); if (us->srb != NULL) @@ -862,9 +864,6 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, u8 ExtBuf[4]; u32 bn = PhyBlockAddr * 0x20 + PageNum; - /* printk(KERN_INFO "MS --- MS_ReaderReadPage, - PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */ - result = ene_load_bincode(us, MS_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1141,8 +1140,6 @@ static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy, struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; - /* printk(KERN_INFO "MS_ReaderCopyBlock --- PhyBlockAddr = %x, - PageNum = %x\n", PhyBlockAddr, PageNum); */ result = ene_load_bincode(us, MS_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1176,8 +1173,6 @@ static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr) int result; u32 bn = PhyBlockAddr; - /* printk(KERN_INFO "MS --- ms_read_eraseblock, - PhyBlockAddr = %x\n", PhyBlockAddr); */ result = ene_load_bincode(us, MS_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1255,8 +1250,6 @@ static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr, struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; - /* printk("MS --- MS_LibOverwriteExtra, - PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */ result = ene_load_bincode(us, MS_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1342,7 +1335,6 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, int result; u8 ExtBuf[4]; - /* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */ memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = 0x4; @@ -1541,9 +1533,6 @@ static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock, struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; int result; - /* printk("MS_LibReadExtraBlock --- PhyBlock = %x, - PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen); */ - /* Read Extra Data */ memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); @@ -2390,8 +2379,10 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface) /* Report the reset to the SCSI core */ usb_stor_reset_resume(iface); - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ + /* + * FIXME: Notify the subdrivers that they need to reinitialize + * the device + */ info->Power_IsResum = true; /*info->SD_Status.Ready = 0; */ info->SD_Status = *(struct SD_STATUS *)&tmp; diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 3f2b08966b9d..c0a5d954414b 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -1,4 +1,5 @@ -/* Driver for Freecom USB/IDE adaptor +/* + * Driver for Freecom USB/IDE adaptor * * Freecom v0.1: * @@ -84,25 +85,33 @@ struct freecom_status { u8 Pad[60]; }; -/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide - * register. */ +/* + * Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide + * register. + */ #define FCM_INT_STATUS 0x02 /* INDEX_STAT */ #define FCM_STATUS_BUSY 0x80 -/* These are the packet types. The low bit indicates that this command - * should wait for an interrupt. */ +/* + * These are the packet types. The low bit indicates that this command + * should wait for an interrupt. + */ #define FCM_PACKET_ATAPI 0x21 #define FCM_PACKET_STATUS 0x20 -/* Receive data from the IDE interface. The ATAPI packet has already - * waited, so the data should be immediately available. */ +/* + * Receive data from the IDE interface. The ATAPI packet has already + * waited, so the data should be immediately available. + */ #define FCM_PACKET_INPUT 0x81 /* Send data to the IDE interface. */ #define FCM_PACKET_OUTPUT 0x01 -/* Write a value to an ide register. Or the ide register to write after - * munging the address a bit. */ +/* + * Write a value to an ide register. Or the ide register to write after + * munging the address a bit. + */ #define FCM_PACKET_IDE_WRITE 0x40 #define FCM_PACKET_IDE_READ 0xC0 @@ -251,16 +260,20 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) result = usb_stor_bulk_transfer_buf (us, opipe, fcb, FCM_PACKET_LENGTH, NULL); - /* The Freecom device will only fail if there is something wrong in + /* + * The Freecom device will only fail if there is something wrong in * USB land. It returns the status in its own registers, which - * come back in the bulk pipe. */ + * come back in the bulk pipe. + */ if (result != USB_STOR_XFER_GOOD) { usb_stor_dbg(us, "freecom transport error\n"); return USB_STOR_TRANSPORT_ERROR; } - /* There are times we can optimize out this status read, but it - * doesn't hurt us to always do it now. */ + /* + * There are times we can optimize out this status read, but it + * doesn't hurt us to always do it now. + */ result = usb_stor_bulk_transfer_buf (us, ipipe, fst, FCM_STATUS_PACKET_LENGTH, &partial); usb_stor_dbg(us, "foo Status result %d %u\n", result, partial); @@ -269,7 +282,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) US_DEBUG(pdump(us, (void *)fst, partial)); - /* The firmware will time-out commands after 20 seconds. Some commands + /* + * The firmware will time-out commands after 20 seconds. Some commands * can legitimately take longer than this, so we use a different * command that only waits for the interrupt and then sends status, * without having to send a new ATAPI command to the device. @@ -291,7 +305,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) result = usb_stor_bulk_transfer_buf (us, opipe, fcb, FCM_PACKET_LENGTH, NULL); - /* The Freecom device will only fail if there is something + /* + * The Freecom device will only fail if there is something * wrong in USB land. It returns the status in its own * registers, which come back in the bulk pipe. */ @@ -318,9 +333,11 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_FAILED; } - /* The device might not have as much data available as we + /* + * The device might not have as much data available as we * requested. If you ask for more than the device has, this reads - * and such will hang. */ + * and such will hang. + */ usb_stor_dbg(us, "Device indicates that it has %d bytes available\n", le16_to_cpu(fst->Count)); usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb)); @@ -344,16 +361,20 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) length); } - /* What we do now depends on what direction the data is supposed to - * move in. */ + /* + * What we do now depends on what direction the data is supposed to + * move in. + */ switch (us->srb->sc_data_direction) { case DMA_FROM_DEVICE: /* catch bogus "read 0 length" case */ if (!length) break; - /* Make sure that the status indicates that the device - * wants data as well. */ + /* + * Make sure that the status indicates that the device + * wants data as well. + */ if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n"); return USB_STOR_TRANSPORT_FAILED; @@ -384,8 +405,10 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) /* catch bogus "write 0 length" case */ if (!length) break; - /* Make sure the status indicates that the device wants to - * send us data. */ + /* + * Make sure the status indicates that the device wants to + * send us data. + */ /* !!IMPLEMENT!! */ result = freecom_writedata (srb, us, ipipe, opipe, length); if (result != USB_STOR_TRANSPORT_GOOD) @@ -431,7 +454,8 @@ static int init_freecom(struct us_data *us) int result; char *buffer = us->iobuf; - /* The DMA-mapped I/O buffer is 64 bytes long, just right for + /* + * The DMA-mapped I/O buffer is 64 bytes long, just right for * all our packets. No need to allocate any extra buffer space. */ @@ -440,7 +464,8 @@ static int init_freecom(struct us_data *us) buffer[32] = '\0'; usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer); - /* Special thanks to the people at Freecom for providing me with + /* + * Special thanks to the people at Freecom for providing me with * this "magic sequence", which they use in their Windows and MacOS * drivers to make sure that all the attached perhiperals are * properly reset. diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 31fa2e92065b..d9d8c17e05d1 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -1,4 +1,5 @@ -/* Special Initializers for certain USB Mass Storage devices +/* + * Special Initializers for certain USB Mass Storage devices * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -42,8 +43,10 @@ #include "debug.h" #include "transport.h" -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ +/* + * This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target + * mode + */ int usb_stor_euscsi_init(struct us_data *us) { int result; @@ -57,8 +60,10 @@ int usb_stor_euscsi_init(struct us_data *us) return 0; } -/* This function is required to activate all four slots on the UCR-61S2B - * flash reader */ +/* + * This function is required to activate all four slots on the UCR-61S2B + * flash reader + */ int usb_stor_ucr61s2b_init(struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf; diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 529327fbb06b..039abf4d1cb7 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -1,4 +1,5 @@ -/* Header file for Special Initializers for certain USB Mass Storage devices +/* + * Header file for Special Initializers for certain USB Mass Storage devices * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -38,12 +39,16 @@ #include "usb.h" #include "transport.h" -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ +/* + * This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target + * mode + */ int usb_stor_euscsi_init(struct us_data *us); -/* This function is required to activate all four slots on the UCR-61S2B - * flash reader */ +/* + * This function is required to activate all four slots on the UCR-61S2B + * flash reader + */ int usb_stor_ucr61s2b_init(struct us_data *us); /* This places the HUAWEI E220 devices in multi-port mode */ diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 39afd7045c43..fba4005dd737 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1,4 +1,5 @@ -/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC +/* + * Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC * * Current development and maintenance: * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) @@ -628,7 +629,8 @@ static void isd200_invoke_transport( struct us_data *us, srb->cmd_len = sizeof(ataCdb->generic); transferStatus = usb_stor_Bulk_transport(srb, us); - /* if the command gets aborted by the higher layers, we need to + /* + * if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { @@ -695,15 +697,18 @@ static void isd200_invoke_transport( struct us_data *us, } } - /* Regardless of auto-sense, if we _know_ we have an error + /* + * Regardless of auto-sense, if we _know_ we have an error * condition, show that in the result code */ if (transferStatus == USB_STOR_TRANSPORT_FAILED) srb->result = SAM_STAT_CHECK_CONDITION; return; - /* abort processing: the bulk-only transport requires a reset - * following an abort */ + /* + * abort processing: the bulk-only transport requires a reset + * following an abort + */ Handle_Abort: srb->result = DID_ABORT << 16; @@ -965,20 +970,22 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, info->DeviceHead = master_slave; break; } - /* check Cylinder High/Low to - determine if it is an ATAPI device - */ + /* + * check Cylinder High/Low to + * determine if it is an ATAPI device + */ else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && regs[ATA_REG_LCYL_OFFSET] == 0x14) { - /* It seems that the RICOH - MP6200A CD/RW drive will - report itself okay as a - slave when it is really a - master. So this check again - as a master device just to - make sure it doesn't report - itself okay as a master also - */ + /* + * It seems that the RICOH + * MP6200A CD/RW drive will + * report itself okay as a + * slave when it is really a + * master. So this check again + * as a master device just to + * make sure it doesn't report + * itself okay as a master also + */ if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && !recheckAsMaster) { usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n"); @@ -1176,9 +1183,11 @@ static int isd200_get_inquiry_data( struct us_data *us ) if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { usb_stor_dbg(us, " Device supports Media Status Notification\n"); - /* Indicate that it is enabled, even though it is not - * This allows the lock/unlock of the media to work - * correctly. + /* + * Indicate that it is enabled, even + * though it is not. + * This allows the lock/unlock of the + * media to work correctly. */ info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; } @@ -1197,7 +1206,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) usb_stor_dbg(us, "Protocol changed to: %s\n", us->protocol_name); - /* Free driver structure */ + /* Free driver structure */ us->extra_destructor(info); kfree(info); us->extra = NULL; diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index ee613e258db0..011e5270690a 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -1,4 +1,5 @@ -/* Driver for Lexar "Jumpshot" Compact Flash reader +/* + * Driver for Lexar "Jumpshot" Compact Flash reader * * jumpshot driver v0.1: * @@ -618,18 +619,23 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from popping - // the media out of the device (no locking doors, etc) - // + /* + * sure. whatever. not like we can stop the user from popping + * the media out of the device (no locking doors, etc) + */ return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == START_STOP) { - /* this is used by sd.c'check_scsidisk_media_change to detect - media change */ + /* + * this is used by sd.c'check_scsidisk_media_change to detect + * media change + */ usb_stor_dbg(us, "START_STOP\n"); - /* the first jumpshot_id_device after a media change returns - an error (determined experimentally) */ + /* + * the first jumpshot_id_device after a media change returns + * an error (determined experimentally) + */ rc = jumpshot_id_device(us, info); if (rc == USB_STOR_TRANSPORT_GOOD) { info->sense_key = NO_SENSE; diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index ae201e69475c..f9d407f0b508 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -1,4 +1,5 @@ -/* Driver for Rio Karma +/* + * Driver for Rio Karma * * (c) 2006 Bob Copeland <me@bobcopeland.com> * (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk> diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index b2b35b1d7de8..57282f12317b 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -65,7 +65,8 @@ static int option_rezero(struct us_data *us) goto out; } - /* Some of the devices need to be asked for a response, but we don't + /* + * Some of the devices need to be asked for a response, but we don't * care what that response is. */ usb_stor_bulk_transfer_buf(us, @@ -140,7 +141,8 @@ int option_ms_init(struct us_data *us) usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called"); - /* Additional test for vendor information via INQUIRY, + /* + * Additional test for vendor information via INQUIRY, * because some vendor/product IDs are ambiguous */ result = option_inquiry(us); diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 12e3c2fac642..74c38870a17e 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * * Current development and maintenance by: * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -75,7 +76,8 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) { - /* fix some commands -- this is a form of mode translation + /* + * fix some commands -- this is a form of mode translation * UFI devices only accept 12 byte long commands * * NOTE: This only works because a scsi_cmnd struct field contains @@ -127,7 +129,8 @@ EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command); * Scatter-gather transfer buffer access routines ***********************************************************************/ -/* Copy a buffer of length buflen to/from the srb's transfer buffer. +/* + * Copy a buffer of length buflen to/from the srb's transfer buffer. * Update the **sgptr and *offset variables so that the next copy will * pick up from where this one left off. */ @@ -175,7 +178,8 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, } EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf); -/* Store the contents of buffer into srb's transfer buffer and set the +/* + * Store the contents of buffer into srb's transfer buffer and set the * SCSI residue. */ void usb_stor_set_xfer_buf(unsigned char *buffer, diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h index ffc3e2af0156..a55666880b7b 100644 --- a/drivers/usb/storage/protocol.h +++ b/drivers/usb/storage/protocol.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Protocol Functions Header File * * Current development and maintenance by: diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 20433563a601..4176d1af9bf2 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -1,4 +1,5 @@ -/* Driver for Realtek RTS51xx USB card reader +/* + * Driver for Realtek RTS51xx USB card reader * * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. * @@ -267,8 +268,10 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, if (bcs->Tag != us->tag) return USB_STOR_TRANSPORT_ERROR; - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ + /* + * try to compute the actual residue, based on how much data + * was really transferred and what the device tells us + */ if (residue) residue = residue < buf_len ? residue : buf_len; @@ -286,7 +289,8 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: - /* phase error -- note that a transport reset will be + /* + * phase error -- note that a transport reset will be * invoked by the invoke_transport() function */ return USB_STOR_TRANSPORT_ERROR; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 90901861bfc0..33eb923df892 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * SCSI layer glue code * * Current development and maintenance by: @@ -58,7 +59,8 @@ #include "transport.h" #include "protocol.h" -/* Vendor IDs for companies that seem to include the READ CAPACITY bug +/* + * Vendor IDs for companies that seem to include the READ CAPACITY bug * in all their devices */ #define VENDOR_ID_NOKIA 0x0421 @@ -87,7 +89,8 @@ static int slave_alloc (struct scsi_device *sdev) */ sdev->inquiry_len = 36; - /* USB has unusual DMA-alignment requirements: Although the + /* + * USB has unusual DMA-alignment requirements: Although the * starting address of each scatter-gather element doesn't matter, * the length of each element except the last must be divisible * by the Bulk maxpacket value. There's currently no way to @@ -115,7 +118,8 @@ static int slave_configure(struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); - /* Many devices have trouble transferring more than 32KB at a time, + /* + * Many devices have trouble transferring more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). */ @@ -128,14 +132,22 @@ static int slave_configure(struct scsi_device *sdev) blk_queue_max_hw_sectors(sdev->request_queue, max_sectors); } else if (sdev->type == TYPE_TAPE) { - /* Tapes need much higher max_sector limits, so just + /* + * Tapes need much higher max_sector limits, so just * raise it to the maximum possible (4 GB / 512) and * let the queue segment size sort out the real limit. */ blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF); + } else if (us->pusb_dev->speed >= USB_SPEED_SUPER) { + /* + * USB3 devices will be limited to 2048 sectors. This gives us + * better throughput on most devices. + */ + blk_queue_max_hw_sectors(sdev->request_queue, 2048); } - /* Some USB host controllers can't do DMA; they have to use PIO. + /* + * Some USB host controllers can't do DMA; they have to use PIO. * They indicate this by setting their dma_mask to NULL. For * such controllers we need to make sure the block layer sets * up bounce buffers in addressable memory. @@ -143,17 +155,21 @@ static int slave_configure(struct scsi_device *sdev) if (!us->pusb_dev->bus->controller->dma_mask) blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH); - /* We can't put these settings in slave_alloc() because that gets + /* + * We can't put these settings in slave_alloc() because that gets * called before the device type is known. Consequently these - * settings can't be overridden via the scsi devinfo mechanism. */ + * settings can't be overridden via the scsi devinfo mechanism. + */ if (sdev->type == TYPE_DISK) { - /* Some vendors seem to put the READ CAPACITY bug into + /* + * Some vendors seem to put the READ CAPACITY bug into * all their devices -- primarily makers of cell phones * and digital cameras. Since these devices always use * flash media and can be expected to have an even number * of sectors, we will always enable the CAPACITY_HEURISTICS - * flag unless told otherwise. */ + * flag unless told otherwise. + */ switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) { case VENDOR_ID_NOKIA: case VENDOR_ID_NIKON: @@ -165,28 +181,36 @@ static int slave_configure(struct scsi_device *sdev) break; } - /* Disk-type devices use MODE SENSE(6) if the protocol + /* + * Disk-type devices use MODE SENSE(6) if the protocol * (SubClass) is Transparent SCSI, otherwise they use - * MODE SENSE(10). */ + * MODE SENSE(10). + */ if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB) sdev->use_10_for_ms = 1; - /* Many disks only accept MODE SENSE transfer lengths of - * 192 bytes (that's what Windows uses). */ + /* + *Many disks only accept MODE SENSE transfer lengths of + * 192 bytes (that's what Windows uses). + */ sdev->use_192_bytes_for_3f = 1; - /* Some devices don't like MODE SENSE with page=0x3f, + /* + * Some devices don't like MODE SENSE with page=0x3f, * which is the command used for checking if a device * is write-protected. Now that we tell the sd driver * to do a 192-byte transfer with this command the * majority of devices work fine, but a few still can't * handle it. The sd driver will simply assume those - * devices are write-enabled. */ + * devices are write-enabled. + */ if (us->fflags & US_FL_NO_WP_DETECT) sdev->skip_ms_page_3f = 1; - /* A number of devices have problems with MODE SENSE for - * page x08, so we will skip it. */ + /* + * A number of devices have problems with MODE SENSE for + * page x08, so we will skip it. + */ sdev->skip_ms_page_8 = 1; /* Some devices don't handle VPD pages correctly */ @@ -198,15 +222,19 @@ static int slave_configure(struct scsi_device *sdev) /* Do not attempt to use WRITE SAME */ sdev->no_write_same = 1; - /* Some disks return the total number of blocks in response + /* + * Some disks return the total number of blocks in response * to READ CAPACITY rather than the highest block number. - * If this device makes that mistake, tell the sd driver. */ + * If this device makes that mistake, tell the sd driver. + */ if (us->fflags & US_FL_FIX_CAPACITY) sdev->fix_capacity = 1; - /* A few disks have two indistinguishable version, one of + /* + * A few disks have two indistinguishable version, one of * which reports the correct capacity and the other does not. - * The sd driver has to guess which is the case. */ + * The sd driver has to guess which is the case. + */ if (us->fflags & US_FL_CAPACITY_HEURISTICS) sdev->guess_capacity = 1; @@ -227,26 +255,34 @@ static int slave_configure(struct scsi_device *sdev) if (sdev->scsi_level > SCSI_SPC_2) us->fflags |= US_FL_SANE_SENSE; - /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable + /* + * USB-IDE bridges tend to report SK = 0x04 (Non-recoverable * Hardware Error) when any low-level error occurs, * recoverable or not. Setting this flag tells the SCSI * midlayer to retry such commands, which frequently will * succeed and fix the error. The worst this can lead to - * is an occasional series of retries that will all fail. */ + * is an occasional series of retries that will all fail. + */ sdev->retry_hwerror = 1; - /* USB disks should allow restart. Some drives spin down - * automatically, requiring a START-STOP UNIT command. */ + /* + * USB disks should allow restart. Some drives spin down + * automatically, requiring a START-STOP UNIT command. + */ sdev->allow_restart = 1; - /* Some USB cardreaders have trouble reading an sdcard's last + /* + * Some USB cardreaders have trouble reading an sdcard's last * sector in a larger then 1 sector read, since the performance - * impact is negligible we set this flag for all USB disks */ + * impact is negligible we set this flag for all USB disks + */ sdev->last_sector_bug = 1; - /* Enable last-sector hacks for single-target devices using + /* + * Enable last-sector hacks for single-target devices using * the Bulk-only transport, unless we already know the - * capacity will be decremented or is correct. */ + * capacity will be decremented or is correct. + */ if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK | US_FL_SCM_MULT_TARG)) && us->protocol == USB_PR_BULK) @@ -262,9 +298,11 @@ static int slave_configure(struct scsi_device *sdev) } else { - /* Non-disk-type devices don't need to blacklist any pages + /* + * Non-disk-type devices don't need to blacklist any pages * or to force 192-byte transfer lengths for MODE SENSE. - * But they do need to use MODE SENSE(10). */ + * But they do need to use MODE SENSE(10). + */ sdev->use_10_for_ms = 1; /* Some (fake) usb cdrom devices don't like READ_DISC_INFO */ @@ -272,7 +310,8 @@ static int slave_configure(struct scsi_device *sdev) sdev->no_read_disc_info = 1; } - /* The CB and CBI transports have no way to pass LUN values + /* + * The CB and CBI transports have no way to pass LUN values * other than the bits in the second byte of a CDB. But those * bits don't get set to the LUN value if the device reports * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily @@ -282,13 +321,17 @@ static int slave_configure(struct scsi_device *sdev) sdev->scsi_level == SCSI_UNKNOWN) us->max_lun = 0; - /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM - * REMOVAL command, so suppress those commands. */ + /* + * Some devices choke when they receive a PREVENT-ALLOW MEDIUM + * REMOVAL command, so suppress those commands. + */ if (us->fflags & US_FL_NOT_LOCKABLE) sdev->lockable = 0; - /* this is to satisfy the compiler, tho I don't think the - * return code is ever checked anywhere. */ + /* + * this is to satisfy the compiler, tho I don't think the + * return code is ever checked anywhere. + */ return 0; } @@ -362,8 +405,10 @@ static int command_abort(struct scsi_cmnd *srb) usb_stor_dbg(us, "%s called\n", __func__); - /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING - * bits are protected by the host lock. */ + /* + * us->srb together with the TIMED_OUT, RESETTING, and ABORTING + * bits are protected by the host lock. + */ scsi_lock(us_to_host(us)); /* Is this command still active? */ @@ -373,11 +418,13 @@ static int command_abort(struct scsi_cmnd *srb) return FAILED; } - /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if + /* + * Set the TIMED_OUT bit. Also set the ABORTING bit, but only if * a device reset isn't already in progress (to avoid interfering * with the reset). Note that we must retain the host lock while * calling usb_stor_stop_transport(); otherwise it might interfere - * with an auto-reset that begins as soon as we release the lock. */ + * with an auto-reset that begins as soon as we release the lock. + */ set_bit(US_FLIDX_TIMED_OUT, &us->dflags); if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) { set_bit(US_FLIDX_ABORTING, &us->dflags); @@ -390,8 +437,10 @@ static int command_abort(struct scsi_cmnd *srb) return SUCCESS; } -/* This invokes the transport reset mechanism to reset the state of the - * device */ +/* + * This invokes the transport reset mechanism to reset the state of the + * device + */ static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); @@ -419,9 +468,11 @@ static int bus_reset(struct scsi_cmnd *srb) return result < 0 ? FAILED : SUCCESS; } -/* Report a driver-initiated device reset to the SCSI layer. +/* + * Report a driver-initiated device reset to the SCSI layer. * Calling this for a SCSI-initiated reset is unnecessary but harmless. - * The caller must own the SCSI host lock. */ + * The caller must own the SCSI host lock. + */ void usb_stor_report_device_reset(struct us_data *us) { int i; @@ -434,9 +485,11 @@ void usb_stor_report_device_reset(struct us_data *us) } } -/* Report a driver-initiated bus reset to the SCSI layer. +/* + * Report a driver-initiated bus reset to the SCSI layer. * Calling this for a SCSI-initiated reset is unnecessary but harmless. - * The caller must not own the SCSI host lock. */ + * The caller must not own the SCSI host lock. + */ void usb_stor_report_bus_reset(struct us_data *us) { struct Scsi_Host *host = us_to_host(us); @@ -563,12 +616,30 @@ static const struct scsi_host_template usb_stor_host_template = { .target_alloc = target_alloc, /* lots of sg segments can be handled */ - .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, + .sg_tablesize = SG_MAX_SEGMENTS, - /* limit the total size of a transfer to 120 KB */ + + /* + * Limit the total size of a transfer to 120 KB. + * + * Some devices are known to choke with anything larger. It seems like + * the problem stems from the fact that original IDE controllers had + * only an 8-bit register to hold the number of sectors in one transfer + * and even those couldn't handle a full 256 sectors. + * + * Because we want to make sure we interoperate with as many devices as + * possible, we will maintain a 240 sector transfer size limit for USB + * Mass Storage devices. + * + * Tests show that other operating have similar limits with Microsoft + * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3 + * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2 + * and 2048 for USB3 devices. + */ .max_sectors = 240, - /* merge commands... this seems to help performance, but + /* + * merge commands... this seems to help performance, but * periodically someone should test to see which setting is more * optimal. */ diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h index 5494d87607fb..d0a331dd9bc5 100644 --- a/drivers/usb/storage/scsiglue.h +++ b/drivers/usb/storage/scsiglue.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * SCSI Connecting Glue Header File * * Current development and maintenance by: diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 79224fcf9b59..c5797fa2125e 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -1,4 +1,5 @@ -/* Driver for SanDisk SDDR-09 SmartMedia reader +/* + * Driver for SanDisk SDDR-09 SmartMedia reader * * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * (c) 2002 Andries Brouwer (aeb@cwi.nl) @@ -799,10 +800,12 @@ sddr09_read_data(struct us_data *us, usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", pages, lba, page); - /* This is not really an error. It just means - that the block has never been written. - Instead of returning an error - it is better to return all zero data. */ + /* + * This is not really an error. It just means + * that the block has never been written. + * Instead of returning an error + * it is better to return all zero data. + */ memset(buffer, 0, len); @@ -890,8 +893,10 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, } if (pba == 1) { - /* Maybe it is impossible to write to PBA 1. - Fake success, but don't do anything. */ + /* + * Maybe it is impossible to write to PBA 1. + * Fake success, but don't do anything. + */ printk(KERN_WARNING "sddr09: avoid writing to pba 1\n"); return 0; } @@ -979,18 +984,22 @@ sddr09_write_data(struct us_data *us, struct scatterlist *sg; int result; - // Figure out the initial LBA and page + /* Figure out the initial LBA and page */ lba = address >> info->blockshift; page = (address & info->blockmask); maxlba = info->capacity >> (info->pageshift + info->blockshift); if (lba >= maxlba) return -EIO; - // blockbuffer is used for reading in the old data, overwriting - // with the new data, and performing ECC calculations + /* + * blockbuffer is used for reading in the old data, overwriting + * with the new data, and performing ECC calculations + */ - /* TODO: instead of doing kmalloc/kfree for each write, - add a bufferpointer to the info structure */ + /* + * TODO: instead of doing kmalloc/kfree for each write, + * add a bufferpointer to the info structure + */ pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); blocklen = (pagelen << info->blockshift); @@ -1000,9 +1009,11 @@ sddr09_write_data(struct us_data *us, return -ENOMEM; } - // Since we don't write the user data directly to the device, - // we have to create a bounce buffer and move the data a piece - // at a time between the bounce buffer and the actual transfer buffer. + /* + * Since we don't write the user data directly to the device, + * we have to create a bounce buffer and move the data a piece + * at a time between the bounce buffer and the actual transfer buffer. + */ len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); @@ -1018,7 +1029,7 @@ sddr09_write_data(struct us_data *us, while (sectors > 0) { - // Write as many sectors as possible in this block + /* Write as many sectors as possible in this block */ pages = min(sectors, info->blocksize - page); len = (pages << info->pageshift); @@ -1031,7 +1042,7 @@ sddr09_write_data(struct us_data *us, break; } - // Get the data from the transfer buffer + /* Get the data from the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, &sg, &offset, FROM_XFER_BUF); @@ -1168,9 +1179,11 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { /* Byte 1 is the device type */ cardinfo = nand_find_id(deviceID[1]); if (cardinfo) { - /* MB or MiB? It is neither. A 16 MB card has - 17301504 raw bytes, of which 16384000 are - usable for user data. */ + /* + * MB or MiB? It is neither. A 16 MB card has + * 17301504 raw bytes, of which 16384000 are + * usable for user data. + */ sprintf(blurbtxt + strlen(blurbtxt), ", %d MB", 1<<(cardinfo->chipshift - 20)); } else { @@ -1211,14 +1224,18 @@ sddr09_read_map(struct us_data *us) { if (!info->capacity) return -1; - // size of a block is 1 << (blockshift + pageshift) bytes - // divide into the total capacity to get the number of blocks + /* + * size of a block is 1 << (blockshift + pageshift) bytes + * divide into the total capacity to get the number of blocks + */ numblocks = info->capacity >> (info->blockshift + info->pageshift); - // read 64 bytes for every block (actually 1 << CONTROL_SHIFT) - // but only use a 64 KB buffer - // buffer size used must be a multiple of (1 << CONTROL_SHIFT) + /* + * read 64 bytes for every block (actually 1 << CONTROL_SHIFT) + * but only use a 64 KB buffer + * buffer size used must be a multiple of (1 << CONTROL_SHIFT) + */ #define SDDR09_READ_MAP_BUFSZ 65536 alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); @@ -1575,8 +1592,10 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) havefakesense = 1; - /* Dummy up a response for INQUIRY since SDDR09 doesn't - respond to INQUIRY commands */ + /* + * Dummy up a response for INQUIRY since SDDR09 doesn't + * respond to INQUIRY commands + */ if (srb->cmnd[0] == INQUIRY) { memcpy(ptr, inquiry_response, 8); @@ -1628,8 +1647,10 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) if (srb->cmnd[0] == MODE_SENSE_10) { int modepage = (srb->cmnd[2] & 0x3F); - /* They ask for the Read/Write error recovery page, - or for all pages. */ + /* + * They ask for the Read/Write error recovery page, + * or for all pages. + */ /* %% We should check DBD %% */ if (modepage == 0x01 || modepage == 0x3F) { usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n", @@ -1682,7 +1703,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) USB_STOR_TRANSPORT_ERROR); } - /* catch-all for all other commands, except + /* + * catch-all for all other commands, except * pass TEST_UNIT_READY and REQUEST_SENSE through */ if (srb->cmnd[0] != TEST_UNIT_READY && diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index e5e0a25ecd96..147c50b3e00f 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -1,4 +1,5 @@ -/* Driver for SanDisk SDDR-55 SmartMedia reader +/* + * Driver for SanDisk SDDR-55 SmartMedia reader * * SDDR55 driver v0.1: * @@ -130,7 +131,8 @@ sddr55_bulk_transport(struct us_data *us, int direction, return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL); } -/* check if card inserted, if there is, update read_only status +/* + * check if card inserted, if there is, update read_only status * return non zero if no card */ @@ -714,15 +716,18 @@ static int sddr55_read_map(struct us_data *us) { if (max_lba > 1000) max_lba = 1000; - // Each block is 64 bytes of control data, so block i is located in - // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) + /* + * Each block is 64 bytes of control data, so block i is located in + * scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) + */ for (i=0; i<numblocks; i++) { int zone = i / 1024; lba = short_pack(buffer[i * 2], buffer[i * 2 + 1]); - /* Every 1024 physical blocks ("zone"), the LBA numbers + /* + * Every 1024 physical blocks ("zone"), the LBA numbers * go back to zero, but are within a higher * block of LBA's. Also, there is a maximum of * 1000 LBA's per zone. In other words, in PBA @@ -733,7 +738,8 @@ static int sddr55_read_map(struct us_data *us) { * are 24 spare blocks to use when blocks do go bad. */ - /* SDDR55 returns 0xffff for a bad block, and 0x400 for the + /* + * SDDR55 returns 0xffff for a bad block, and 0x400 for the * CIS block. (Is this true for cards 8MB or less??) * Record these in the physical to logical map */ @@ -824,8 +830,10 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) memset (info->sense_data, 0, sizeof info->sense_data); - /* Dummy up a response for INQUIRY since SDDR55 doesn't - respond to INQUIRY commands */ + /* + * Dummy up a response for INQUIRY since SDDR55 doesn't + * respond to INQUIRY commands + */ if (srb->cmnd[0] == INQUIRY) { memcpy(ptr, inquiry_response, 8); @@ -833,7 +841,8 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; } - /* only check card status if the map isn't allocated, ie no card seen yet + /* + * only check card status if the map isn't allocated, ie no card seen yet * or if it's been over half a second since we last accessed it */ if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) { @@ -849,8 +858,10 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) } } - /* if we detected a problem with the map when writing, - don't allow any more access */ + /* + * if we detected a problem with the map when writing, + * don't allow any more access + */ if (info->fatal_error) { set_sense_info (3, 0x31, 0); @@ -868,12 +879,16 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) info->capacity = capacity; - /* figure out the maximum logical block number, allowing for - * the fact that only 250 out of every 256 are used */ + /* + * figure out the maximum logical block number, allowing for + * the fact that only 250 out of every 256 are used + */ info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250; - /* Last page in the card, adjust as we only use 250 out of - * every 256 pages */ + /* + * Last page in the card, adjust as we only use 250 out of + * every 256 pages + */ capacity = (capacity / 256) * 250; capacity /= PAGESIZE; diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index a3ec86b913a1..3b0294e4df93 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1,4 +1,5 @@ -/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable +/* + * Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) @@ -408,7 +409,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) int result; unsigned char *status = us->iobuf; - /* Synchronizing cache on a CDR could take a heck of a long time, + /* + * Synchronizing cache on a CDR could take a heck of a long time, * but probably not more than 10 minutes or so. On the other hand, * doing a full blank on a CDRW at speed 1 will take about 75 * minutes! @@ -1570,9 +1572,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) len = scsi_bufflen(srb); - /* Send A0 (ATA PACKET COMMAND). - Note: I guess we're never going to get any of the ATA - commands... just ATA Packet Commands. + /* + * Send A0 (ATA PACKET COMMAND). + * Note: I guess we're never going to get any of the ATA + * commands... just ATA Packet Commands. */ registers[0] = USBAT_ATA_FEATURES; @@ -1851,7 +1854,8 @@ static int usbat_probe(struct usb_interface *intf, if (result) return result; - /* The actual transport will be determined later by the + /* + * The actual transport will be determined later by the * initialization routine; this is just a placeholder. */ us->transport_name = "Shuttle USBAT"; diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 2ea657be14c8..9a51019ac7b2 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -177,7 +177,8 @@ int sierra_ms_init(struct us_data *us) debug_swoc(&us->pusb_dev->dev, swocInfo); - /* If there is not Linux software on the TRU-Install device + /* + * If there is not Linux software on the TRU-Install device * then switch to modem mode */ if (!containsFullLinuxPackage(swocInfo)) { diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 5e67f63b2e46..ffd086733421 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * * Current development and maintenance by: * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -109,7 +110,8 @@ * called more than once or from being called during usb_submit_urb(). */ -/* This is the completion handler which will wake us up when an URB +/* + * This is the completion handler which will wake us up when an URB * completes. */ static void usb_stor_blocking_completion(struct urb *urb) @@ -119,7 +121,8 @@ static void usb_stor_blocking_completion(struct urb *urb) complete(urb_done_ptr); } -/* This is the common part of the URB message submission code +/* + * This is the common part of the URB message submission code * * All URBs from the usb-storage driver involved in handling a queued scsi * command _must_ pass through this function (or something like it) for the @@ -142,10 +145,12 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) us->current_urb->context = &urb_done; us->current_urb->transfer_flags = 0; - /* we assume that if transfer_buffer isn't us->iobuf then it + /* + * we assume that if transfer_buffer isn't us->iobuf then it * hasn't been mapped for DMA. Yes, this is clunky, but it's * easier than always having the caller tell us whether the - * transfer buffer has already been mapped. */ + * transfer buffer has already been mapped. + */ if (us->current_urb->transfer_buffer == us->iobuf) us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; us->current_urb->transfer_dma = us->iobuf_dma; @@ -157,8 +162,10 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) return status; } - /* since the URB has been submitted successfully, it's now okay - * to cancel it */ + /* + * since the URB has been submitted successfully, it's now okay + * to cancel it + */ set_bit(US_FLIDX_URB_ACTIVE, &us->dflags); /* did an abort occur during the submission? */ @@ -220,7 +227,8 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, } EXPORT_SYMBOL_GPL(usb_stor_control_msg); -/* This is a version of usb_clear_halt() that allows early termination and +/* + * This is a version of usb_clear_halt() that allows early termination and * doesn't read the status from the device -- this is because some devices * crash their internal firmware when the status is requested after a halt. * @@ -280,8 +288,10 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, /* stalled */ case -EPIPE: - /* for control endpoints, (used by CB[I]) a stall indicates - * a failed command */ + /* + * for control endpoints, (used by CB[I]) a stall indicates + * a failed command + */ if (usb_pipecontrol(pipe)) { usb_stor_dbg(us, "-- stall on control pipe\n"); return USB_STOR_XFER_STALLED; @@ -433,8 +443,10 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, return USB_STOR_XFER_ERROR; } - /* since the block has been initialized successfully, it's now - * okay to cancel it */ + /* + * since the block has been initialized successfully, it's now + * okay to cancel it + */ set_bit(US_FLIDX_SG_ACTIVE, &us->dflags); /* did an abort occur during the submission? */ @@ -515,7 +527,8 @@ EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg); * Transport routines ***********************************************************************/ -/* There are so many devices that report the capacity incorrectly, +/* + * There are so many devices that report the capacity incorrectly, * this routine was written to counteract some of the resulting * problems. */ @@ -533,7 +546,8 @@ static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) [12] = 0x14 /* Record Not Found */ }; - /* If last-sector problems can't occur, whether because the + /* + * If last-sector problems can't occur, whether because the * capacity was already decremented or because the device is * known to report the correct capacity, then we don't need * to do anything. @@ -559,13 +573,15 @@ static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) { - /* The command succeeded. We know this device doesn't + /* + * The command succeeded. We know this device doesn't * have the last-sector bug, so stop checking it. */ us->use_last_sector_hacks = 0; } else { - /* The command failed. Allow up to 3 retries in case this + /* + * The command failed. Allow up to 3 retries in case this * is some normal sort of failure. After that, assume the * capacity is wrong and we're trying to access the sector * beyond the end. Replace the result code and sense data @@ -581,7 +597,8 @@ static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) } done: - /* Don't reset the retry counter for TEST UNIT READY commands, + /* + * Don't reset the retry counter for TEST UNIT READY commands, * because they get issued after device resets which might be * caused by a failed last-sector access. */ @@ -589,7 +606,8 @@ static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) us->last_sector_retries = 0; } -/* Invoke the transport and basic error-handling/recovery methods +/* + * Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and receive the response. @@ -603,7 +621,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) scsi_set_resid(srb, 0); result = us->transport(srb, us); - /* if the command gets aborted by the higher layers, we need to + /* + * if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { @@ -628,7 +647,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) srb->result = SAM_STAT_GOOD; - /* Determine if we need to auto-sense + /* + * Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. @@ -728,7 +748,8 @@ Retry_Sense: goto Handle_Errors; } - /* Some devices claim to support larger sense but fail when + /* + * Some devices claim to support larger sense but fail when * trying to request it. When a transport failure happens * using US_FS_SANE_SENSE, we always retry with a standard * (small) sense request. This fixes some USB GSM modems @@ -746,7 +767,8 @@ Retry_Sense: if (temp_result != USB_STOR_TRANSPORT_GOOD) { usb_stor_dbg(us, "-- auto-sense failure\n"); - /* we skip the reset if this happens to be a + /* + * we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ @@ -756,7 +778,8 @@ Retry_Sense: return; } - /* If the sense data returned is larger than 18-bytes then we + /* + * If the sense data returned is larger than 18-bytes then we * assume this device supports requesting more in the future. * The response code must be 70h through 73h inclusive. */ @@ -767,7 +790,8 @@ Retry_Sense: usb_stor_dbg(us, "-- SANE_SENSE support enabled\n"); us->fflags |= US_FL_SANE_SENSE; - /* Indicate to the user that we truncated their sense + /* + * Indicate to the user that we truncated their sense * because we didn't know it supported larger sense. */ usb_stor_dbg(us, "-- Sense data truncated to %i from %i\n", @@ -795,13 +819,15 @@ Retry_Sense: SCSI_SENSE_BUFFERSIZE, 4); fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; - /* We often get empty sense data. This could indicate that + /* + * We often get empty sense data. This could indicate that * everything worked or that there was an unspecified * problem. We have to decide which. */ if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && fm_ili == 0) { - /* If things are really okay, then let's show that. + /* + * If things are really okay, then let's show that. * Zero out the sense buffer so the higher layers * won't realize we did an unsolicited auto-sense. */ @@ -809,7 +835,8 @@ Retry_Sense: srb->result = SAM_STAT_GOOD; srb->sense_buffer[0] = 0x0; - /* If there was a problem, report an unspecified + /* + * If there was a problem, report an unspecified * hardware error to prevent the higher layers from * entering an infinite retry loop. */ @@ -860,20 +887,26 @@ Retry_Sense: last_sector_hacks(us, srb); return; - /* Error and abort processing: try to resynchronize with the device + /* + * Error and abort processing: try to resynchronize with the device * by issuing a port reset. If that fails, try a class-specific - * device reset. */ + * device reset. + */ Handle_Errors: - /* Set the RESETTING bit, and clear the ABORTING bit so that - * the reset may proceed. */ + /* + * Set the RESETTING bit, and clear the ABORTING bit so that + * the reset may proceed. + */ scsi_lock(us_to_host(us)); set_bit(US_FLIDX_RESETTING, &us->dflags); clear_bit(US_FLIDX_ABORTING, &us->dflags); scsi_unlock(us_to_host(us)); - /* We must release the device lock because the pre_reset routine - * will want to acquire it. */ + /* + * We must release the device lock because the pre_reset routine + * will want to acquire it. + */ mutex_unlock(&us->dev_mutex); result = usb_stor_port_reset(us); mutex_lock(&us->dev_mutex); @@ -891,10 +924,12 @@ Retry_Sense: /* Stop the current URB transfer */ void usb_stor_stop_transport(struct us_data *us) { - /* If the state machine is blocked waiting for an URB, + /* + * If the state machine is blocked waiting for an URB, * let's wake it up. The test_and_clear_bit() call * guarantees that if a URB has just been submitted, - * it won't be cancelled more than once. */ + * it won't be cancelled more than once. + */ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { usb_stor_dbg(us, "-- cancelling URB\n"); usb_unlink_urb(us->current_urb); @@ -955,7 +990,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) /* STATUS STAGE */ - /* NOTE: CB does not have a status stage. Silly, I know. So + /* + * NOTE: CB does not have a status stage. Silly, I know. So * we have to catch this at a higher level. */ if (us->protocol != USB_PR_CBI) @@ -967,7 +1003,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - /* UFI gives us ASC and ASCQ, like a request sense + /* + * UFI gives us ASC and ASCQ, like a request sense * * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI * devices, so we ignore the information for those commands. Note @@ -983,7 +1020,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; } - /* If not UFI, we interpret the data as a result code + /* + * If not UFI, we interpret the data as a result code * The first byte should always be a 0x0. * * Some bogus devices don't follow that rule. They stuff the ASC @@ -1005,7 +1043,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) } return USB_STOR_TRANSPORT_ERROR; - /* the CBI spec requires that the bulk pipe must be cleared + /* + * the CBI spec requires that the bulk pipe must be cleared * following any data-in/out command failure (section 2.4.3.1.3) */ Failed: @@ -1107,9 +1146,11 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) /* DATA STAGE */ /* send/receive data payload, if there is any */ - /* Some USB-IDE converter chips need a 100us delay between the + /* + * Some USB-IDE converter chips need a 100us delay between the * command phase and the data phase. Some devices need a little - * more than that, probably because of clock rate inaccuracies. */ + * more than that, probably because of clock rate inaccuracies. + */ if (unlikely(us->fflags & US_FL_GO_SLOW)) usleep_range(125, 150); @@ -1121,7 +1162,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; - /* If the device tried to send back more data than the + /* + * If the device tried to send back more data than the * amount requested, the spec requires us to transfer * the CSW anyway. Since there's no point retrying the * the command, we'll return fake sense data indicating @@ -1156,7 +1198,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) } } - /* See flow chart on pg 15 of the Bulk Only Transport spec for + /* + * See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ @@ -1165,7 +1208,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); - /* Some broken devices add unnecessary zero-length packets to the + /* + * Some broken devices add unnecessary zero-length packets to the * end of their data transfers. Such packets show up as 0-length * CSWs. If we encounter such a thing, try to read the CSW again. */ @@ -1201,7 +1245,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } - /* Some broken devices report odd signatures, so we do not check them + /* + * Some broken devices report odd signatures, so we do not check them * for validity against the spec. We store the first one we see, * and check subsequent transfers for validity against this signature. */ @@ -1217,11 +1262,14 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ + /* + * try to compute the actual residue, based on how much data + * was really transferred and what the device tells us + */ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { - /* Heuristically detect devices that generate bogus residues + /* + * Heuristically detect devices that generate bogus residues * by seeing what happens with INQUIRY and READ CAPACITY * commands. */ @@ -1259,7 +1307,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: - /* phase error -- note that a transport reset will be + /* + * phase error -- note that a transport reset will be * invoked by the invoke_transport() function */ return USB_STOR_TRANSPORT_ERROR; @@ -1274,7 +1323,8 @@ EXPORT_SYMBOL_GPL(usb_stor_Bulk_transport); * Reset routines ***********************************************************************/ -/* This is the common part of the device reset code. +/* + * This is the common part of the device reset code. * * It's handy that every transport mechanism uses the control endpoint for * resets. @@ -1302,8 +1352,10 @@ static int usb_stor_reset_common(struct us_data *us, return result; } - /* Give the device some time to recover from the reset, - * but don't delay disconnect processing. */ + /* + * Give the device some time to recover from the reset, + * but don't delay disconnect processing. + */ wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6); @@ -1328,8 +1380,7 @@ static int usb_stor_reset_common(struct us_data *us, return result; } -/* This issues a CB[I] Reset to the device in question - */ +/* This issues a CB[I] Reset to the device in question */ #define CB_RESET_CMD_SIZE 12 int usb_stor_CB_reset(struct us_data *us) @@ -1343,7 +1394,8 @@ int usb_stor_CB_reset(struct us_data *us) } EXPORT_SYMBOL_GPL(usb_stor_CB_reset); -/* This issues a Bulk-only Reset to the device in question, including +/* + * This issues a Bulk-only Reset to the device in question, including * clearing the subsequent endpoint halts that may occur. */ int usb_stor_Bulk_reset(struct us_data *us) @@ -1354,7 +1406,8 @@ int usb_stor_Bulk_reset(struct us_data *us) } EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset); -/* Issue a USB port reset to the device. The caller must not hold +/* + * Issue a USB port reset to the device. The caller must not hold * us->dev_mutex. */ int usb_stor_port_reset(struct us_data *us) diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 9369d752d419..dae3ecd2e6cf 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Transport Functions Header File * * Current development and maintenance by: diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 16bc679dc2fc..5ef014ba6ae8 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -799,7 +799,8 @@ static int uas_slave_alloc(struct scsi_device *sdev) sdev->hostdata = devinfo; - /* USB has unusual DMA-alignment requirements: Although the + /* + * USB has unusual DMA-alignment requirements: Although the * starting address of each scatter-gather element doesn't matter, * the length of each element except the last must be divisible * by the Bulk maxpacket value. There's currently no way to @@ -835,6 +836,7 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_BROKEN_FUA) sdev->broken_fua = 1; + scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } @@ -847,7 +849,6 @@ static struct scsi_host_template uas_host_template = { .slave_configure = uas_slave_configure, .eh_abort_handler = uas_eh_abort_handler, .eh_bus_reset_handler = uas_eh_bus_reset_handler, - .can_queue = MAX_CMNDS, .this_id = -1, .sg_tablesize = SG_NONE, .skip_settle_delay = 1, diff --git a/drivers/usb/storage/unusual_alauda.h b/drivers/usb/storage/unusual_alauda.h index fa3e9edaa2cf..763bc03032a1 100644 --- a/drivers/usb/storage/unusual_alauda.h +++ b/drivers/usb/storage/unusual_alauda.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Alauda-based card readers +/* + * Unusual Devices File for the Alauda-based card readers * * 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 diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index 82e8ed0324e3..e9a2eb88869a 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for devices based on the Cypress USB/ATA bridge +/* + * Unusual Devices File for devices based on the Cypress USB/ATA bridge * with support for ATACB * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/usb/storage/unusual_datafab.h b/drivers/usb/storage/unusual_datafab.h index 582a603c78be..5049b6bbe5d5 100644 --- a/drivers/usb/storage/unusual_datafab.h +++ b/drivers/usb/storage/unusual_datafab.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Datafab USB Compact Flash reader +/* + * Unusual Devices File for the Datafab USB Compact Flash reader * * 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 @@ -79,7 +80,8 @@ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, USB_SC_SCSI, USB_PR_DATAFAB, NULL, 0), -/* Reported by Felix Moeller <felix@derklecks.de> +/* + * Reported by Felix Moeller <felix@derklecks.de> * in Germany this is sold by Hama with the productnumber 46952 * as "DualSlot CompactFlash(TM) & MStick Drive USB" */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 7ffe4209067b..aa3539238848 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Unusual Devices File * * Current development and maintenance by: @@ -25,13 +26,15 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* IMPORTANT NOTE: This file must be included in another file which does +/* + * IMPORTANT NOTE: This file must be included in another file which does * the following thing for it to work: * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined * before this file is included. */ -/* If you edit this file, please try to keep it sorted first by VendorID, +/* + * If you edit this file, please try to keep it sorted first by VendorID, * then by ProductID. * * If you want to add an entry for this file, be sure to include the @@ -47,13 +50,15 @@ * <usb-storage@lists.one-eyed-alien.net> */ -/* Note: If you add an entry only in order to set the CAPACITY_OK flag, +/* + * Note: If you add an entry only in order to set the CAPACITY_OK flag, * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is * because such entries mark devices which actually work correctly, * as opposed to devices that do something strangely or wrongly. */ -/* In-kernel mode switching is deprecated. Do not add new devices to +/* + * In-kernel mode switching is deprecated. Do not add new devices to * this list for the sole purpose of switching them to a different * mode. Existing userspace solutions are superior. * @@ -66,8 +71,7 @@ #define NO_SDDR09 #endif -/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr> - */ +/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr> */ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, "ATMEL", "SND1 Storage", @@ -93,7 +97,8 @@ UNUSUAL_DEV( 0x03f0, 0x070c, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE ), -/* Reported by Grant Grundler <grundler@parisc-linux.org> +/* + * Reported by Grant Grundler <grundler@parisc-linux.org> * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware. */ UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001, @@ -107,7 +112,8 @@ UNUSUAL_DEV( 0x03f3, 0x0001, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), -/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> +/* + * Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product) * for USB floppies that need the SINGLE_LUN enforcement. */ @@ -124,7 +130,8 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Deduced by Jonathan Woithe <jwoithe@just42.net> +/* + * Deduced by Jonathan Woithe <jwoithe@just42.net> * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message * always fails and confuses drive. */ @@ -167,8 +174,10 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Reported by Andrew Nayenko <relan@bk.ru> - * Updated for new firmware by Phillip Potter <phillipinda@hotmail.com> */ +/* + * Reported by Andrew Nayenko <relan@bk.ru> + * Updated for new firmware by Phillip Potter <phillipinda@hotmail.com> + */ UNUSUAL_DEV( 0x0421, 0x0019, 0x0592, 0x0610, "Nokia", "Nokia 6288", @@ -196,16 +205,20 @@ UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), -/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and - * Einar Th. Einarsson <einarthered@gmail.com> */ +/* + * Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and + * Einar Th. Einarsson <einarthered@gmail.com> + */ UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100, "Nokia", "N91", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), -/* Reported by Jiri Slaby <jirislaby@gmail.com> and - * Rene C. Castberg <Rene@Castberg.org> */ +/* + * Reported by Jiri Slaby <jirislaby@gmail.com> and + * Rene C. Castberg <Rene@Castberg.org> + */ UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, "Nokia", "N80", @@ -269,8 +282,10 @@ UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, US_FL_SINGLE_LUN ), #endif -/* Patch submitted by Daniel Drake <dsd@gentoo.org> - * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */ +/* + * Patch submitted by Daniel Drake <dsd@gentoo.org> + * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 + */ UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100, "Neuros Audio", "USB 2.0 HD 2.5", @@ -288,17 +303,18 @@ UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), /* -* Bohdan Linda <bohdan.linda@gmail.com> -* 1GB USB sticks MyFlash High Speed. I have restricted -* the revision to my model only -*/ + * Bohdan Linda <bohdan.linda@gmail.com> + * 1GB USB sticks MyFlash High Speed. I have restricted + * the revision to my model only + */ UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100, "USB 2.0", "Flash Disk", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), -/* Reported by Tamas Kerecsen <kerecsen@bigfoot.com> +/* + * Reported by Tamas Kerecsen <kerecsen@bigfoot.com> * Obviously the PROM has not been customized by the VAR; * the Vendor and Product string descriptors are: * Generic Mass Storage (PROTOTYPE--Remember to change idVendor) @@ -347,24 +363,30 @@ UNUSUAL_DEV( 0x0482, 0x0107, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE), -/* Reported by Paul Stewart <stewart@wetlogic.net> - * This entry is needed because the device reports Sub=ff */ +/* + * Reported by Paul Stewart <stewart@wetlogic.net> + * This entry is needed because the device reports Sub=ff + */ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, "Hitachi", "DVD-CAM DZ-MV100A Camcorder", USB_SC_SCSI, USB_PR_CB, NULL, US_FL_SINGLE_LUN), -/* BENQ DC5330 +/* + * BENQ DC5330 * Reported by Manuel Fombuena <mfombuena@ya.com> and - * Frank Copeland <fjc@thingy.apana.org.au> */ + * Frank Copeland <fjc@thingy.apana.org.au> + */ UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100, "Tekom Technologies, Inc", "300_CAMERA", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Patch for Nikon coolpix 2000 - * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/ +/* + * Patch for Nikon coolpix 2000 + * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr> + */ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010, "NIKON", "NIKON DSC E2000", @@ -378,21 +400,26 @@ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_CB, NULL, US_FL_MAX_SECTORS_MIN), -/* Reported by Simon Levitt <simon@whattf.com> - * This entry needs Sub and Proto fields */ +/* + * Reported by Simon Levitt <simon@whattf.com> + * This entry needs Sub and Proto fields + */ UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100, "Epson", "875DC Storage", USB_SC_SCSI, USB_PR_CB, NULL, US_FL_FIX_INQUIRY), -/* Reported by Khalid Aziz <khalid@gonehiking.org> - * This entry is needed because the device reports Sub=ff */ +/* + * Reported by Khalid Aziz <khalid@gonehiking.org> + * This entry is needed because the device reports Sub=ff + */ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, "Epson", "785EPX Storage", USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_SINGLE_LUN), -/* Not sure who reported this originally but +/* + * Not sure who reported this originally but * Pavel Machek <pavel@ucw.cz> reported that the extra US_FL_SINGLE_LUN * flag be added */ UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, @@ -400,7 +427,8 @@ UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, "FinePix 1400Zoom", USB_SC_UFI, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN), -/* Reported by Ondrej Zary <linux@rainbow-software.org> +/* + * Reported by Ondrej Zary <linux@rainbow-software.org> * The device reports one sector more and breaks when that sector is accessed */ UNUSUAL_DEV( 0x04ce, 0x0002, 0x026c, 0x026c, @@ -409,7 +437,8 @@ UNUSUAL_DEV( 0x04ce, 0x0002, 0x026c, 0x026c, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), -/* Reported by Kriston Fincher <kriston@airmail.net> +/* + * Reported by Kriston Fincher <kriston@airmail.net> * Patch submitted by Sean Millichamp <sean@bruenor.org> * This is to support the Panasonic PalmCam PV-SD4090 * This entry is needed because the device reports Sub=ff @@ -419,8 +448,10 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, "LS-120 Camera", USB_SC_UFI, USB_PR_DEVICE, NULL, 0), -/* From Yukihiro Nakai, via zaitcev@yahoo.com. - * This is needed for CB instead of CBI */ +/* + * From Yukihiro Nakai, via zaitcev@yahoo.com. + * This is needed for CB instead of CBI + */ UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000, "Sharp CE-CW05", "CD-R/RW Drive", @@ -440,7 +471,8 @@ UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), -/* Most of the following entries were developed with the help of +/* + * Most of the following entries were developed with the help of * Shuttle/SCM directly. */ UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, @@ -536,7 +568,8 @@ UNUSUAL_DEV( 0x04e8, 0x5136, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64), -/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. +/* + * Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. * Device uses standards-violating 32-byte Bulk Command Block Wrappers and * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011. */ @@ -553,7 +586,8 @@ UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), -/* Iomega Clik! Drive +/* + * Iomega Clik! Drive * Reported by David Chatenay <dchatenay@hotmail.com> * The reason this is needed is not fully known. */ @@ -570,7 +604,8 @@ COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_CAPACITY_OK ), -/* Yakumo Mega Image 37 +/* + * Yakumo Mega Image 37 * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, "Tekom Technologies, Inc", @@ -578,8 +613,10 @@ UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Another Yakumo camera. - * Reported by Michele Alzetta <michele.alzetta@aliceposta.it> */ +/* + * Another Yakumo camera. + * Reported by Michele Alzetta <michele.alzetta@aliceposta.it> + */ UNUSUAL_DEV( 0x052b, 0x1804, 0x0100, 0x0100, "Tekom Technologies, Inc", "300_CAMERA", @@ -593,16 +630,20 @@ UNUSUAL_DEV( 0x052b, 0x1807, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Yakumo Mega Image 47 - * Reported by Bjoern Paetzel <kolrabi@kolrabi.de> */ +/* + * Yakumo Mega Image 47 + * Reported by Bjoern Paetzel <kolrabi@kolrabi.de> + */ UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100, "Tekom Technologies, Inc", "400_CAMERA", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Reported by Paul Ortyl <ortylp@3miasto.net> - * Note that it's similar to the device above, only different prodID */ +/* + * Reported by Paul Ortyl <ortylp@3miasto.net> + * Note that it's similar to the device above, only different prodID + */ UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100, "Tekom Technologies, Inc", "400_CAMERA", @@ -615,8 +656,10 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, USB_SC_SCSI, USB_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ), -/* Submitted by Lars Jacob <jacob.lars@googlemail.com> - * This entry is needed because the device reports Sub=ff */ +/* + * Submitted by Lars Jacob <jacob.lars@googlemail.com> + * This entry is needed because the device reports Sub=ff + */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610, "Sony", "DSC-T1/T5/H5", @@ -719,7 +762,8 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, USB_SC_DEVICE, USB_PR_CB, NULL, US_FL_SINGLE_LUN), -/* Reported by Johann Cardon <johann.cardon@free.fr> +/* + * Reported by Johann Cardon <johann.cardon@free.fr> * This entry is needed only because the device reports * bInterfaceClass = 0xff (vendor-specific) */ @@ -741,7 +785,8 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Digital Camera EX-20 DSC", USB_SC_8070, USB_PR_DEVICE, NULL, 0 ), -/* Reported by Andre Welter <a.r.welter@gmx.de> +/* + * Reported by Andre Welter <a.r.welter@gmx.de> * This antique device predates the release of the Bulk-only Transport * spec, and if it gets a Get-Max-LUN then it requires the host to do a * Clear-Halt on the bulk endpoints. The SINGLE_LUN flag will prevent @@ -773,7 +818,8 @@ UNUSUAL_DEV( 0x059f, 0x0651, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), -/* Submitted by Joel Bourquard <numlock@freesurf.ch> +/* + * Submitted by Joel Bourquard <numlock@freesurf.ch> * Some versions of this device need the SubClass and Protocol overrides * while others don't. */ @@ -783,7 +829,8 @@ UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_NEED_OVERRIDE ), -/* Submitted by Sven Anderson <sven-linux@anderson.de> +/* + * Submitted by Sven Anderson <sven-linux@anderson.de> * There are at least four ProductIDs used for iPods, so I added 0x1202 and * 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears * to change with firmware updates, I changed the range to maximum for all @@ -824,7 +871,8 @@ UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Dan Williams <dcbw@redhat.com> +/* + * Reported by Dan Williams <dcbw@redhat.com> * Option N.V. mobile broadband modems * Ignore driver CD mode and force into modem mode by default. */ @@ -843,7 +891,8 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* The following two entries are for a Genesys USB to IDE +/* + * The following two entries are for a Genesys USB to IDE * converter chip, but it changes its ProductId depending * on whether or not a disk or an optical device is enclosed * They were originally reported by Alexander Oltu @@ -873,8 +922,10 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE ), -/* Reported by Hanno Boeck <hanno@gmx.de> - * Taken from the Lycoris Kernel */ +/* + * Reported by Hanno Boeck <hanno@gmx.de> + * Taken from the Lycoris Kernel + */ UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, "Vivitar", "Vivicam 35Xx", @@ -908,8 +959,10 @@ UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, US_FL_NOT_LOCKABLE ), /* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */ -/* Change to bcdDeviceMin (0x0100 to 0x0001) reported by - * Thomas Bartosik <tbartdev@gmx-topmail.de> */ +/* + * Change to bcdDeviceMin (0x0100 to 0x0001) reported by + * Thomas Bartosik <tbartdev@gmx-topmail.de> + */ UNUSUAL_DEV( 0x067b, 0x2507, 0x0001, 0x0100, "Prolific Technology Inc.", "Mass Storage Device", @@ -961,7 +1014,8 @@ UNUSUAL_DEV( 0x071b, 0x3203, 0x0000, 0x0000, US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64 | US_FL_NO_READ_CAPACITY_16), -/* Reported by Jean-Baptiste Onofre <jb@nanthrax.net> +/* + * Reported by Jean-Baptiste Onofre <jb@nanthrax.net> * Support the following product : * "Dane-Elec MediaTouch" */ @@ -971,7 +1025,8 @@ UNUSUAL_DEV( 0x071b, 0x32bb, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64), -/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com> +/* + * Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com> * This USB MP3/AVI player device fails and disconnects if more than 128 * sectors (64kB) are read/written in a single command, and may be present * at least in the following products: @@ -1040,7 +1095,8 @@ UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, US_FL_SINGLE_LUN ), #endif -/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100 +/* + * Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100 * Only revision 1.13 tested (same for all of the above devices, * based on the Datafab DF-UG-07 chip). Needed for US_FL_FIX_INQUIRY. * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>. @@ -1052,7 +1108,8 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ), -/* Reported by Rauch Wolke <rauchwolke@gmx.net> +/* + * Reported by Rauch Wolke <rauchwolke@gmx.net> * and augmented by binbin <binbinsh@gmail.com> (Bugzilla #12882) */ UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff, @@ -1061,7 +1118,8 @@ UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ), -/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant +/* + * Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant * to the USB storage specification in two ways: * - They tell us they are using transport protocol CBI. In reality they * are using transport protocol CB. @@ -1119,7 +1177,8 @@ UNUSUAL_DEV( 0x084b, 0xa001, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), -/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. +/* + * Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. * Flag will support Bulk devices which use a standards-violating 32-byte * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with * Grandtech GT892x chip, which request "Proprietary SCSI Bulk" support. @@ -1131,7 +1190,8 @@ UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BULK32), -/* Reported by <ttkspam@free.fr> +/* + * Reported by <ttkspam@free.fr> * The device reports a vendor-specific device class, requiring an * explicit vendor/product match. */ @@ -1140,11 +1200,12 @@ UNUSUAL_DEV( 0x0851, 0x1542, 0x0002, 0x0002, "FW_Omega2", USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), -/* Andrew Lunn <andrew@lunn.ch> +/* + * Andrew Lunn <andrew@lunn.ch> * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL * on LUN 4. * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera" -*/ + */ UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200, "PanDigital", "Photo Frame", @@ -1170,7 +1231,8 @@ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SINGLE_LUN), -/* Submitted by Dylan Taft <d13f00l@gmail.com> +/* + * Submitted by Dylan Taft <d13f00l@gmail.com> * US_FL_IGNORE_RESIDUE Needed */ UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100, @@ -1179,7 +1241,8 @@ UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE), -/* Entry needed for flags. Moreover, all devices with this ID use +/* + * Entry needed for flags. Moreover, all devices with this ID use * bulk-only transport, but _some_ falsely report Control/Bulk instead. * One example is "Trumpion Digital Research MYMP3". * Submitted by Bjoern Brill <brill(at)fs.math.uni-frankfurt.de> @@ -1190,7 +1253,8 @@ UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_BULK, NULL, US_FL_NEED_OVERRIDE ), -/* Reported by Filippo Bardelli <filibard@libero.it> +/* + * Reported by Filippo Bardelli <filibard@libero.it> * The device reports a subclass of RBC, which is wrong. */ UNUSUAL_DEV( 0x090a, 0x1050, 0x0100, 0x0100, @@ -1213,7 +1277,8 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Paul Hartman <paul.hartman+linux@gmail.com> +/* + * Reported by Paul Hartman <paul.hartman+linux@gmail.com> * This card reader returns "Illegal Request, Logical Block Address * Out of Range" for the first READ(10) after a new card is inserted. */ @@ -1223,7 +1288,8 @@ UNUSUAL_DEV( 0x090c, 0x6000, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_INITIAL_READ10 ), -/* This Pentax still camera is not conformant +/* + * This Pentax still camera is not conformant * to the USB storage specification: - * - It does not like the INQUIRY command. So we must handle this command * of the SCSI layer ourselves. @@ -1236,8 +1302,10 @@ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* These are virtual windows driver CDs, which the zd1211rw driver - * automatically converts into WLAN devices. */ +/* + * These are virtual windows driver CDs, which the zd1211rw driver + * automatically converts into WLAN devices. + */ UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101, "ZyXEL", "G-220F USB-WLAN Install", @@ -1250,7 +1318,8 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_DEVICE ), -/* Reported by Dan Williams <dcbw@redhat.com> +/* + * Reported by Dan Williams <dcbw@redhat.com> * Option N.V. mobile broadband modems * Ignore driver CD mode and force into modem mode by default. */ @@ -1262,20 +1331,24 @@ UNUSUAL_DEV( 0x0af0, 0x6971, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, 0), -/* Reported by F. Aben <f.aben@option.com> +/* + * Reported by F. Aben <f.aben@option.com> * This device (wrongly) has a vendor-specific device descriptor. * The entry is needed so usb-storage can bind to it's mass-storage - * interface as an interface driver */ + * interface as an interface driver + */ UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000, "Option", "GI 0401 SD-Card", USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0 ), -/* Reported by Jan Dumon <j.dumon@option.com> +/* + * Reported by Jan Dumon <j.dumon@option.com> * These devices (wrongly) have a vendor-specific device descriptor. * These entries are needed so usb-storage can bind to their mass-storage - * interface as an interface driver */ + * interface as an interface driver + */ UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000, "Option", "GI 0431 SD-Card", @@ -1419,7 +1492,8 @@ UNUSUAL_DEV( 0x0dc4, 0x0073, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), -/* Reported by Lubomir Blaha <tritol@trilogic.cz> +/* + * Reported by Lubomir Blaha <tritol@trilogic.cz> * I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this * works for me. Can anybody correct these values? (I able to test corrected * version.) @@ -1430,8 +1504,10 @@ UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* Reported by Edward Chapman (taken from linux-usb mailing list) - Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive */ +/* + * Reported by Edward Chapman (taken from linux-usb mailing list) + * Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive + */ UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999, "Netac", "USB Flash Disk", @@ -1439,8 +1515,10 @@ UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999, US_FL_IGNORE_RESIDUE ), -/* Patch by Stephan Walter <stephan.walter@epfl.ch> - * I don't know why, but it works... */ +/* + * Patch by Stephan Walter <stephan.walter@epfl.ch> + * I don't know why, but it works... + */ UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012, "WINWARD", "Music Disk", @@ -1468,8 +1546,10 @@ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* Submitted by Daniel Drake <dsd@gentoo.org> - * Reported by dayul on the Gentoo Forums */ +/* + * Submitted by Daniel Drake <dsd@gentoo.org> + * Reported by dayul on the Gentoo Forums + */ UNUSUAL_DEV( 0x0ea0, 0x2168, 0x0110, 0x0110, "Ours Technology", "Flash Disk", @@ -1483,15 +1563,18 @@ UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Reported by Benjamin Schiller <sbenni@gmx.de> - * It is also sold by Easylite as DJ 20 */ +/* + * Reported by Benjamin Schiller <sbenni@gmx.de> + * It is also sold by Easylite as DJ 20 + */ UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103, "Typhoon", "My DJ 1820", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64), -/* Patch by Leonid Petrov mail at lpetrov.net +/* + * Patch by Leonid Petrov mail at lpetrov.net * Reported by Robert Spitzenpfeil <robert@spitzenpfeil.org> * http://www.qbik.ch/usb/devices/showdev.php?id=1705 * Updated to 103 device by MJ Ray mjr at phonecoop.coop @@ -1502,7 +1585,8 @@ UNUSUAL_DEV( 0x0f19, 0x0103, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* David Kuehling <dvdkhlng@gmx.de>: +/* + * David Kuehling <dvdkhlng@gmx.de>: * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI * errors when trying to write. */ @@ -1540,8 +1624,10 @@ UNUSUAL_DEV( 0x0fce, 0xd0e1, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_DEVICE), -/* Reported by Jan Mate <mate@fiit.stuba.sk> - * and by Soeren Sonnenburg <kernel@nn7.de> */ +/* + * Reported by Jan Mate <mate@fiit.stuba.sk> + * and by Soeren Sonnenburg <kernel@nn7.de> + */ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, "Sony Ericsson", "P990i", @@ -1562,7 +1648,8 @@ UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> +/* + * Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. * Devices with bcd > 110 seem to not need it while those @@ -1586,7 +1673,8 @@ UNUSUAL_DEV(0x1058, 0x070a, 0x0000, 0x9999, "My Passport HDD", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE), -/* Reported by Fabio Venturi <f.venturi@tdnet.it> +/* + * Reported by Fabio Venturi <f.venturi@tdnet.it> * The device reports a vendor-specific bDeviceClass. */ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, @@ -1595,7 +1683,8 @@ UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), -/* Reported by Pascal Terjan <pterjan@mandriva.com> +/* + * Reported by Pascal Terjan <pterjan@mandriva.com> * Ignore driver CD mode and force into modem mode by default. */ UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, @@ -1603,7 +1692,8 @@ UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, "USB Mass Storage", USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE), -/* Reported by Kevin Lloyd <linux@sierrawireless.com> +/* + * Reported by Kevin Lloyd <linux@sierrawireless.com> * Entry is needed for the initializer function override, * which instructs the device to load as a modem * device. @@ -1614,7 +1704,8 @@ UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, sierra_ms_init, 0), -/* Reported by Jaco Kroon <jaco@kroon.co.za> +/* + * Reported by Jaco Kroon <jaco@kroon.co.za> * The usb-storage module found on the Digitech GNX4 (and supposedly other * devices) misbehaves and causes a bunch of invalid I/O errors. */ @@ -1624,7 +1715,8 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), -/* Reported by fangxiaozhi <huananhu@huawei.com> +/* + * Reported by fangxiaozhi <huananhu@huawei.com> * This brings the HUAWEI data card devices into multi-port mode */ UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000, @@ -1993,7 +2085,8 @@ UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0116, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA ), -/* Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br> +/* + * Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br> * JMicron responds to USN and several other SCSI ioctls with a * residue that causes subsequent I/O requests to fail. */ UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100, @@ -2009,7 +2102,8 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA ), -/* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI) +/* + * Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI) * and Mac USB Dock USB-SCSI */ UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133, "Entrega Technologies", @@ -2017,8 +2111,10 @@ UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133, USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), -/* Reported by Robert Schedel <r.schedel@yahoo.de> - * Note: this is a 'super top' device like the above 14cd/6600 device */ +/* + * Reported by Robert Schedel <r.schedel@yahoo.de> + * Note: this is a 'super top' device like the above 14cd/6600 device + */ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, "Teac", "HD-35PUK-B", @@ -2045,10 +2141,12 @@ UNUSUAL_DEV( 0x1822, 0x0001, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), -/* Reported by Hans de Goede <hdegoede@redhat.com> +/* + * Reported by Hans de Goede <hdegoede@redhat.com> * These Appotech controllers are found in Picture Frames, they provide a * (buggy) emulation of a cdrom drive which contains the windows software - * Uploading of pictures happens over the corresponding /dev/sg device. */ + * Uploading of pictures happens over the corresponding /dev/sg device. + */ UNUSUAL_DEV( 0x1908, 0x1315, 0x0000, 0x0000, "BUILDWIN", "Photo Frame", @@ -2065,19 +2163,22 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_READ_DISC_INFO ), -/* Reported by Oliver Neukum <oneukum@suse.com> +/* + * Reported by Oliver Neukum <oneukum@suse.com> * This device morphes spontaneously into another device if the access * pattern of Windows isn't followed. Thus writable media would be dirty * if the initial instance is used. So the device is limited to its * virtual CD. - * And yes, the concept that BCD goes up to 9 is not heeded */ + * And yes, the concept that BCD goes up to 9 is not heeded + */ UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff, "ZTE,Incorporated", "ZTE WCDMA Technologies MSM", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), -/* Reported by Sven Geggus <sven-usbst@geggus.net> +/* + * Reported by Sven Geggus <sven-usbst@geggus.net> * This encrypted pen drive returns bogus data for the initial READ(10). */ UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200, @@ -2086,7 +2187,8 @@ UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_INITIAL_READ10 ), -/* Reported by Hans de Goede <hdegoede@redhat.com> +/* + * Reported by Hans de Goede <hdegoede@redhat.com> * These are mini projectors using USB for both power and video data transport * The usb-storage interface is a virtual windows driver CD, which the gm12u320 * driver automatically converts into framebuffer & kms dri device nodes. @@ -2097,9 +2199,11 @@ UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_DEVICE ), -/* Patch by Richard Schütz <r.schtz@t-online.de> +/* + * Patch by Richard Schütz <r.schtz@t-online.de> * This external hard drive enclosure uses a JMicron chip which - * needs the US_FL_IGNORE_RESIDUE flag to work properly. */ + * needs the US_FL_IGNORE_RESIDUE flag to work properly. + */ UNUSUAL_DEV( 0x1e68, 0x001b, 0x0000, 0x0000, "TrekStor GmbH & Co. KG", "DataStation maxi g.u", @@ -2126,7 +2230,8 @@ UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), -/* patch submitted by Davide Perini <perini.davide@dpsoftware.org> +/* + * patch submitted by Davide Perini <perini.davide@dpsoftware.org> * and Renato Perini <rperini@email.it> */ UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001, @@ -2153,7 +2258,8 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_GO_SLOW ), -/* Reported by Frederic Marchal <frederic.marchal@wowcompany.com> +/* + * Reported by Frederic Marchal <frederic.marchal@wowcompany.com> * Mio Moov 330 */ UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000, diff --git a/drivers/usb/storage/unusual_freecom.h b/drivers/usb/storage/unusual_freecom.h index 59a261155b98..1f5aab42ece2 100644 --- a/drivers/usb/storage/unusual_freecom.h +++ b/drivers/usb/storage/unusual_freecom.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Freecom USB/IDE adaptor +/* + * Unusual Devices File for the Freecom USB/IDE adaptor * * 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 diff --git a/drivers/usb/storage/unusual_isd200.h b/drivers/usb/storage/unusual_isd200.h index 14cca0c48302..9b6862ec3d4f 100644 --- a/drivers/usb/storage/unusual_isd200.h +++ b/drivers/usb/storage/unusual_isd200.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for In-System Design, Inc. ISD200 ASIC +/* + * Unusual Devices File for In-System Design, Inc. ISD200 ASIC * * 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 diff --git a/drivers/usb/storage/unusual_jumpshot.h b/drivers/usb/storage/unusual_jumpshot.h index 54be78b5d643..413e64fa6b95 100644 --- a/drivers/usb/storage/unusual_jumpshot.h +++ b/drivers/usb/storage/unusual_jumpshot.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader +/* + * Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader * * 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 diff --git a/drivers/usb/storage/unusual_karma.h b/drivers/usb/storage/unusual_karma.h index 6df03972a22c..e6fad3aeae20 100644 --- a/drivers/usb/storage/unusual_karma.h +++ b/drivers/usb/storage/unusual_karma.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Rio Karma +/* + * Unusual Devices File for the Rio Karma * * 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 diff --git a/drivers/usb/storage/unusual_onetouch.h b/drivers/usb/storage/unusual_onetouch.h index 0abb819c7405..425dc22f345a 100644 --- a/drivers/usb/storage/unusual_onetouch.h +++ b/drivers/usb/storage/unusual_onetouch.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for the Maxtor OneTouch USB hard drive's button +/* + * Unusual Devices File for the Maxtor OneTouch USB hard drive's button * * 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 @@ -18,7 +19,8 @@ #if defined(CONFIG_USB_STORAGE_ONETOUCH) || \ defined(CONFIG_USB_STORAGE_ONETOUCH_MODULE) -/* Submitted by: Nick Sillik <n.sillik@temple.edu> +/* + * Submitted by: Nick Sillik <n.sillik@temple.edu> * Needed for OneTouch extension to usb-storage */ UNUSUAL_DEV( 0x0d49, 0x7000, 0x0000, 0x9999, diff --git a/drivers/usb/storage/unusual_realtek.h b/drivers/usb/storage/unusual_realtek.h index e41f50c95ed4..8fe624ad302a 100644 --- a/drivers/usb/storage/unusual_realtek.h +++ b/drivers/usb/storage/unusual_realtek.h @@ -1,4 +1,5 @@ -/* Driver for Realtek RTS51xx USB card reader +/* + * Driver for Realtek RTS51xx USB card reader * * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. * diff --git a/drivers/usb/storage/unusual_sddr09.h b/drivers/usb/storage/unusual_sddr09.h index 59a7e37b6c11..d9d38ac4abf9 100644 --- a/drivers/usb/storage/unusual_sddr09.h +++ b/drivers/usb/storage/unusual_sddr09.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for SanDisk SDDR-09 SmartMedia reader +/* + * Unusual Devices File for SanDisk SDDR-09 SmartMedia reader * * 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 diff --git a/drivers/usb/storage/unusual_sddr55.h b/drivers/usb/storage/unusual_sddr55.h index fcb7e12c598f..ebb1d1c6c467 100644 --- a/drivers/usb/storage/unusual_sddr55.h +++ b/drivers/usb/storage/unusual_sddr55.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for SanDisk SDDR-55 SmartMedia reader +/* + * Unusual Devices File for SanDisk SDDR-55 SmartMedia reader * * 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 diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 53341a77d89f..cbea9f329e71 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -1,4 +1,5 @@ -/* Driver for USB Attached SCSI devices - Unusual Devices File +/* + * Driver for USB Attached SCSI devices - Unusual Devices File * * (c) 2013 Hans de Goede <hdegoede@redhat.com> * diff --git a/drivers/usb/storage/unusual_usbat.h b/drivers/usb/storage/unusual_usbat.h index 38e79c4e6d6a..2044ad5ef5e4 100644 --- a/drivers/usb/storage/unusual_usbat.h +++ b/drivers/usb/storage/unusual_usbat.h @@ -1,4 +1,5 @@ -/* Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable +/* + * Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable * * 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 diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 9de988a0f856..ef2d8cde6ef7 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * * Current development and maintenance by: * (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -97,7 +98,8 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); * with the entries in usb_storage_usb_ids[], defined in usual-tables.c. */ -/* The vendor name should be kept at eight characters or less, and +/* + *The vendor name should be kept at eight characters or less, and * the product name should be kept at 16 characters or less. If a device * has the US_FL_FIX_INQUIRY flag, then the vendor and product names * normally generated by a device through the INQUIRY response will be @@ -191,8 +193,10 @@ int usb_stor_suspend(struct usb_interface *iface, pm_message_t message) if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_SUSPEND); - /* When runtime PM is working, we'll set a flag to indicate - * whether we should autoresume when a SCSI request arrives. */ + /* + * When runtime PM is working, we'll set a flag to indicate + * whether we should autoresume when a SCSI request arrives. + */ mutex_unlock(&us->dev_mutex); return 0; @@ -220,8 +224,10 @@ int usb_stor_reset_resume(struct usb_interface *iface) /* Report the reset to the SCSI core */ usb_stor_report_bus_reset(us); - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ + /* + * FIXME: Notify the subdrivers that they need to reinitialize + * the device + */ return 0; } EXPORT_SYMBOL_GPL(usb_stor_reset_resume); @@ -250,8 +256,10 @@ int usb_stor_post_reset(struct usb_interface *iface) /* Report the reset to the SCSI core */ usb_stor_report_bus_reset(us); - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ + /* + * FIXME: Notify the subdrivers that they need to reinitialize + * the device + */ mutex_unlock(&us->dev_mutex); return 0; @@ -274,15 +282,17 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data, return; memset(data+8, ' ', 28); - if (data[0]&0x20) { /* USB device currently not connected. Return - peripheral qualifier 001b ("...however, the - physical device is not currently connected - to this logical unit") and leave vendor and - product identification empty. ("If the target - does store some of the INQUIRY data on the - device, it may return zeros or ASCII spaces - (20h) in those fields until the data is - available from the device."). */ + if (data[0]&0x20) { /* + * USB device currently not connected. Return + * peripheral qualifier 001b ("...however, the + * physical device is not currently connected + * to this logical unit") and leave vendor and + * product identification empty. ("If the target + * does store some of the INQUIRY data on the + * device, it may return zeros or ASCII spaces + * (20h) in those fields until the data is + * available from the device."). + */ } else { u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice); int n; @@ -336,7 +346,8 @@ static int usb_stor_control_thread(void * __us) scsi_unlock(host); - /* reject the command if the direction indicator + /* + * reject the command if the direction indicator * is UNKNOWN */ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { @@ -344,7 +355,8 @@ static int usb_stor_control_thread(void * __us) us->srb->result = DID_ERROR << 16; } - /* reject if target != 0 or if LUN is higher than + /* + * reject if target != 0 or if LUN is higher than * the maximum known LUN */ else if (us->srb->device->id && @@ -362,8 +374,10 @@ static int usb_stor_control_thread(void * __us) us->srb->result = DID_BAD_TARGET << 16; } - /* Handle those devices which need us to fake - * their inquiry data */ + /* + * Handle those devices which need us to fake + * their inquiry data + */ else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { unsigned char data_ptr[36] = { @@ -395,11 +409,13 @@ SkipForAbort: usb_stor_dbg(us, "scsi command aborted\n"); } - /* If an abort request was received we need to signal that + /* + * If an abort request was received we need to signal that * the abort has finished. The proper test for this is * the TIMED_OUT flag, not srb->result == DID_ABORT, because * the timeout might have occurred after the command had - * already completed with a different result code. */ + * already completed with a different result code. + */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { complete(&(us->notify)); @@ -610,7 +626,8 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id, le16_to_cpu(dev->descriptor.idProduct), us->fflags); - /* Log a message if a non-generic unusual_dev entry contains an + /* + * Log a message if a non-generic unusual_dev entry contains an * unnecessary subclass or protocol override. This may stimulate * reports from users that will help us remove unneeded entries * from the unusual_devs.h table. @@ -782,8 +799,10 @@ static int usb_stor_acquire_resources(struct us_data *us) return -ENOMEM; } - /* Just before we start our control thread, initialize - * the device if it needs initialization */ + /* + * Just before we start our control thread, initialize + * the device if it needs initialization + */ if (us->unusual_dev->initFunction) { p = us->unusual_dev->initFunction(us); if (p) @@ -805,7 +824,8 @@ static int usb_stor_acquire_resources(struct us_data *us) /* Release all our dynamic resources */ static void usb_stor_release_resources(struct us_data *us) { - /* Tell the control thread to exit. The SCSI host must + /* + * Tell the control thread to exit. The SCSI host must * already have been removed and the DISCONNECTING flag set * so that we won't accept any more commands. */ @@ -836,7 +856,8 @@ static void dissociate_dev(struct us_data *us) usb_set_intfdata(us->pusb_intf, NULL); } -/* First stage of disconnect processing: stop SCSI scanning, +/* + * First stage of disconnect processing: stop SCSI scanning, * remove the host, and stop accepting new commands */ static void quiesce_and_remove_host(struct us_data *us) @@ -849,7 +870,8 @@ static void quiesce_and_remove_host(struct us_data *us) wake_up(&us->delay_wait); } - /* Prevent SCSI scanning (if it hasn't started yet) + /* + * Prevent SCSI scanning (if it hasn't started yet) * or wait for the SCSI-scanning routine to stop. */ cancel_delayed_work_sync(&us->scan_dwork); @@ -858,12 +880,14 @@ static void quiesce_and_remove_host(struct us_data *us) if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) usb_autopm_put_interface_no_suspend(us->pusb_intf); - /* Removing the host will perform an orderly shutdown: caches + /* + * Removing the host will perform an orderly shutdown: caches * synchronized, disks spun down, etc. */ scsi_remove_host(host); - /* Prevent any new commands from being accepted and cut short + /* + * Prevent any new commands from being accepted and cut short * reset delays. */ scsi_lock(host); @@ -878,8 +902,10 @@ static void release_everything(struct us_data *us) usb_stor_release_resources(us); dissociate_dev(us); - /* Drop our reference to the host; the SCSI core will free it - * (and "us" along with it) when the refcount becomes 0. */ + /* + * Drop our reference to the host; the SCSI core will free it + * (and "us" along with it) when the refcount becomes 0. + */ scsi_host_put(us_to_host(us)); } @@ -900,7 +926,8 @@ static void usb_stor_scan_dwork(struct work_struct *work) us->max_lun = usb_stor_Bulk_max_lun(us); /* * Allow proper scanning of devices that present more than 8 LUNs - * While not affecting other devices that may need the previous behavior + * While not affecting other devices that may need the previous + * behavior */ if (us->max_lun >= 8) us_to_host(us)->max_lun = us->max_lun+1; @@ -975,7 +1002,8 @@ int usb_stor_probe1(struct us_data **pus, get_transport(us); get_protocol(us); - /* Give the caller a chance to fill in specialized transport + /* + * Give the caller a chance to fill in specialized transport * or protocol settings. */ return 0; diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index da0ad3241728..8fae28b40bb4 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage compliant devices +/* + * Driver for USB Mass Storage compliant devices * Main Header File * * Current development and maintenance by: @@ -100,7 +101,8 @@ typedef void (*pm_hook)(struct us_data *, int); /* power management hook */ /* we allocate one of these for every device that we remember */ struct us_data { - /* The device we're working with + /* + * The device we're working with * It's important to note: * (o) you must hold dev_mutex to change pusb_dev */ @@ -125,7 +127,7 @@ struct us_data { u8 max_lun; u8 ifnum; /* interface number */ - u8 ep_bInterval; /* interrupt interval */ + u8 ep_bInterval; /* interrupt interval */ /* function pointers for this device */ trans_cmnd transport; /* transport function */ @@ -175,8 +177,10 @@ static inline struct us_data *host_to_us(struct Scsi_Host *host) { extern void fill_inquiry_response(struct us_data *us, unsigned char *data, unsigned int data_len); -/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the - * single queue element srb for write access */ +/* + * The scsi_lock() and scsi_unlock() macros protect the sm_state and the + * single queue element srb for write access + */ #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index 5ef8ce74aae4..499669bcf700 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c @@ -1,4 +1,5 @@ -/* Driver for USB Mass Storage devices +/* + * Driver for USB Mass Storage devices * Usual Tables File for usb-storage and libusual * * Copyright (C) 2009 Alan Stern (stern@rowland.harvard.edu) diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index bd99e9e47e50..17646b25343f 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -1,6 +1,6 @@ config USBIP_CORE tristate "USB/IP support" - depends on USB && NET + depends on USB_COMMON && NET ---help--- This enables pushing USB packets over IP to allow remote machines direct access to USB devices. It provides the @@ -16,7 +16,7 @@ config USBIP_CORE config USBIP_VHCI_HCD tristate "VHCI hcd" - depends on USBIP_CORE + depends on USBIP_CORE && USB ---help--- This enables the USB/IP virtual host controller driver, which is run on the remote machine. @@ -26,7 +26,7 @@ config USBIP_VHCI_HCD config USBIP_HOST tristate "Host driver" - depends on USBIP_CORE + depends on USBIP_CORE && USB ---help--- This enables the USB/IP host driver, which is run on the machine that is sharing the USB devices. @@ -34,6 +34,17 @@ config USBIP_HOST To compile this driver as a module, choose M here: the module will be called usbip-host. +config USBIP_VUDC + tristate "VUDC driver" + depends on USBIP_CORE && USB_GADGET + ---help--- + This enables the USB/IP virtual USB device controller + driver, which is run on the host machine, allowing the + machine itself to act as a device. + + To compile this driver as a module, choose M here: the + module will be called usbip-vudc. + config USBIP_DEBUG bool "Debug messages for USB/IP" depends on USBIP_CORE diff --git a/drivers/usb/usbip/Makefile b/drivers/usb/usbip/Makefile index 9ecd61545be1..d843a9e68852 100644 --- a/drivers/usb/usbip/Makefile +++ b/drivers/usb/usbip/Makefile @@ -8,3 +8,6 @@ vhci-hcd-y := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o obj-$(CONFIG_USBIP_HOST) += usbip-host.o usbip-host-y := stub_dev.o stub_main.o stub_rx.o stub_tx.o + +obj-$(CONFIG_USBIP_VUDC) += usbip-vudc.o +usbip-vudc-y := vudc_dev.o vudc_sysfs.o vudc_tx.o vudc_rx.o vudc_transfer.o vudc_main.o diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h index 266e2b0ce9a8..910f027773aa 100644 --- a/drivers/usb/usbip/stub.h +++ b/drivers/usb/usbip/stub.h @@ -33,7 +33,6 @@ #define STUB_BUSID_ALLOC 3 struct stub_device { - struct usb_interface *interface; struct usb_device *udev; struct usbip_device ud; diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c index a3ec49bdc1e6..c653ce533430 100644 --- a/drivers/usb/usbip/stub_dev.c +++ b/drivers/usb/usbip/stub_dev.c @@ -219,7 +219,7 @@ static void stub_device_reset(struct usbip_device *ud) dev_dbg(&udev->dev, "device reset"); - ret = usb_lock_device_for_reset(udev, sdev->interface); + ret = usb_lock_device_for_reset(udev, NULL); if (ret < 0) { dev_err(&udev->dev, "lock for reset\n"); spin_lock_irq(&ud->lock); @@ -252,7 +252,7 @@ static void stub_device_unusable(struct usbip_device *ud) /** * stub_device_alloc - allocate a new stub_device struct - * @interface: usb_interface of a new device + * @udev: usb_device of a new device * * Allocates and initializes a new stub_device struct. */ @@ -388,7 +388,6 @@ err_files: err_port: dev_set_drvdata(&udev->dev, NULL); usb_put_dev(udev); - kthread_stop_put(sdev->ud.eh); busid_priv->sdev = NULL; stub_device_free(sdev); @@ -449,7 +448,7 @@ static void stub_disconnect(struct usb_device *udev) } /* If usb reset is called from event handler */ - if (busid_priv->sdev->ud.eh == current) + if (usbip_in_eh(current)) return; /* shutdown the current connection */ diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 00e475c51a12..2df63e305722 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -165,12 +165,7 @@ static int tweak_reset_device_cmd(struct urb *urb) dev_info(&urb->dev->dev, "usb_queue_reset_device\n"); - /* - * With the implementation of pre_reset and post_reset the driver no - * longer unbinds. This allows the use of synchronous reset. - */ - - if (usb_lock_device_for_reset(sdev->udev, sdev->interface) < 0) { + if (usb_lock_device_for_reset(sdev->udev, NULL) < 0) { dev_err(&urb->dev->dev, "could not obtain lock to reset device\n"); return 0; } @@ -321,7 +316,7 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, priv = kmem_cache_zalloc(stub_priv_cache, GFP_ATOMIC); if (!priv) { - dev_err(&sdev->interface->dev, "alloc stub_priv\n"); + dev_err(&sdev->udev->dev, "alloc stub_priv\n"); spin_unlock_irqrestore(&sdev->priv_lock, flags); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return NULL; @@ -352,7 +347,7 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) else ep = udev->ep_out[epnum & 0x7f]; if (!ep) { - dev_err(&sdev->interface->dev, "no such endpoint?, %d\n", + dev_err(&sdev->udev->dev, "no such endpoint?, %d\n", epnum); BUG(); } @@ -387,7 +382,7 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) } /* NOT REACHED */ - dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum); + dev_err(&sdev->udev->dev, "get pipe, epnum %d\n", epnum); return 0; } @@ -466,7 +461,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, priv->urb = usb_alloc_urb(0, GFP_KERNEL); if (!priv->urb) { - dev_err(&sdev->interface->dev, "malloc urb\n"); + dev_err(&udev->dev, "malloc urb\n"); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } @@ -486,7 +481,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, GFP_KERNEL); if (!priv->urb->setup_packet) { - dev_err(&sdev->interface->dev, "allocate setup_packet\n"); + dev_err(&udev->dev, "allocate setup_packet\n"); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } @@ -517,7 +512,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, usbip_dbg_stub_rx("submit urb ok, seqnum %u\n", pdu->base.seqnum); else { - dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret); + dev_err(&udev->dev, "submit_urb error, %d\n", ret); usbip_dump_header(pdu); usbip_dump_urb(priv->urb); diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c index dbcabc9dbe0d..6b1e8c3f0e4b 100644 --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c @@ -97,7 +97,10 @@ void stub_complete(struct urb *urb) /* link a urb to the queue of tx. */ spin_lock_irqsave(&sdev->priv_lock, flags); - if (priv->unlinking) { + if (sdev->ud.tcp_socket == NULL) { + usbip_dbg_stub_tx("ignore urb for closed connection %p", urb); + /* It will be freed in stub_device_cleanup_urbs(). */ + } else if (priv->unlinking) { stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status); stub_free_priv_and_urb(priv); } else { @@ -229,7 +232,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) } if (txsize != sizeof(pdu_header) + urb->actual_length) { - dev_err(&sdev->interface->dev, + dev_err(&sdev->udev->dev, "actual length of urb %d does not match iso packet sizes %zu\n", urb->actual_length, txsize-sizeof(pdu_header)); @@ -261,7 +264,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, iovnum, txsize); if (ret != txsize) { - dev_err(&sdev->interface->dev, + dev_err(&sdev->udev->dev, "sendmsg failed!, retval %d for %zd\n", ret, txsize); kfree(iov); @@ -336,7 +339,7 @@ static int stub_send_ret_unlink(struct stub_device *sdev) ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, 1, txsize); if (ret != txsize) { - dev_err(&sdev->interface->dev, + dev_err(&sdev->udev->dev, "sendmsg failed!, retval %d for %zd\n", ret, txsize); usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index e40da7759a0e..8b232290be6b 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 Samsung Electronics + * Krzysztof Opasiak <k.opasiak@samsung.com> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -643,7 +645,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) ret); kfree(buff); - if (ud->side == USBIP_STUB) + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); else usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); @@ -665,7 +667,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) "total length of iso packets %d not equal to actual length of buffer %d\n", total_length, urb->actual_length); - if (ud->side == USBIP_STUB) + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); else usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); @@ -723,7 +725,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) int ret; int size; - if (ud->side == USBIP_STUB) { + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) { /* the direction of urb must be OUT. */ if (usb_pipein(urb->pipe)) return 0; @@ -755,7 +757,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); - if (ud->side == USBIP_STUB) { + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) { usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); } else { usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); @@ -769,12 +771,19 @@ EXPORT_SYMBOL_GPL(usbip_recv_xbuff); static int __init usbip_core_init(void) { + int ret; + pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); + ret = usbip_init_eh(); + if (ret) + return ret; + return 0; } static void __exit usbip_core_exit(void) { + usbip_finish_eh(); return; } diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index 86b08475c254..c7508cbce3ce 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 Samsung Electronics + * Krzysztof Opasiak <k.opasiak@samsung.com> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -234,6 +236,7 @@ struct usbip_iso_packet_descriptor { enum usbip_side { USBIP_VHCI, USBIP_STUB, + USBIP_VUDC, }; /* event handler */ @@ -248,6 +251,13 @@ enum usbip_side { #define SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) +#define VUDC_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE) +#define VUDC_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) +#define VUDC_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) +/* catastrophic emulated usb error */ +#define VUDC_EVENT_ERROR_USB (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) +#define VUDC_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) + #define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE) #define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) @@ -267,7 +277,6 @@ struct usbip_device { struct task_struct *tcp_tx; unsigned long event; - struct task_struct *eh; wait_queue_head_t eh_waitq; struct eh_ops { @@ -313,10 +322,13 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb); int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); /* usbip_event.c */ +int usbip_init_eh(void); +void usbip_finish_eh(void); int usbip_start_eh(struct usbip_device *ud); void usbip_stop_eh(struct usbip_device *ud); void usbip_event_add(struct usbip_device *ud, unsigned long event); int usbip_event_happened(struct usbip_device *ud); +int usbip_in_eh(struct task_struct *task); static inline int interface_to_busnum(struct usb_interface *interface) { diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c index 2580a32bcdff..f1635662c299 100644 --- a/drivers/usb/usbip/usbip_event.c +++ b/drivers/usb/usbip/usbip_event.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015 Nobuo Iwata * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,17 +20,68 @@ #include <linux/kthread.h> #include <linux/export.h> +#include <linux/slab.h> +#include <linux/workqueue.h> #include "usbip_common.h" -static int event_handler(struct usbip_device *ud) +struct usbip_event { + struct list_head node; + struct usbip_device *ud; +}; + +static DEFINE_SPINLOCK(event_lock); +static LIST_HEAD(event_list); + +static void set_event(struct usbip_device *ud, unsigned long event) { - usbip_dbg_eh("enter\n"); + unsigned long flags; - /* - * Events are handled by only this thread. - */ - while (usbip_event_happened(ud)) { + spin_lock_irqsave(&ud->lock, flags); + ud->event |= event; + spin_unlock_irqrestore(&ud->lock, flags); +} + +static void unset_event(struct usbip_device *ud, unsigned long event) +{ + unsigned long flags; + + spin_lock_irqsave(&ud->lock, flags); + ud->event &= ~event; + spin_unlock_irqrestore(&ud->lock, flags); +} + +static struct usbip_device *get_event(void) +{ + struct usbip_event *ue = NULL; + struct usbip_device *ud = NULL; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + if (!list_empty(&event_list)) { + ue = list_first_entry(&event_list, struct usbip_event, node); + list_del(&ue->node); + } + spin_unlock_irqrestore(&event_lock, flags); + + if (ue) { + ud = ue->ud; + kfree(ue); + } + return ud; +} + +static struct task_struct *worker_context; + +static void event_handler(struct work_struct *work) +{ + struct usbip_device *ud; + + if (worker_context == NULL) { + worker_context = current; + } + + while ((ud = get_event()) != NULL) { usbip_dbg_eh("pending event %lx\n", ud->event); /* @@ -38,79 +90,102 @@ static int event_handler(struct usbip_device *ud) */ if (ud->event & USBIP_EH_SHUTDOWN) { ud->eh_ops.shutdown(ud); - ud->event &= ~USBIP_EH_SHUTDOWN; + unset_event(ud, USBIP_EH_SHUTDOWN); } /* Reset the device. */ if (ud->event & USBIP_EH_RESET) { ud->eh_ops.reset(ud); - ud->event &= ~USBIP_EH_RESET; + unset_event(ud, USBIP_EH_RESET); } /* Mark the device as unusable. */ if (ud->event & USBIP_EH_UNUSABLE) { ud->eh_ops.unusable(ud); - ud->event &= ~USBIP_EH_UNUSABLE; + unset_event(ud, USBIP_EH_UNUSABLE); } /* Stop the error handler. */ if (ud->event & USBIP_EH_BYE) - return -1; + usbip_dbg_eh("removed %p\n", ud); + + wake_up(&ud->eh_waitq); } +} +int usbip_start_eh(struct usbip_device *ud) +{ + init_waitqueue_head(&ud->eh_waitq); + ud->event = 0; return 0; } +EXPORT_SYMBOL_GPL(usbip_start_eh); -static int event_handler_loop(void *data) +void usbip_stop_eh(struct usbip_device *ud) { - struct usbip_device *ud = data; + unsigned long pending = ud->event & ~USBIP_EH_BYE; - while (!kthread_should_stop()) { - wait_event_interruptible(ud->eh_waitq, - usbip_event_happened(ud) || - kthread_should_stop()); - usbip_dbg_eh("wakeup\n"); + if (!(ud->event & USBIP_EH_BYE)) + usbip_dbg_eh("usbip_eh stopping but not removed\n"); - if (event_handler(ud) < 0) - break; - } + if (pending) + usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending); - return 0; + wait_event_interruptible(ud->eh_waitq, !(ud->event & ~USBIP_EH_BYE)); + usbip_dbg_eh("usbip_eh has stopped\n"); } +EXPORT_SYMBOL_GPL(usbip_stop_eh); -int usbip_start_eh(struct usbip_device *ud) -{ - init_waitqueue_head(&ud->eh_waitq); - ud->event = 0; +#define WORK_QUEUE_NAME "usbip_event" - ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh"); - if (IS_ERR(ud->eh)) { - pr_warn("Unable to start control thread\n"); - return PTR_ERR(ud->eh); - } +static struct workqueue_struct *usbip_queue; +static DECLARE_WORK(usbip_work, event_handler); +int usbip_init_eh(void) +{ + usbip_queue = create_singlethread_workqueue(WORK_QUEUE_NAME); + if (usbip_queue == NULL) { + pr_err("failed to create usbip_event\n"); + return -ENOMEM; + } return 0; } -EXPORT_SYMBOL_GPL(usbip_start_eh); -void usbip_stop_eh(struct usbip_device *ud) +void usbip_finish_eh(void) { - if (ud->eh == current) - return; /* do not wait for myself */ - - kthread_stop(ud->eh); - usbip_dbg_eh("usbip_eh has finished\n"); + flush_workqueue(usbip_queue); + destroy_workqueue(usbip_queue); + usbip_queue = NULL; } -EXPORT_SYMBOL_GPL(usbip_stop_eh); void usbip_event_add(struct usbip_device *ud, unsigned long event) { + struct usbip_event *ue; unsigned long flags; - spin_lock_irqsave(&ud->lock, flags); - ud->event |= event; - wake_up(&ud->eh_waitq); - spin_unlock_irqrestore(&ud->lock, flags); + if (ud->event & USBIP_EH_BYE) + return; + + set_event(ud, event); + + spin_lock_irqsave(&event_lock, flags); + + list_for_each_entry_reverse(ue, &event_list, node) { + if (ue->ud == ud) + goto out; + } + + ue = kmalloc(sizeof(struct usbip_event), GFP_ATOMIC); + if (ue == NULL) + goto out; + + ue->ud = ud; + + list_add_tail(&ue->node, &event_list); + queue_work(usbip_queue, &usbip_work); + +out: + spin_unlock_irqrestore(&event_lock, flags); } EXPORT_SYMBOL_GPL(usbip_event_add); @@ -127,3 +202,12 @@ int usbip_event_happened(struct usbip_device *ud) return happened; } EXPORT_SYMBOL_GPL(usbip_event_happened); + +int usbip_in_eh(struct task_struct *task) +{ + if (task == worker_context) + return 1; + + return 0; +} +EXPORT_SYMBOL_GPL(usbip_in_eh); diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index fca51105974e..2e0450bec1b1 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -941,7 +941,7 @@ static void vhci_stop(struct usb_hcd *hcd) static int vhci_get_frame_number(struct usb_hcd *hcd) { - pr_err("Not yet implemented\n"); + dev_err_ratelimited(&hcd->self.root_hub->dev, "Not yet implemented\n"); return 0; } diff --git a/drivers/usb/usbip/vudc.h b/drivers/usb/usbip/vudc.h new file mode 100644 index 000000000000..25e01b09c4c3 --- /dev/null +++ b/drivers/usb/usbip/vudc.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.com> + * Krzysztof Opasiak <k.opasiak@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __USBIP_VUDC_H +#define __USBIP_VUDC_H + +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/time.h> +#include <linux/sysfs.h> + +#include "usbip_common.h" + +#define GADGET_NAME "usbip-vudc" + +struct vep { + struct usb_ep ep; + unsigned type:2; /* type, as USB_ENDPOINT_XFER_* */ + char name[8]; /* space for ep name */ + + const struct usb_endpoint_descriptor *desc; + struct usb_gadget *gadget; + struct list_head req_queue; /* Request queue */ + unsigned halted:1; + unsigned wedged:1; + unsigned already_seen:1; + unsigned setup_stage:1; +}; + +struct vrequest { + struct usb_request req; + struct vudc *udc; + struct list_head req_entry; /* Request queue */ +}; + +struct urbp { + struct urb *urb; + struct vep *ep; + struct list_head urb_entry; /* urb queue */ + unsigned long seqnum; + unsigned type:2; /* for tx, since ep type can change after */ + unsigned new:1; +}; + +struct v_unlink { + unsigned long seqnum; + __u32 status; +}; + +enum tx_type { + TX_UNLINK, + TX_SUBMIT, +}; + +struct tx_item { + struct list_head tx_entry; + enum tx_type type; + union { + struct urbp *s; + struct v_unlink *u; + }; +}; + +enum tr_state { + VUDC_TR_RUNNING, + VUDC_TR_IDLE, + VUDC_TR_STOPPED, +}; + +struct transfer_timer { + struct timer_list timer; + enum tr_state state; + unsigned long frame_start; + int frame_limit; +}; + +struct vudc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + + struct usb_device_descriptor dev_desc; + + struct usbip_device ud; + struct transfer_timer tr_timer; + struct timeval start_time; + + struct list_head urb_queue; + + spinlock_t lock_tx; + struct list_head tx_queue; + wait_queue_head_t tx_waitq; + + spinlock_t lock; + struct vep *ep; + int address; + u16 devstatus; + + unsigned pullup:1; + unsigned connected:1; + unsigned desc_cached:1; +}; + +struct vudc_device { + struct platform_device *pdev; + struct list_head dev_entry; +}; + +extern const struct attribute_group vudc_attr_group; + +/* visible everywhere */ + +static inline struct vep *to_vep(struct usb_ep *_ep) +{ + return container_of(_ep, struct vep, ep); +} + +static inline struct vrequest *to_vrequest( + struct usb_request *_req) +{ + return container_of(_req, struct vrequest, req); +} + +static inline struct vudc *usb_gadget_to_vudc( + struct usb_gadget *_gadget) +{ + return container_of(_gadget, struct vudc, gadget); +} + +static inline struct vudc *ep_to_vudc(struct vep *ep) +{ + return container_of(ep->gadget, struct vudc, gadget); +} + +/* vudc_sysfs.c */ + +int get_gadget_descs(struct vudc *udc); + +/* vudc_tx.c */ + +int v_tx_loop(void *data); +void v_enqueue_ret_unlink(struct vudc *udc, __u32 seqnum, __u32 status); +void v_enqueue_ret_submit(struct vudc *udc, struct urbp *urb_p); + +/* vudc_rx.c */ + +int v_rx_loop(void *data); + +/* vudc_transfer.c */ + +void v_init_timer(struct vudc *udc); +void v_start_timer(struct vudc *udc); +void v_kick_timer(struct vudc *udc, unsigned long time); +void v_stop_timer(struct vudc *udc); + +/* vudc_dev.c */ + +struct urbp *alloc_urbp(void); +void free_urbp_and_urb(struct urbp *urb_p); + +struct vep *vudc_find_endpoint(struct vudc *udc, u8 address); + +struct vudc_device *alloc_vudc_device(int devid); +void put_vudc_device(struct vudc_device *udc_dev); + +int vudc_probe(struct platform_device *pdev); +int vudc_remove(struct platform_device *pdev); + +#endif /* __USBIP_VUDC_H */ diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c new file mode 100644 index 000000000000..8994a13819ab --- /dev/null +++ b/drivers/usb/usbip/vudc_dev.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.com> + * Krzysztof Opasiak <k.opasiak@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/kthread.h> +#include <linux/file.h> +#include <linux/byteorder/generic.h> + +#include "usbip_common.h" +#include "vudc.h" + +#define VIRTUAL_ENDPOINTS (1 /* ep0 */ + 15 /* in eps */ + 15 /* out eps */) + +/* urb-related structures alloc / free */ + + +static void free_urb(struct urb *urb) +{ + if (!urb) + return; + + kfree(urb->setup_packet); + urb->setup_packet = NULL; + + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; + + usb_free_urb(urb); +} + +struct urbp *alloc_urbp(void) +{ + struct urbp *urb_p; + + urb_p = kzalloc(sizeof(*urb_p), GFP_KERNEL); + if (!urb_p) + return urb_p; + + urb_p->urb = NULL; + urb_p->ep = NULL; + INIT_LIST_HEAD(&urb_p->urb_entry); + return urb_p; +} + +static void free_urbp(struct urbp *urb_p) +{ + kfree(urb_p); +} + +void free_urbp_and_urb(struct urbp *urb_p) +{ + if (!urb_p) + return; + free_urb(urb_p->urb); + free_urbp(urb_p); +} + + +/* utilities ; almost verbatim from dummy_hcd.c */ + +/* called with spinlock held */ +static void nuke(struct vudc *udc, struct vep *ep) +{ + struct vrequest *req; + + while (!list_empty(&ep->req_queue)) { + req = list_first_entry(&ep->req_queue, struct vrequest, + req_entry); + list_del_init(&req->req_entry); + req->req.status = -ESHUTDOWN; + + spin_unlock(&udc->lock); + usb_gadget_giveback_request(&ep->ep, &req->req); + spin_lock(&udc->lock); + } +} + +/* caller must hold lock */ +static void stop_activity(struct vudc *udc) +{ + int i; + struct urbp *urb_p, *tmp; + + udc->address = 0; + + for (i = 0; i < VIRTUAL_ENDPOINTS; i++) + nuke(udc, &udc->ep[i]); + + list_for_each_entry_safe(urb_p, tmp, &udc->urb_queue, urb_entry) { + list_del(&urb_p->urb_entry); + free_urbp_and_urb(urb_p); + } +} + +struct vep *vudc_find_endpoint(struct vudc *udc, u8 address) +{ + int i; + + if ((address & ~USB_DIR_IN) == 0) + return &udc->ep[0]; + + for (i = 1; i < VIRTUAL_ENDPOINTS; i++) { + struct vep *ep = &udc->ep[i]; + + if (!ep->desc) + continue; + if (ep->desc->bEndpointAddress == address) + return ep; + } + return NULL; +} + +/* gadget ops */ + +/* FIXME - this will probably misbehave when suspend/resume is added */ +static int vgadget_get_frame(struct usb_gadget *_gadget) +{ + struct timeval now; + struct vudc *udc = usb_gadget_to_vudc(_gadget); + + do_gettimeofday(&now); + return ((now.tv_sec - udc->start_time.tv_sec) * 1000 + + (now.tv_usec - udc->start_time.tv_usec) / 1000) + % 0x7FF; +} + +static int vgadget_set_selfpowered(struct usb_gadget *_gadget, int value) +{ + struct vudc *udc = usb_gadget_to_vudc(_gadget); + + if (value) + udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); + else + udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); + return 0; +} + +static int vgadget_pullup(struct usb_gadget *_gadget, int value) +{ + struct vudc *udc = usb_gadget_to_vudc(_gadget); + unsigned long flags; + int ret; + + + spin_lock_irqsave(&udc->lock, flags); + value = !!value; + if (value == udc->pullup) + goto unlock; + + udc->pullup = value; + if (value) { + udc->gadget.speed = min_t(u8, USB_SPEED_HIGH, + udc->driver->max_speed); + udc->ep[0].ep.maxpacket = 64; + /* + * This is the first place where we can ask our + * gadget driver for descriptors. + */ + ret = get_gadget_descs(udc); + if (ret) { + dev_err(&udc->gadget.dev, "Unable go get desc: %d", ret); + goto unlock; + } + + spin_unlock_irqrestore(&udc->lock, flags); + usbip_start_eh(&udc->ud); + } else { + /* Invalidate descriptors */ + udc->desc_cached = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + usbip_event_add(&udc->ud, VUDC_EVENT_REMOVED); + usbip_stop_eh(&udc->ud); /* Wait for eh completion */ + } + + return 0; + +unlock: + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static int vgadget_udc_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + struct vudc *udc = usb_gadget_to_vudc(g); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + udc->driver = driver; + udc->pullup = udc->connected = udc->desc_cached = 0; + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int vgadget_udc_stop(struct usb_gadget *g) +{ + struct vudc *udc = usb_gadget_to_vudc(g); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + udc->driver = NULL; + spin_unlock_irqrestore(&udc->lock, flags); + return 0; +} + +static const struct usb_gadget_ops vgadget_ops = { + .get_frame = vgadget_get_frame, + .set_selfpowered = vgadget_set_selfpowered, + .pullup = vgadget_pullup, + .udc_start = vgadget_udc_start, + .udc_stop = vgadget_udc_stop, +}; + + +/* endpoint ops */ + +static int vep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct vep *ep; + struct vudc *udc; + unsigned maxp; + unsigned long flags; + + ep = to_vep(_ep); + udc = ep_to_vudc(ep); + + if (!_ep || !desc || ep->desc || _ep->caps.type_control + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + + if (!udc->driver) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc->lock, flags); + + maxp = usb_endpoint_maxp(desc) & 0x7ff; + _ep->maxpacket = maxp; + ep->desc = desc; + ep->type = usb_endpoint_type(desc); + ep->halted = ep->wedged = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int vep_disable(struct usb_ep *_ep) +{ + struct vep *ep; + struct vudc *udc; + unsigned long flags; + + ep = to_vep(_ep); + udc = ep_to_vudc(ep); + if (!_ep || !ep->desc || _ep->caps.type_control) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + ep->desc = NULL; + nuke(udc, ep); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request *vep_alloc_request(struct usb_ep *_ep, + gfp_t mem_flags) +{ + struct vep *ep; + struct vrequest *req; + + if (!_ep) + return NULL; + ep = to_vep(_ep); + + req = kzalloc(sizeof(*req), mem_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->req_entry); + + return &req->req; +} + +static void vep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vrequest *req; + + if (WARN_ON(!_ep || !_req)) + return; + + req = to_vrequest(_req); + kfree(req); +} + +static int vep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t mem_flags) +{ + struct vep *ep; + struct vrequest *req; + struct vudc *udc; + unsigned long flags; + + if (!_ep || !_req) + return -EINVAL; + + ep = to_vep(_ep); + req = to_vrequest(_req); + udc = ep_to_vudc(ep); + + spin_lock_irqsave(&udc->lock, flags); + _req->actual = 0; + _req->status = -EINPROGRESS; + + list_add_tail(&req->req_entry, &ep->req_queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct vep *ep; + struct vrequest *req; + struct vudc *udc; + struct vrequest *lst; + unsigned long flags; + int ret = -EINVAL; + + if (!_ep || !_req) + return ret; + + ep = to_vep(_ep); + req = to_vrequest(_req); + udc = req->udc; + + if (!udc->driver) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc->lock, flags); + list_for_each_entry(lst, &ep->req_queue, req_entry) { + if (&lst->req == _req) { + list_del_init(&lst->req_entry); + _req->status = -ECONNRESET; + ret = 0; + break; + } + } + spin_unlock_irqrestore(&udc->lock, flags); + + if (ret == 0) + usb_gadget_giveback_request(_ep, _req); + + return ret; +} + +static int +vep_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) +{ + struct vep *ep; + struct vudc *udc; + unsigned long flags; + int ret = 0; + + ep = to_vep(_ep); + if (!_ep) + return -EINVAL; + + udc = ep_to_vudc(ep); + if (!udc->driver) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc->lock, flags); + if (!value) + ep->halted = ep->wedged = 0; + else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && + !list_empty(&ep->req_queue)) + ret = -EAGAIN; + else { + ep->halted = 1; + if (wedged) + ep->wedged = 1; + } + + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} + +static int +vep_set_halt(struct usb_ep *_ep, int value) +{ + return vep_set_halt_and_wedge(_ep, value, 0); +} + +static int vep_set_wedge(struct usb_ep *_ep) +{ + return vep_set_halt_and_wedge(_ep, 1, 1); +} + +static const struct usb_ep_ops vep_ops = { + .enable = vep_enable, + .disable = vep_disable, + + .alloc_request = vep_alloc_request, + .free_request = vep_free_request, + + .queue = vep_queue, + .dequeue = vep_dequeue, + + .set_halt = vep_set_halt, + .set_wedge = vep_set_wedge, +}; + + +/* shutdown / reset / error handlers */ + +static void vudc_shutdown(struct usbip_device *ud) +{ + struct vudc *udc = container_of(ud, struct vudc, ud); + int call_disconnect = 0; + unsigned long flags; + + dev_dbg(&udc->pdev->dev, "device shutdown"); + if (ud->tcp_socket) + kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); + + if (ud->tcp_tx) { + kthread_stop_put(ud->tcp_rx); + ud->tcp_rx = NULL; + } + if (ud->tcp_tx) { + kthread_stop_put(ud->tcp_tx); + ud->tcp_tx = NULL; + } + + if (ud->tcp_socket) { + sockfd_put(ud->tcp_socket); + ud->tcp_socket = NULL; + } + + spin_lock_irqsave(&udc->lock, flags); + stop_activity(udc); + if (udc->connected && udc->driver->disconnect) + call_disconnect = 1; + udc->connected = 0; + spin_unlock_irqrestore(&udc->lock, flags); + if (call_disconnect) + udc->driver->disconnect(&udc->gadget); +} + +static void vudc_device_reset(struct usbip_device *ud) +{ + struct vudc *udc = container_of(ud, struct vudc, ud); + unsigned long flags; + + dev_dbg(&udc->pdev->dev, "device reset"); + spin_lock_irqsave(&udc->lock, flags); + stop_activity(udc); + spin_unlock_irqrestore(&udc->lock, flags); + if (udc->driver) + usb_gadget_udc_reset(&udc->gadget, udc->driver); + spin_lock_irqsave(&ud->lock, flags); + ud->status = SDEV_ST_AVAILABLE; + spin_unlock_irqrestore(&ud->lock, flags); +} + +static void vudc_device_unusable(struct usbip_device *ud) +{ + unsigned long flags; + + spin_lock_irqsave(&ud->lock, flags); + ud->status = SDEV_ST_ERROR; + spin_unlock_irqrestore(&ud->lock, flags); +} + +/* device setup / cleanup */ + +struct vudc_device *alloc_vudc_device(int devid) +{ + struct vudc_device *udc_dev = NULL; + + udc_dev = kzalloc(sizeof(*udc_dev), GFP_KERNEL); + if (!udc_dev) + goto out; + + INIT_LIST_HEAD(&udc_dev->dev_entry); + + udc_dev->pdev = platform_device_alloc(GADGET_NAME, devid); + if (!udc_dev->pdev) { + kfree(udc_dev); + udc_dev = NULL; + } + +out: + return udc_dev; +} + +void put_vudc_device(struct vudc_device *udc_dev) +{ + platform_device_put(udc_dev->pdev); + kfree(udc_dev); +} + +static int init_vudc_hw(struct vudc *udc) +{ + int i; + struct usbip_device *ud = &udc->ud; + struct vep *ep; + + udc->ep = kcalloc(VIRTUAL_ENDPOINTS, sizeof(*udc->ep), GFP_KERNEL); + if (!udc->ep) + goto nomem_ep; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + + /* create ep0 and 15 in, 15 out general purpose eps */ + for (i = 0; i < VIRTUAL_ENDPOINTS; ++i) { + int is_out = i % 2; + int num = (i + 1) / 2; + + ep = &udc->ep[i]; + + sprintf(ep->name, "ep%d%s", num, + i ? (is_out ? "out" : "in") : ""); + ep->ep.name = ep->name; + if (i == 0) { + ep->ep.caps.type_control = true; + ep->ep.caps.dir_out = true; + ep->ep.caps.dir_in = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_int = true; + ep->ep.caps.type_bulk = true; + } + + if (is_out) + ep->ep.caps.dir_out = true; + else + ep->ep.caps.dir_in = true; + + ep->ep.ops = &vep_ops; + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->halted = ep->wedged = ep->already_seen = + ep->setup_stage = 0; + usb_ep_set_maxpacket_limit(&ep->ep, ~0); + ep->ep.max_streams = 16; + ep->gadget = &udc->gadget; + ep->desc = NULL; + INIT_LIST_HEAD(&ep->req_queue); + } + + spin_lock_init(&udc->lock); + spin_lock_init(&udc->lock_tx); + INIT_LIST_HEAD(&udc->urb_queue); + INIT_LIST_HEAD(&udc->tx_queue); + init_waitqueue_head(&udc->tx_waitq); + + spin_lock_init(&ud->lock); + ud->status = SDEV_ST_AVAILABLE; + ud->side = USBIP_VUDC; + + ud->eh_ops.shutdown = vudc_shutdown; + ud->eh_ops.reset = vudc_device_reset; + ud->eh_ops.unusable = vudc_device_unusable; + + udc->gadget.ep0 = &udc->ep[0].ep; + list_del_init(&udc->ep[0].ep.ep_list); + + v_init_timer(udc); + return 0; + +nomem_ep: + return -ENOMEM; +} + +static void cleanup_vudc_hw(struct vudc *udc) +{ + kfree(udc->ep); +} + +/* platform driver ops */ + +int vudc_probe(struct platform_device *pdev) +{ + struct vudc *udc; + int ret = -ENOMEM; + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto out; + + udc->gadget.name = GADGET_NAME; + udc->gadget.ops = &vgadget_ops; + udc->gadget.max_speed = USB_SPEED_HIGH; + udc->gadget.dev.parent = &pdev->dev; + udc->pdev = pdev; + + ret = init_vudc_hw(udc); + if (ret) + goto err_init_vudc_hw; + + ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (ret < 0) + goto err_add_udc; + + ret = sysfs_create_group(&pdev->dev.kobj, &vudc_attr_group); + if (ret) { + dev_err(&udc->pdev->dev, "create sysfs files\n"); + goto err_sysfs; + } + + platform_set_drvdata(pdev, udc); + + return ret; + +err_sysfs: + usb_del_gadget_udc(&udc->gadget); +err_add_udc: + cleanup_vudc_hw(udc); +err_init_vudc_hw: + kfree(udc); +out: + return ret; +} + +int vudc_remove(struct platform_device *pdev) +{ + struct vudc *udc = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &vudc_attr_group); + usb_del_gadget_udc(&udc->gadget); + cleanup_vudc_hw(udc); + kfree(udc); + return 0; +} diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c new file mode 100644 index 000000000000..9e655714e389 --- /dev/null +++ b/drivers/usb/usbip/vudc_main.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.com> + * Krzysztof Opasiak <k.opasiak@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/list.h> +#include <linux/module.h> + +#include "vudc.h" + +static unsigned int vudc_number = 1; + +module_param_named(num, vudc_number, uint, S_IRUGO); +MODULE_PARM_DESC(num, "number of emulated controllers"); + +static struct platform_driver vudc_driver = { + .probe = vudc_probe, + .remove = vudc_remove, + .driver = { + .name = GADGET_NAME, + }, +}; + +static struct list_head vudc_devices = LIST_HEAD_INIT(vudc_devices); + +static int __init init(void) +{ + int retval = -ENOMEM; + int i; + struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL; + + if (usb_disabled()) + return -ENODEV; + + if (vudc_number < 1) { + pr_err("Number of emulated UDC must be no less than 1"); + return -EINVAL; + } + + retval = platform_driver_register(&vudc_driver); + if (retval < 0) + goto out; + + for (i = 0; i < vudc_number; i++) { + udc_dev = alloc_vudc_device(i); + if (!udc_dev) { + retval = -ENOMEM; + goto cleanup; + } + + retval = platform_device_add(udc_dev->pdev); + if (retval < 0) { + put_vudc_device(udc_dev); + goto cleanup; + } + + list_add_tail(&udc_dev->dev_entry, &vudc_devices); + if (!platform_get_drvdata(udc_dev->pdev)) { + /* + * The udc was added successfully but its probe + * function failed for some reason. + */ + retval = -EINVAL; + goto cleanup; + } + } + goto out; + +cleanup: + list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { + list_del(&udc_dev->dev_entry); + platform_device_del(udc_dev->pdev); + put_vudc_device(udc_dev); + } + + platform_driver_unregister(&vudc_driver); +out: + return retval; +} +module_init(init); + +static void __exit cleanup(void) +{ + struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL; + + list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) { + list_del(&udc_dev->dev_entry); + platform_device_unregister(udc_dev->pdev); + put_vudc_device(udc_dev); + } + platform_driver_unregister(&vudc_driver); +} +module_exit(cleanup); + +MODULE_DESCRIPTION("USB over IP Device Controller"); +MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/usbip/vudc_rx.c b/drivers/usb/usbip/vudc_rx.c new file mode 100644 index 000000000000..344bd9473475 --- /dev/null +++ b/drivers/usb/usbip/vudc_rx.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <net/sock.h> +#include <linux/list.h> +#include <linux/kthread.h> + +#include "usbip_common.h" +#include "vudc.h" + +static int alloc_urb_from_cmd(struct urb **urbp, + struct usbip_header *pdu, u8 type) +{ + struct urb *urb; + + if (type == USB_ENDPOINT_XFER_ISOC) + urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets, + GFP_KERNEL); + else + urb = usb_alloc_urb(0, GFP_KERNEL); + + if (!urb) + goto err; + + usbip_pack_pdu(pdu, urb, USBIP_CMD_SUBMIT, 0); + + if (urb->transfer_buffer_length > 0) { + urb->transfer_buffer = kzalloc(urb->transfer_buffer_length, + GFP_KERNEL); + if (!urb->transfer_buffer) + goto free_urb; + } + + urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, + GFP_KERNEL); + if (!urb->setup_packet) + goto free_buffer; + + /* + * FIXME - we only setup pipe enough for usbip functions + * to behave nicely + */ + urb->pipe |= pdu->base.direction == USBIP_DIR_IN ? + USB_DIR_IN : USB_DIR_OUT; + + *urbp = urb; + return 0; + +free_buffer: + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; +free_urb: + usb_free_urb(urb); +err: + return -ENOMEM; +} + +static int v_recv_cmd_unlink(struct vudc *udc, + struct usbip_header *pdu) +{ + unsigned long flags; + struct urbp *urb_p; + + spin_lock_irqsave(&udc->lock, flags); + list_for_each_entry(urb_p, &udc->urb_queue, urb_entry) { + if (urb_p->seqnum != pdu->u.cmd_unlink.seqnum) + continue; + urb_p->urb->unlinked = -ECONNRESET; + urb_p->seqnum = pdu->base.seqnum; + v_kick_timer(udc, jiffies); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; + } + /* Not found, completed / not queued */ + spin_lock(&udc->lock_tx); + v_enqueue_ret_unlink(udc, pdu->base.seqnum, 0); + wake_up(&udc->tx_waitq); + spin_unlock(&udc->lock_tx); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int v_recv_cmd_submit(struct vudc *udc, + struct usbip_header *pdu) +{ + int ret = 0; + struct urbp *urb_p; + u8 address; + unsigned long flags; + + urb_p = alloc_urbp(); + if (!urb_p) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); + return -ENOMEM; + } + + /* base.ep is pipeendpoint(pipe) */ + address = pdu->base.ep; + if (pdu->base.direction == USBIP_DIR_IN) + address |= USB_DIR_IN; + + spin_lock_irq(&udc->lock); + urb_p->ep = vudc_find_endpoint(udc, address); + if (!urb_p->ep) { + /* we don't know the type, there may be isoc data! */ + dev_err(&udc->pdev->dev, "request to nonexistent endpoint"); + spin_unlock_irq(&udc->lock); + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); + ret = -EPIPE; + goto free_urbp; + } + urb_p->type = urb_p->ep->type; + spin_unlock_irq(&udc->lock); + + urb_p->new = 1; + urb_p->seqnum = pdu->base.seqnum; + + ret = alloc_urb_from_cmd(&urb_p->urb, pdu, urb_p->ep->type); + if (ret) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); + ret = -ENOMEM; + goto free_urbp; + } + + urb_p->urb->status = -EINPROGRESS; + + /* FIXME: more pipe setup to please usbip_common */ + urb_p->urb->pipe &= ~(11 << 30); + switch (urb_p->ep->type) { + case USB_ENDPOINT_XFER_BULK: + urb_p->urb->pipe |= (PIPE_BULK << 30); + break; + case USB_ENDPOINT_XFER_INT: + urb_p->urb->pipe |= (PIPE_INTERRUPT << 30); + break; + case USB_ENDPOINT_XFER_CONTROL: + urb_p->urb->pipe |= (PIPE_CONTROL << 30); + break; + case USB_ENDPOINT_XFER_ISOC: + urb_p->urb->pipe |= (PIPE_ISOCHRONOUS << 30); + break; + } + ret = usbip_recv_xbuff(&udc->ud, urb_p->urb); + if (ret < 0) + goto free_urbp; + + ret = usbip_recv_iso(&udc->ud, urb_p->urb); + if (ret < 0) + goto free_urbp; + + spin_lock_irqsave(&udc->lock, flags); + v_kick_timer(udc, jiffies); + list_add_tail(&urb_p->urb_entry, &udc->urb_queue); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; + +free_urbp: + free_urbp_and_urb(urb_p); + return ret; +} + +static int v_rx_pdu(struct usbip_device *ud) +{ + int ret; + struct usbip_header pdu; + struct vudc *udc = container_of(ud, struct vudc, ud); + + memset(&pdu, 0, sizeof(pdu)); + ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); + if (ret != sizeof(pdu)) { + usbip_event_add(ud, VUDC_EVENT_ERROR_TCP); + if (ret >= 0) + return -EPIPE; + return ret; + } + usbip_header_correct_endian(&pdu, 0); + + spin_lock_irq(&ud->lock); + ret = (ud->status == SDEV_ST_USED); + spin_unlock_irq(&ud->lock); + if (!ret) { + usbip_event_add(ud, VUDC_EVENT_ERROR_TCP); + return -EBUSY; + } + + switch (pdu.base.command) { + case USBIP_CMD_UNLINK: + ret = v_recv_cmd_unlink(udc, &pdu); + break; + case USBIP_CMD_SUBMIT: + ret = v_recv_cmd_submit(udc, &pdu); + break; + default: + ret = -EPIPE; + pr_err("rx: unknown command"); + break; + } + return ret; +} + +int v_rx_loop(void *data) +{ + struct usbip_device *ud = data; + int ret = 0; + + while (!kthread_should_stop()) { + if (usbip_event_happened(ud)) + break; + ret = v_rx_pdu(ud); + if (ret < 0) { + pr_warn("v_rx exit with error %d", ret); + break; + } + } + return ret; +} diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c new file mode 100644 index 000000000000..99397fa1e3f0 --- /dev/null +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.com> + * Krzysztof Opasiak <k.opasiak@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/list.h> +#include <linux/usb/gadget.h> +#include <linux/usb/ch9.h> +#include <linux/sysfs.h> +#include <linux/kthread.h> +#include <linux/byteorder/generic.h> + +#include "usbip_common.h" +#include "vudc.h" + +#include <net/sock.h> + +/* called with udc->lock held */ +int get_gadget_descs(struct vudc *udc) +{ + struct vrequest *usb_req; + struct vep *ep0 = to_vep(udc->gadget.ep0); + struct usb_device_descriptor *ddesc = &udc->dev_desc; + struct usb_ctrlrequest req; + int ret; + + if (!udc || !udc->driver || !udc->pullup) + return -EINVAL; + + req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; + req.bRequest = USB_REQ_GET_DESCRIPTOR; + req.wValue = cpu_to_le16(USB_DT_DEVICE << 8); + req.wIndex = cpu_to_le16(0); + req.wLength = cpu_to_le16(sizeof(*ddesc)); + + spin_unlock(&udc->lock); + ret = udc->driver->setup(&(udc->gadget), &req); + spin_lock(&udc->lock); + if (ret < 0) + goto out; + + /* assuming request queue is empty; request is now on top */ + usb_req = list_last_entry(&ep0->req_queue, struct vrequest, req_entry); + list_del(&usb_req->req_entry); + + if (usb_req->req.length > sizeof(*ddesc)) { + ret = -EOVERFLOW; + goto giveback_req; + } + + memcpy(ddesc, usb_req->req.buf, sizeof(*ddesc)); + udc->desc_cached = 1; + ret = 0; +giveback_req: + usb_req->req.status = 0; + usb_req->req.actual = usb_req->req.length; + usb_gadget_giveback_request(&(ep0->ep), &(usb_req->req)); +out: + return ret; +} + +/* + * Exposes device descriptor from the gadget driver. + */ +static ssize_t dev_desc_read(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *out, + loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct vudc *udc = (struct vudc *)dev_get_drvdata(dev); + char *desc_ptr = (char *) &udc->dev_desc; + unsigned long flags; + int ret; + + spin_lock_irqsave(&udc->lock, flags); + if (!udc->desc_cached) { + ret = -ENODEV; + goto unlock; + } + + memcpy(out, desc_ptr + off, count); + ret = count; +unlock: + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} +static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor)); + +static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, + const char *in, size_t count) +{ + struct vudc *udc = (struct vudc *) dev_get_drvdata(dev); + int rv; + int sockfd = 0; + int err; + struct socket *socket; + unsigned long flags; + int ret; + + rv = kstrtoint(in, 0, &sockfd); + if (rv != 0) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + /* Don't export what we don't have */ + if (!udc || !udc->driver || !udc->pullup) { + dev_err(dev, "no device or gadget not bound"); + ret = -ENODEV; + goto unlock; + } + + if (sockfd != -1) { + if (udc->connected) { + dev_err(dev, "Device already connected"); + ret = -EBUSY; + goto unlock; + } + + spin_lock_irq(&udc->ud.lock); + + if (udc->ud.status != SDEV_ST_AVAILABLE) { + ret = -EINVAL; + goto unlock_ud; + } + + socket = sockfd_lookup(sockfd, &err); + if (!socket) { + dev_err(dev, "failed to lookup sock"); + ret = -EINVAL; + goto unlock_ud; + } + + udc->ud.tcp_socket = socket; + + spin_unlock_irq(&udc->ud.lock); + spin_unlock_irqrestore(&udc->lock, flags); + + udc->ud.tcp_rx = kthread_get_run(&v_rx_loop, + &udc->ud, "vudc_rx"); + udc->ud.tcp_tx = kthread_get_run(&v_tx_loop, + &udc->ud, "vudc_tx"); + + spin_lock_irqsave(&udc->lock, flags); + spin_lock_irq(&udc->ud.lock); + udc->ud.status = SDEV_ST_USED; + spin_unlock_irq(&udc->ud.lock); + + do_gettimeofday(&udc->start_time); + v_start_timer(udc); + udc->connected = 1; + } else { + if (!udc->connected) { + dev_err(dev, "Device not connected"); + ret = -EINVAL; + goto unlock; + } + + spin_lock_irq(&udc->ud.lock); + if (udc->ud.status != SDEV_ST_USED) { + ret = -EINVAL; + goto unlock_ud; + } + spin_unlock_irq(&udc->ud.lock); + + usbip_event_add(&udc->ud, VUDC_EVENT_DOWN); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return count; + +unlock_ud: + spin_unlock_irq(&udc->ud.lock); +unlock: + spin_unlock_irqrestore(&udc->lock, flags); + + return ret; +} +static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd); + +static ssize_t usbip_status_show(struct device *dev, + struct device_attribute *attr, char *out) +{ + struct vudc *udc = (struct vudc *) dev_get_drvdata(dev); + int status; + + if (!udc) { + dev_err(dev, "no device"); + return -ENODEV; + } + spin_lock_irq(&udc->ud.lock); + status = udc->ud.status; + spin_unlock_irq(&udc->ud.lock); + + return snprintf(out, PAGE_SIZE, "%d\n", status); +} +static DEVICE_ATTR_RO(usbip_status); + +static struct attribute *dev_attrs[] = { + &dev_attr_usbip_sockfd.attr, + &dev_attr_usbip_status.attr, + NULL, +}; + +static struct bin_attribute *dev_bin_attrs[] = { + &bin_attr_dev_desc, + NULL, +}; + +const struct attribute_group vudc_attr_group = { + .attrs = dev_attrs, + .bin_attrs = dev_bin_attrs, +}; diff --git a/drivers/usb/usbip/vudc_transfer.c b/drivers/usb/usbip/vudc_transfer.c new file mode 100644 index 000000000000..aba6bd478045 --- /dev/null +++ b/drivers/usb/usbip/vudc_transfer.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.com> + * + * Based on dummy_hcd.c, which is: + * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2005 Alan Stern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/usb.h> +#include <linux/timer.h> +#include <linux/usb/ch9.h> + +#include "vudc.h" + +#define DEV_REQUEST (USB_TYPE_STANDARD | USB_RECIP_DEVICE) +#define DEV_INREQUEST (DEV_REQUEST | USB_DIR_IN) +#define INTF_REQUEST (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define INTF_INREQUEST (INTF_REQUEST | USB_DIR_IN) +#define EP_REQUEST (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) +#define EP_INREQUEST (EP_REQUEST | USB_DIR_IN) + +static int get_frame_limit(enum usb_device_speed speed) +{ + switch (speed) { + case USB_SPEED_LOW: + return 8 /*bytes*/ * 12 /*packets*/; + case USB_SPEED_FULL: + return 64 /*bytes*/ * 19 /*packets*/; + case USB_SPEED_HIGH: + return 512 /*bytes*/ * 13 /*packets*/ * 8 /*uframes*/; + case USB_SPEED_SUPER: + /* Bus speed is 500000 bytes/ms, so use a little less */ + return 490000; + default: + /* error */ + return -1; + } + +} + +/* + * handle_control_request() - handles all control transfers + * @udc: pointer to vudc + * @urb: the urb request to handle + * @setup: pointer to the setup data for a USB device control + * request + * @status: pointer to request handling status + * + * Return 0 - if the request was handled + * 1 - if the request wasn't handles + * error code on error + * + * Adapted from drivers/usb/gadget/udc/dummy_hcd.c + */ +static int handle_control_request(struct vudc *udc, struct urb *urb, + struct usb_ctrlrequest *setup, + int *status) +{ + struct vep *ep2; + int ret_val = 1; + unsigned w_index; + unsigned w_value; + + w_index = le16_to_cpu(setup->wIndex); + w_value = le16_to_cpu(setup->wValue); + switch (setup->bRequest) { + case USB_REQ_SET_ADDRESS: + if (setup->bRequestType != DEV_REQUEST) + break; + udc->address = w_value; + ret_val = 0; + *status = 0; + break; + case USB_REQ_SET_FEATURE: + if (setup->bRequestType == DEV_REQUEST) { + ret_val = 0; + switch (w_value) { + case USB_DEVICE_REMOTE_WAKEUP: + break; + case USB_DEVICE_B_HNP_ENABLE: + udc->gadget.b_hnp_enable = 1; + break; + case USB_DEVICE_A_HNP_SUPPORT: + udc->gadget.a_hnp_support = 1; + break; + case USB_DEVICE_A_ALT_HNP_SUPPORT: + udc->gadget.a_alt_hnp_support = 1; + break; + default: + ret_val = -EOPNOTSUPP; + } + if (ret_val == 0) { + udc->devstatus |= (1 << w_value); + *status = 0; + } + } else if (setup->bRequestType == EP_REQUEST) { + /* endpoint halt */ + ep2 = vudc_find_endpoint(udc, w_index); + if (!ep2 || ep2->ep.name == udc->ep[0].ep.name) { + ret_val = -EOPNOTSUPP; + break; + } + ep2->halted = 1; + ret_val = 0; + *status = 0; + } + break; + case USB_REQ_CLEAR_FEATURE: + if (setup->bRequestType == DEV_REQUEST) { + ret_val = 0; + switch (w_value) { + case USB_DEVICE_REMOTE_WAKEUP: + w_value = USB_DEVICE_REMOTE_WAKEUP; + break; + + case USB_DEVICE_U1_ENABLE: + case USB_DEVICE_U2_ENABLE: + case USB_DEVICE_LTM_ENABLE: + ret_val = -EOPNOTSUPP; + break; + default: + ret_val = -EOPNOTSUPP; + break; + } + if (ret_val == 0) { + udc->devstatus &= ~(1 << w_value); + *status = 0; + } + } else if (setup->bRequestType == EP_REQUEST) { + /* endpoint halt */ + ep2 = vudc_find_endpoint(udc, w_index); + if (!ep2) { + ret_val = -EOPNOTSUPP; + break; + } + if (!ep2->wedged) + ep2->halted = 0; + ret_val = 0; + *status = 0; + } + break; + case USB_REQ_GET_STATUS: + if (setup->bRequestType == DEV_INREQUEST + || setup->bRequestType == INTF_INREQUEST + || setup->bRequestType == EP_INREQUEST) { + char *buf; + /* + * device: remote wakeup, selfpowered + * interface: nothing + * endpoint: halt + */ + buf = (char *)urb->transfer_buffer; + if (urb->transfer_buffer_length > 0) { + if (setup->bRequestType == EP_INREQUEST) { + ep2 = vudc_find_endpoint(udc, w_index); + if (!ep2) { + ret_val = -EOPNOTSUPP; + break; + } + buf[0] = ep2->halted; + } else if (setup->bRequestType == + DEV_INREQUEST) { + buf[0] = (u8)udc->devstatus; + } else + buf[0] = 0; + } + if (urb->transfer_buffer_length > 1) + buf[1] = 0; + urb->actual_length = min_t(u32, 2, + urb->transfer_buffer_length); + ret_val = 0; + *status = 0; + } + break; + } + return ret_val; +} + +/* Adapted from dummy_hcd.c ; caller must hold lock */ +static int transfer(struct vudc *udc, + struct urb *urb, struct vep *ep, int limit) +{ + struct vrequest *req; + int sent = 0; +top: + /* if there's no request queued, the device is NAKing; return */ + list_for_each_entry(req, &ep->req_queue, req_entry) { + unsigned host_len, dev_len, len; + void *ubuf_pos, *rbuf_pos; + int is_short, to_host; + int rescan = 0; + + /* + * 1..N packets of ep->ep.maxpacket each ... the last one + * may be short (including zero length). + * + * writer can send a zlp explicitly (length 0) or implicitly + * (length mod maxpacket zero, and 'zero' flag); they always + * terminate reads. + */ + host_len = urb->transfer_buffer_length - urb->actual_length; + dev_len = req->req.length - req->req.actual; + len = min(host_len, dev_len); + + to_host = usb_pipein(urb->pipe); + if (unlikely(len == 0)) + is_short = 1; + else { + /* send multiple of maxpacket first, then remainder */ + if (len >= ep->ep.maxpacket) { + is_short = 0; + if (len % ep->ep.maxpacket > 0) + rescan = 1; + len -= len % ep->ep.maxpacket; + } else { + is_short = 1; + } + + ubuf_pos = urb->transfer_buffer + urb->actual_length; + rbuf_pos = req->req.buf + req->req.actual; + + if (urb->pipe & USB_DIR_IN) + memcpy(ubuf_pos, rbuf_pos, len); + else + memcpy(rbuf_pos, ubuf_pos, len); + + urb->actual_length += len; + req->req.actual += len; + sent += len; + } + + /* + * short packets terminate, maybe with overflow/underflow. + * it's only really an error to write too much. + * + * partially filling a buffer optionally blocks queue advances + * (so completion handlers can clean up the queue) but we don't + * need to emulate such data-in-flight. + */ + if (is_short) { + if (host_len == dev_len) { + req->req.status = 0; + urb->status = 0; + } else if (to_host) { + req->req.status = 0; + if (dev_len > host_len) + urb->status = -EOVERFLOW; + else + urb->status = 0; + } else { + urb->status = 0; + if (host_len > dev_len) + req->req.status = -EOVERFLOW; + else + req->req.status = 0; + } + + /* many requests terminate without a short packet */ + /* also check if we need to send zlp */ + } else { + if (req->req.length == req->req.actual) { + if (req->req.zero && to_host) + rescan = 1; + else + req->req.status = 0; + } + if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_flags & URB_ZERO_PACKET && + !to_host) + rescan = 1; + else + urb->status = 0; + } + } + + /* device side completion --> continuable */ + if (req->req.status != -EINPROGRESS) { + + list_del_init(&req->req_entry); + spin_unlock(&udc->lock); + usb_gadget_giveback_request(&ep->ep, &req->req); + spin_lock(&udc->lock); + + /* requests might have been unlinked... */ + rescan = 1; + } + + /* host side completion --> terminate */ + if (urb->status != -EINPROGRESS) + break; + + /* rescan to continue with any other queued i/o */ + if (rescan) + goto top; + } + return sent; +} + +static void v_timer(unsigned long _vudc) +{ + struct vudc *udc = (struct vudc *) _vudc; + struct transfer_timer *timer = &udc->tr_timer; + struct urbp *urb_p, *tmp; + unsigned long flags; + struct usb_ep *_ep; + struct vep *ep; + int ret = 0; + int total, limit; + + spin_lock_irqsave(&udc->lock, flags); + + total = get_frame_limit(udc->gadget.speed); + if (total < 0) { /* unknown speed, or not set yet */ + timer->state = VUDC_TR_IDLE; + spin_unlock_irqrestore(&udc->lock, flags); + return; + } + /* is it next frame now? */ + if (time_after(jiffies, timer->frame_start + msecs_to_jiffies(1))) { + timer->frame_limit = total; + /* FIXME: how to make it accurate? */ + timer->frame_start = jiffies; + } else { + total = timer->frame_limit; + } + + list_for_each_entry(_ep, &udc->gadget.ep_list, ep_list) { + ep = to_vep(_ep); + ep->already_seen = 0; + } + +restart: + list_for_each_entry_safe(urb_p, tmp, &udc->urb_queue, urb_entry) { + struct urb *urb = urb_p->urb; + + ep = urb_p->ep; + if (urb->unlinked) + goto return_urb; + if (timer->state != VUDC_TR_RUNNING) + continue; + + if (!ep) { + urb->status = -EPROTO; + goto return_urb; + } + + /* Used up bandwidth? */ + if (total <= 0 && ep->type == USB_ENDPOINT_XFER_BULK) + continue; + + if (ep->already_seen) + continue; + ep->already_seen = 1; + if (ep == &udc->ep[0] && urb_p->new) { + ep->setup_stage = 1; + urb_p->new = 0; + } + if (ep->halted && !ep->setup_stage) { + urb->status = -EPIPE; + goto return_urb; + } + + if (ep == &udc->ep[0] && ep->setup_stage) { + /* TODO - flush any stale requests */ + ep->setup_stage = 0; + ep->halted = 0; + + ret = handle_control_request(udc, urb, + (struct usb_ctrlrequest *) urb->setup_packet, + (&urb->status)); + if (ret > 0) { + spin_unlock(&udc->lock); + ret = udc->driver->setup(&udc->gadget, + (struct usb_ctrlrequest *) + urb->setup_packet); + spin_lock(&udc->lock); + } + if (ret >= 0) { + /* no delays (max 64kb data stage) */ + limit = 64 * 1024; + goto treat_control_like_bulk; + } else { + urb->status = -EPIPE; + urb->actual_length = 0; + goto return_urb; + } + } + + limit = total; + switch (ep->type) { + case USB_ENDPOINT_XFER_ISOC: + /* TODO: support */ + urb->status = -EXDEV; + break; + + case USB_ENDPOINT_XFER_INT: + /* + * TODO: figure out bandwidth guarantees + * for now, give unlimited bandwidth + */ + limit += urb->transfer_buffer_length; + /* fallthrough */ + default: +treat_control_like_bulk: + total -= transfer(udc, urb, ep, limit); + } + if (urb->status == -EINPROGRESS) + continue; + +return_urb: + if (ep) + ep->already_seen = ep->setup_stage = 0; + + spin_lock(&udc->lock_tx); + list_del(&urb_p->urb_entry); + if (!urb->unlinked) { + v_enqueue_ret_submit(udc, urb_p); + } else { + v_enqueue_ret_unlink(udc, urb_p->seqnum, + urb->unlinked); + free_urbp_and_urb(urb_p); + } + wake_up(&udc->tx_waitq); + spin_unlock(&udc->lock_tx); + + goto restart; + } + + /* TODO - also wait on empty usb_request queues? */ + if (list_empty(&udc->urb_queue)) + timer->state = VUDC_TR_IDLE; + else + mod_timer(&timer->timer, + timer->frame_start + msecs_to_jiffies(1)); + + spin_unlock_irqrestore(&udc->lock, flags); +} + +/* All timer functions are run with udc->lock held */ + +void v_init_timer(struct vudc *udc) +{ + struct transfer_timer *t = &udc->tr_timer; + + setup_timer(&t->timer, v_timer, (unsigned long) udc); + t->state = VUDC_TR_STOPPED; +} + +void v_start_timer(struct vudc *udc) +{ + struct transfer_timer *t = &udc->tr_timer; + + dev_dbg(&udc->pdev->dev, "timer start"); + switch (t->state) { + case VUDC_TR_RUNNING: + return; + case VUDC_TR_IDLE: + return v_kick_timer(udc, jiffies); + case VUDC_TR_STOPPED: + t->state = VUDC_TR_IDLE; + t->frame_start = jiffies; + t->frame_limit = get_frame_limit(udc->gadget.speed); + return v_kick_timer(udc, jiffies); + } +} + +void v_kick_timer(struct vudc *udc, unsigned long time) +{ + struct transfer_timer *t = &udc->tr_timer; + + dev_dbg(&udc->pdev->dev, "timer kick"); + switch (t->state) { + case VUDC_TR_RUNNING: + return; + case VUDC_TR_IDLE: + t->state = VUDC_TR_RUNNING; + /* fallthrough */ + case VUDC_TR_STOPPED: + /* we may want to kick timer to unqueue urbs */ + mod_timer(&t->timer, time); + } +} + +void v_stop_timer(struct vudc *udc) +{ + struct transfer_timer *t = &udc->tr_timer; + + /* timer itself will take care of stopping */ + dev_dbg(&udc->pdev->dev, "timer stop"); + t->state = VUDC_TR_STOPPED; +} diff --git a/drivers/usb/usbip/vudc_tx.c b/drivers/usb/usbip/vudc_tx.c new file mode 100644 index 000000000000..234661782fa0 --- /dev/null +++ b/drivers/usb/usbip/vudc_tx.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> + * Copyright (C) 2015-2016 Samsung Electronics + * Igor Kotrasinski <i.kotrasinsk@samsung.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. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <net/sock.h> +#include <linux/list.h> +#include <linux/kthread.h> + +#include "usbip_common.h" +#include "vudc.h" + +static inline void setup_base_pdu(struct usbip_header_basic *base, + __u32 command, __u32 seqnum) +{ + base->command = command; + base->seqnum = seqnum; + base->devid = 0; + base->ep = 0; + base->direction = 0; +} + +static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urbp *urb_p) +{ + setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, urb_p->seqnum); + usbip_pack_pdu(rpdu, urb_p->urb, USBIP_RET_SUBMIT, 1); +} + +static void setup_ret_unlink_pdu(struct usbip_header *rpdu, + struct v_unlink *unlink) +{ + setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum); + rpdu->u.ret_unlink.status = unlink->status; +} + +static int v_send_ret_unlink(struct vudc *udc, struct v_unlink *unlink) +{ + struct msghdr msg; + struct kvec iov[1]; + size_t txsize; + + int ret; + struct usbip_header pdu_header; + + txsize = 0; + memset(&pdu_header, 0, sizeof(pdu_header)); + memset(&msg, 0, sizeof(msg)); + memset(&iov, 0, sizeof(iov)); + + /* 1. setup usbip_header */ + setup_ret_unlink_pdu(&pdu_header, unlink); + usbip_header_correct_endian(&pdu_header, 1); + + iov[0].iov_base = &pdu_header; + iov[0].iov_len = sizeof(pdu_header); + txsize += sizeof(pdu_header); + + ret = kernel_sendmsg(udc->ud.tcp_socket, &msg, iov, + 1, txsize); + if (ret != txsize) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); + if (ret >= 0) + return -EPIPE; + return ret; + } + kfree(unlink); + + return txsize; +} + +static int v_send_ret_submit(struct vudc *udc, struct urbp *urb_p) +{ + struct urb *urb = urb_p->urb; + struct usbip_header pdu_header; + struct usbip_iso_packet_descriptor *iso_buffer = NULL; + struct kvec *iov = NULL; + int iovnum = 0; + int ret = 0; + size_t txsize; + struct msghdr msg; + + txsize = 0; + memset(&pdu_header, 0, sizeof(pdu_header)); + memset(&msg, 0, sizeof(msg)); + + if (urb_p->type == USB_ENDPOINT_XFER_ISOC) + iovnum = 2 + urb->number_of_packets; + else + iovnum = 2; + + iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL); + if (!iov) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); + ret = -ENOMEM; + goto out; + } + iovnum = 0; + + /* 1. setup usbip_header */ + setup_ret_submit_pdu(&pdu_header, urb_p); + usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", + pdu_header.base.seqnum, urb); + usbip_header_correct_endian(&pdu_header, 1); + + iov[iovnum].iov_base = &pdu_header; + iov[iovnum].iov_len = sizeof(pdu_header); + iovnum++; + txsize += sizeof(pdu_header); + + /* 2. setup transfer buffer */ + if (urb_p->type != USB_ENDPOINT_XFER_ISOC && + usb_pipein(urb->pipe) && urb->actual_length > 0) { + iov[iovnum].iov_base = urb->transfer_buffer; + iov[iovnum].iov_len = urb->actual_length; + iovnum++; + txsize += urb->actual_length; + } else if (urb_p->type == USB_ENDPOINT_XFER_ISOC && + usb_pipein(urb->pipe)) { + /* FIXME - copypasted from stub_tx, refactor */ + int i; + + for (i = 0; i < urb->number_of_packets; i++) { + iov[iovnum].iov_base = urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + iov[iovnum].iov_len = + urb->iso_frame_desc[i].actual_length; + iovnum++; + txsize += urb->iso_frame_desc[i].actual_length; + } + + if (txsize != sizeof(pdu_header) + urb->actual_length) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); + ret = -EPIPE; + goto out; + } + } + /* else - no buffer to send */ + + /* 3. setup iso_packet_descriptor */ + if (urb_p->type == USB_ENDPOINT_XFER_ISOC) { + ssize_t len = 0; + + iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len); + if (!iso_buffer) { + usbip_event_add(&udc->ud, + VUDC_EVENT_ERROR_MALLOC); + ret = -ENOMEM; + goto out; + } + + iov[iovnum].iov_base = iso_buffer; + iov[iovnum].iov_len = len; + txsize += len; + iovnum++; + } + + ret = kernel_sendmsg(udc->ud.tcp_socket, &msg, + iov, iovnum, txsize); + if (ret != txsize) { + usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); + if (ret >= 0) + ret = -EPIPE; + goto out; + } + +out: + kfree(iov); + kfree(iso_buffer); + free_urbp_and_urb(urb_p); + if (ret < 0) + return ret; + return txsize; +} + +static int v_send_ret(struct vudc *udc) +{ + unsigned long flags; + struct tx_item *txi; + size_t total_size = 0; + int ret = 0; + + spin_lock_irqsave(&udc->lock_tx, flags); + while (!list_empty(&udc->tx_queue)) { + txi = list_first_entry(&udc->tx_queue, struct tx_item, + tx_entry); + list_del(&txi->tx_entry); + spin_unlock_irqrestore(&udc->lock_tx, flags); + + switch (txi->type) { + case TX_SUBMIT: + ret = v_send_ret_submit(udc, txi->s); + break; + case TX_UNLINK: + ret = v_send_ret_unlink(udc, txi->u); + break; + } + kfree(txi); + + if (ret < 0) + return ret; + + total_size += ret; + + spin_lock_irqsave(&udc->lock_tx, flags); + } + + spin_unlock_irqrestore(&udc->lock_tx, flags); + return total_size; +} + + +int v_tx_loop(void *data) +{ + struct usbip_device *ud = (struct usbip_device *) data; + struct vudc *udc = container_of(ud, struct vudc, ud); + int ret; + + while (!kthread_should_stop()) { + if (usbip_event_happened(&udc->ud)) + break; + ret = v_send_ret(udc); + if (ret < 0) { + pr_warn("v_tx exit with error %d", ret); + break; + } + wait_event_interruptible(udc->tx_waitq, + (!list_empty(&udc->tx_queue) || + kthread_should_stop())); + } + + return 0; +} + +/* called with spinlocks held */ +void v_enqueue_ret_unlink(struct vudc *udc, __u32 seqnum, __u32 status) +{ + struct tx_item *txi; + struct v_unlink *unlink; + + txi = kzalloc(sizeof(*txi), GFP_ATOMIC); + if (!txi) { + usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); + return; + } + unlink = kzalloc(sizeof(*unlink), GFP_ATOMIC); + if (!unlink) { + kfree(txi); + usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); + return; + } + + unlink->seqnum = seqnum; + unlink->status = status; + txi->type = TX_UNLINK; + txi->u = unlink; + + list_add_tail(&txi->tx_entry, &udc->tx_queue); +} + +/* called with spinlocks held */ +void v_enqueue_ret_submit(struct vudc *udc, struct urbp *urb_p) +{ + struct tx_item *txi; + + txi = kzalloc(sizeof(*txi), GFP_ATOMIC); + if (!txi) { + usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); + return; + } + + txi->type = TX_SUBMIT; + txi->s = urb_p; + + list_add_tail(&txi->tx_entry, &udc->tx_queue); +} diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 8ed8e34c3492..33acd1599e99 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -54,7 +54,7 @@ #include <linux/usb/wusb.h> #include <linux/scatterlist.h> -static int debug_crypto_verify = 0; +static int debug_crypto_verify; module_param(debug_crypto_verify, int, 0); MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms"); @@ -390,7 +390,7 @@ static int wusb_oob_mic_verify(void) 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }, .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c, - 0x14, 0x7b } , + 0x14, 0x7b }, }; size_t hs_size; @@ -480,7 +480,7 @@ static int wusb_key_derive_verify(void) printk(KERN_ERR "E: keydvt in: key\n"); wusb_key_dump(stv_key_a1, sizeof(stv_key_a1)); printk(KERN_ERR "E: keydvt in: nonce\n"); - wusb_key_dump( &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); + wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n"); wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); printk(KERN_ERR "E: keydvt out: KCK\n"); diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 3f4f5fbded55..bf9551735938 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -893,7 +893,6 @@ out: error_nodev: return; - wusb_dev_sysfs_rm(wusb_dev); error_add_sysfs: wusb_dev_bos_rm(wusb_dev); error_bos_add: |