diff options
Diffstat (limited to 'drivers')
39 files changed, 964 insertions, 363 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 0a866e9..18b281d 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1168,13 +1168,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, } instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->rcv_urb) { - usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n"); ret = -ENOMEM; goto fail; } instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->snd_urb) { - usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n"); ret = -ENOMEM; goto fail; } diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4333dc5..f198291 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2203,10 +2203,8 @@ static int uea_boot(struct uea_softc *sc) } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); - if (!sc->urb_int) { - uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); + if (!sc->urb_int) goto err1; - } usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index db322d9..5e4f46c 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1141,7 +1141,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, urb = usb_alloc_urb(iso_packets, GFP_KERNEL); if (!urb) { - dev_err(dev, "%s: no memory for urb %d!\n", __func__, i); error = -ENOMEM; goto fail_unbind; } diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 337948c..bf4bb58 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -58,6 +58,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_SUSPENDING 8 #define WDM_RESETTING 9 #define WDM_OVERFLOW 10 +#define WDM_DRAIN_ON_OPEN 11 #define WDM_MAX 16 @@ -154,6 +155,9 @@ static void wdm_out_callback(struct urb *urb) wake_up(&desc->wait); } +/* forward declaration */ +static int service_outstanding_interrupt(struct wdm_device *desc); + static void wdm_in_callback(struct urb *urb) { struct wdm_device *desc = urb->context; @@ -178,7 +182,7 @@ static void wdm_in_callback(struct urb *urb) "nonzero urb status received: -ESHUTDOWN"); goto skip_error; case -EPIPE: - dev_err(&desc->intf->dev, + dev_dbg(&desc->intf->dev, "nonzero urb status received: -EPIPE\n"); break; default: @@ -188,7 +192,13 @@ static void wdm_in_callback(struct urb *urb) } } - desc->rerr = status; + /* + * only set a new error if there is no previous error. + * Errors are only cleared during read/open + */ + if (desc->rerr == 0) + desc->rerr = status; + if (length + desc->length > desc->wMaxCommand) { /* The buffer would overflow */ set_bit(WDM_OVERFLOW, &desc->flags); @@ -200,10 +210,40 @@ static void wdm_in_callback(struct urb *urb) desc->reslength = length; } } + + /* + * Handling devices with the WDM_DRAIN_ON_OPEN flag set: + * If desc->resp_count is unset, then the urb was submitted + * without a prior notification. If the device returned any + * data, then this implies that it had messages queued without + * notifying us. Continue reading until that queue is flushed. + */ + if (!desc->resp_count) { + if (!length) { + /* do not propagate the expected -EPIPE */ + desc->rerr = 0; + goto unlock; + } + dev_dbg(&desc->intf->dev, "got %d bytes without notification\n", length); + set_bit(WDM_RESPONDING, &desc->flags); + usb_submit_urb(desc->response, GFP_ATOMIC); + } + skip_error: + set_bit(WDM_READ, &desc->flags); wake_up(&desc->wait); - set_bit(WDM_READ, &desc->flags); + if (desc->rerr) { + /* + * Since there was an error, userspace may decide to not read + * any data after poll'ing. + * We should respond to further attempts from the device to send + * data, so that we can get unstuck. + */ + service_outstanding_interrupt(desc); + } + +unlock: spin_unlock(&desc->iuspin); } @@ -274,8 +314,7 @@ static void wdm_int_callback(struct urb *urb) && !test_bit(WDM_DISCONNECTING, &desc->flags) && !test_bit(WDM_SUSPENDING, &desc->flags)) { rv = usb_submit_urb(desc->response, GFP_ATOMIC); - dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", - __func__, rv); + dev_dbg(&desc->intf->dev, "submit response URB %d", rv); } spin_unlock(&desc->iuspin); if (rv < 0) { @@ -436,17 +475,14 @@ out_free_mem: } /* - * clear WDM_READ flag and possibly submit the read urb if resp_count - * is non-zero. + * Submit the read urb if resp_count is non-zero. * * Called with desc->iuspin locked */ -static int clear_wdm_read_flag(struct wdm_device *desc) +static int service_outstanding_interrupt(struct wdm_device *desc) { int rv = 0; - clear_bit(WDM_READ, &desc->flags); - /* submit read urb only if the device is waiting for it */ if (!desc->resp_count || !--desc->resp_count) goto out; @@ -537,8 +573,9 @@ retry: } if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); - rv = clear_wdm_read_flag(desc); + dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ"); + clear_bit(WDM_READ, &desc->flags); + rv = service_outstanding_interrupt(desc); spin_unlock_irq(&desc->iuspin); if (rv < 0) goto err; @@ -563,8 +600,10 @@ retry: desc->length -= cntr; /* in case we had outstanding data */ - if (!desc->length) - clear_wdm_read_flag(desc); + if (!desc->length) { + clear_bit(WDM_READ, &desc->flags); + service_outstanding_interrupt(desc); + } spin_unlock_irq(&desc->iuspin); rv = cntr; @@ -647,6 +686,17 @@ static int wdm_open(struct inode *inode, struct file *file) dev_err(&desc->intf->dev, "Error submitting int urb - %d\n", rv); rv = usb_translate_errors(rv); + } else if (test_bit(WDM_DRAIN_ON_OPEN, &desc->flags)) { + /* + * Some devices keep pending messages queued + * without resending notifications. We must + * flush the message queue before we can + * assume a one-to-one relationship between + * notifications and messages in the queue + */ + dev_dbg(&desc->intf->dev, "draining queued data\n"); + set_bit(WDM_RESPONDING, &desc->flags); + rv = usb_submit_urb(desc->response, GFP_KERNEL); } } else { rv = 0; @@ -753,7 +803,8 @@ static void wdm_rxwork(struct work_struct *work) /* --- hotplug --- */ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, - u16 bufsize, int (*manage_power)(struct usb_interface *, int)) + u16 bufsize, int (*manage_power)(struct usb_interface *, int), + bool drain_on_open) { int rv = -ENOMEM; struct wdm_device *desc; @@ -840,6 +891,68 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor desc->manage_power = manage_power; + /* + * "drain_on_open" enables a hack to work around a firmware + * issue observed on network functions, in particular MBIM + * functions. + * + * Quoting section 7 of the CDC-WMC r1.1 specification: + * + * "The firmware shall interpret GetEncapsulatedResponse as a + * request to read response bytes. The firmware shall send + * the next wLength bytes from the response. The firmware + * shall allow the host to retrieve data using any number of + * GetEncapsulatedResponse requests. The firmware shall + * return a zero- length reply if there are no data bytes + * available. + * + * The firmware shall send ResponseAvailable notifications + * periodically, using any appropriate algorithm, to inform + * the host that there is data available in the reply + * buffer. The firmware is allowed to send ResponseAvailable + * notifications even if there is no data available, but + * this will obviously reduce overall performance." + * + * These requirements, although they make equally sense, are + * often not implemented by network functions. Some firmwares + * will queue data indefinitely, without ever resending a + * notification. The result is that the driver and firmware + * loses "syncronization" if the driver ever fails to respond + * to a single notification, something which easily can happen + * on release(). When this happens, the driver will appear to + * never receive notifications for the most current data. Each + * notification will only cause a single read, which returns + * the oldest data in the firmware's queue. + * + * The "drain_on_open" hack resolves the situation by draining + * data from the firmware until none is returned, without a + * prior notification. + * + * This will inevitably race with the firmware, risking that + * we read data from the device before handling the associated + * notification. To make things worse, some of the devices + * needing the hack do not implement the "return zero if no + * data is available" requirement either. Instead they return + * an error on the subsequent read in this case. This means + * that "winning" the race can cause an unexpected EIO to + * userspace. + * + * "winning" the race is more likely on resume() than on + * open(), and the unexpected error is more harmful in the + * middle of an open session. The hack is therefore only + * applied on open(), and not on resume() where it logically + * would be equally necessary. So we define open() as the only + * driver <-> device "syncronization point". Should we happen + * to lose a notification after open(), then syncronization + * will be lost until release() + * + * The hack should not be enabled for CDC WDM devices + * conforming to the CDC-WMC r1.1 specification. This is + * ensured by setting drain_on_open to false in wdm_probe(). + */ + if (drain_on_open) + set_bit(WDM_DRAIN_ON_OPEN, &desc->flags); + spin_lock(&wdm_device_list_lock); list_add(&desc->device_list, &wdm_device_list); spin_unlock(&wdm_device_list_lock); @@ -893,7 +1006,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) goto err; ep = &iface->endpoint[0].desc; - rv = wdm_create(intf, ep, maxcom, &wdm_manage_power); + rv = wdm_create(intf, ep, maxcom, &wdm_manage_power, false); err: return rv; @@ -925,7 +1038,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf, { int rv = -EINVAL; - rv = wdm_create(intf, ep, bufsize, manage_power); + rv = wdm_create(intf, ep, bufsize, manage_power, true); if (rv < 0) goto err; @@ -967,7 +1080,7 @@ static void wdm_disconnect(struct usb_interface *intf) if (!desc->count) cleanup(desc); else - dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count); + dev_dbg(&intf->dev, "%d open files - postponing cleanup\n", desc->count); mutex_unlock(&wdm_mutex); } diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 917a55c..22c235a 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1467,10 +1467,8 @@ static int usbtmc_probe(struct usb_interface *intf, if (data->iin_ep_present) { /* allocate int urb */ data->iin_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!data->iin_urb) { - dev_err(&intf->dev, "Failed to allocate int urb\n"); + if (!data->iin_urb) goto error_register; - } /* will reference data in int urb */ kref_get(&data->kref); diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 01c0c04..e04a34e 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -127,16 +127,17 @@ static struct device_type ulpi_dev_type = { * * Registers a driver with the ULPI bus. */ -int ulpi_register_driver(struct ulpi_driver *drv) +int __ulpi_register_driver(struct ulpi_driver *drv, struct module *module) { if (!drv->probe) return -EINVAL; + drv->driver.owner = module; drv->driver.bus = &ulpi_bus; return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(ulpi_register_driver); +EXPORT_SYMBOL_GPL(__ulpi_register_driver); /** * ulpi_unregister_driver - unregister a driver with the ULPI bus diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index dd28010..253aac7 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -85,7 +85,6 @@ config USB_OTG_FSM config USB_ULPI_BUS tristate "USB ULPI PHY interface support" - depends on USB_SUPPORT help UTMI+ Low Pin Interface (ULPI) is specification for a commonly used USB 2.0 PHY interface. The ULPI specification defines a standard set diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 9780877..da36b78 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -5,8 +5,9 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o of.o +usbcore-y += port.o +usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 2289700..3de4f88 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -18,6 +18,7 @@ */ #include <linux/of.h> +#include <linux/usb/of.h> /** * usb_of_get_child_node - Find the device node match port number diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2df3d04..df5a065 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5040,7 +5040,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) /* Create new workqueue and init work */ retval = -ENOMEM; - hsotg->wq_otg = create_singlethread_workqueue("dwc2"); + hsotg->wq_otg = alloc_ordered_workqueue("dwc2", 0); if (!hsotg->wq_otg) { dev_err(hsotg->dev, "Failed to create workqueue\n"); goto error2; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index a64ce1c..b97cde7 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,7 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA - select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD + select USB_XHCI_PLATFORM if USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 172ef17..e0761d9 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/of_platform.h> #include <linux/usb/ehci_pdriver.h> #include <linux/usb/ohci_pdriver.h> @@ -34,6 +35,9 @@ MODULE_AUTHOR("Hauke Mehrtens"); MODULE_DESCRIPTION("Common USB driver for BCMA Bus"); MODULE_LICENSE("GPL"); +/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */ +#define USB_BCMA_CLKCTLST_USB_CLK_REQ 0x00000100 + struct bcma_hcd_device { struct bcma_device *core; struct platform_device *ehci_dev; @@ -165,6 +169,76 @@ static void bcma_hcd_init_chip_mips(struct bcma_device *dev) } } +/** + * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM + * + * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced + * long before Northstar devices. It seems some cheaper chipsets like BCM53573 + * still use it. + * Initialization of this old core differs between MIPS and ARM. + */ +static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev) +{ + struct bcma_device *core = usb_dev->core; + struct device *dev = &core->dev; + struct bcma_device *pmu_core; + + usleep_range(10000, 20000); + if (core->id.rev < 5) + return 0; + + pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU); + if (!pmu_core) { + dev_err(dev, "Could not find PMU core\n"); + return -ENOENT; + } + + /* Take USB core out of reset */ + bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_RESET_CTL, 0); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK); + usleep_range(100, 200); + + /* Enable Misc PLL */ + bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT | + BCMA_CLKCTLST_HQCLKREQ | + USB_BCMA_CLKCTLST_USB_CLK_REQ); + usleep_range(100, 200); + + bcma_write32(core, 0x510, 0xc7f85000); + bcma_write32(core, 0x510, 0xc7f85003); + usleep_range(300, 600); + + /* Program USB PHY PLL parameters */ + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1); + usleep_range(100, 200); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0); + usleep_range(100, 200); + bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD); + usleep_range(100, 200); + + bcma_write32(core, 0x510, 0x7f8d007); + udelay(1000); + + /* Take controller out of reset */ + bcma_write32(core, 0x200, 0x4ff); + usleep_range(25, 50); + bcma_write32(core, 0x200, 0x6ff); + usleep_range(25, 50); + bcma_write32(core, 0x200, 0x7ff); + usleep_range(25, 50); + + of_platform_default_populate(dev->of_node, NULL, dev); + + return 0; +} + static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev) { struct bcma_device *arm_core; @@ -338,6 +412,18 @@ err_unregister_ohci_dev: return err; } +static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd) +{ + struct bcma_device *core = bcma_hcd->core; + struct device *dev = &core->dev; + + bcma_core_enable(core, 0); + + of_platform_default_populate(dev->of_node, NULL, dev); + + return 0; +} + static int bcma_hcd_probe(struct bcma_device *core) { int err; @@ -357,14 +443,24 @@ static int bcma_hcd_probe(struct bcma_device *core) switch (core->id.id) { case BCMA_CORE_USB20_HOST: + if (IS_ENABLED(CONFIG_ARM)) + err = bcma_hcd_usb20_old_arm_init(usb_dev); + else if (IS_ENABLED(CONFIG_MIPS)) + err = bcma_hcd_usb20_init(usb_dev); + else + err = -ENOTSUPP; + break; case BCMA_CORE_NS_USB20: err = bcma_hcd_usb20_init(usb_dev); - if (err) - return err; + break; + case BCMA_CORE_NS_USB30: + err = bcma_hcd_usb30_init(usb_dev); break; default: return -ENODEV; } + if (err) + return err; bcma_set_drvdata(core, usb_dev); return 0; @@ -416,6 +512,7 @@ static int bcma_hcd_resume(struct bcma_device *dev) static const struct bcma_device_id bcma_hcd_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, }; MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 6816b8c..876dca4 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -38,7 +38,7 @@ #include "ehci.h" #define DRIVER_DESC "EHCI generic platform driver" -#define EHCI_MAX_CLKS 3 +#define EHCI_MAX_CLKS 4 #define EHCI_MAX_RSTS 3 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 1044b0f..f07ccb2 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -222,23 +222,17 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->controller_ver = usb_get_ver_info(np); /* Activate Erratum by reading property in device tree */ - if (of_get_property(np, "fsl,usb-erratum-a007792", NULL)) - pdata->has_fsl_erratum_a007792 = 1; - else - pdata->has_fsl_erratum_a007792 = 0; - if (of_get_property(np, "fsl,usb-erratum-a005275", NULL)) - pdata->has_fsl_erratum_a005275 = 1; - else - pdata->has_fsl_erratum_a005275 = 0; + pdata->has_fsl_erratum_a007792 = + of_property_read_bool(np, "fsl,usb-erratum-a007792"); + pdata->has_fsl_erratum_a005275 = + of_property_read_bool(np, "fsl,usb-erratum-a005275"); /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree */ - if (of_get_property(np, "phy-clk-valid", NULL)) - pdata->check_phy_clk_valid = 1; - else - pdata->check_phy_clk_valid = 0; + pdata->check_phy_clk_valid = + of_property_read_bool(np, "phy-clk-valid"); if (pdata->have_sysif_regs) { if (pdata->controller_ver == FSL_USB_VER_NONE) { diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c index e363723..ad8eb57 100644 --- a/drivers/usb/host/whci/init.c +++ b/drivers/usb/host/whci/init.c @@ -65,7 +65,7 @@ int whc_init(struct whc *whc) init_waitqueue_head(&whc->cmd_wq); init_waitqueue_head(&whc->async_list_wq); init_waitqueue_head(&whc->periodic_list_wq); - whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev)); + whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0); if (whc->workqueue == NULL) { ret = -ENOMEM; goto error; diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index eb8f8d3..47b3577 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -240,6 +240,12 @@ config USB_HSIC_USB3503 help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. +config USB_HSIC_USB4604 + tristate "USB4604 HSIC to USB20 Driver" + depends on I2C + help + This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver. + config USB_LINK_LAYER_TEST tristate "USB Link Layer Test driver" help diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 3d79faa..3d19927 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o +obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_UCSI) += ucsi.o diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 3071c0e..c34a0b6 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -744,20 +744,16 @@ static int adu_probe(struct usb_interface *interface, memset(dev->interrupt_in_buffer, 'i', in_end_size); dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number, sizeof(dev->serial_number))) { diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a0a3827..29569ec 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -85,7 +85,6 @@ struct appledisplay { }; static atomic_t count_displays = ATOMIC_INIT(0); -static struct workqueue_struct *wq; static void appledisplay_complete(struct urb *urb) { @@ -122,7 +121,7 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - queue_delayed_work(wq, &pdata->work, 0); + schedule_delayed_work(&pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -262,7 +261,6 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->urb = usb_alloc_urb(0, GFP_KERNEL); if (!pdata->urb) { retval = -ENOMEM; - dev_err(&iface->dev, "Allocating URB failed\n"); goto error; } @@ -344,7 +342,7 @@ static void appledisplay_disconnect(struct usb_interface *iface) if (pdata) { usb_kill_urb(pdata->urb); - cancel_delayed_work(&pdata->work); + cancel_delayed_work_sync(&pdata->work); backlight_device_unregister(pdata->bd); usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, pdata->urbdata, pdata->urb->transfer_dma); @@ -365,19 +363,11 @@ static struct usb_driver appledisplay_driver = { static int __init appledisplay_init(void) { - wq = create_singlethread_workqueue("appledisplay"); - if (!wq) { - printk(KERN_ERR "appledisplay: Could not create work queue\n"); - return -ENOMEM; - } - return usb_register(&appledisplay_driver); } static void __exit appledisplay_exit(void) { - flush_workqueue(wq); - destroy_workqueue(wq); usb_deregister(&appledisplay_driver); } diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 9b5b3b2..16765b3 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -61,9 +61,6 @@ module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent setup"); extern struct platform_driver u132_platform_driver; -static struct workqueue_struct *status_queue; -static struct workqueue_struct *command_queue; -static struct workqueue_struct *respond_queue; /* * ftdi_module_lock exists to protect access to global variables * @@ -228,56 +225,56 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) + if (!schedule_delayed_work(&ftdi->status_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) + if (schedule_delayed_work(&ftdi->status_work, delta)) kref_get(&ftdi->kref); } static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->status_work)) + if (cancel_delayed_work_sync(&ftdi->status_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) + if (!schedule_delayed_work(&ftdi->command_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) + if (schedule_delayed_work(&ftdi->command_work, delta)) kref_get(&ftdi->kref); } static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->command_work)) + if (cancel_delayed_work_sync(&ftdi->command_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + if (!schedule_delayed_work(&ftdi->respond_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + if (schedule_delayed_work(&ftdi->respond_work, delta)) kref_get(&ftdi->kref); } static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->respond_work)) + if (cancel_delayed_work_sync(&ftdi->respond_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } @@ -785,11 +782,8 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) return 0; total_size = ftdi_elan_total_command_size(ftdi, command_size); urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { @@ -1948,10 +1942,8 @@ static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) int I = 257; int i = 0; urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequence\n"); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); @@ -1988,10 +1980,8 @@ static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) int I = 4; int i = 0; urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb for the reset sequence\n"); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); @@ -2823,9 +2813,6 @@ static void ftdi_elan_disconnect(struct usb_interface *interface) ftdi->initialized = 0; ftdi->registered = 0; } - flush_workqueue(status_queue); - flush_workqueue(command_queue); - flush_workqueue(respond_queue); ftdi->disconnected += 1; usb_set_intfdata(interface, NULL); dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); @@ -2845,31 +2832,12 @@ static int __init ftdi_elan_init(void) pr_info("driver %s\n", ftdi_elan_driver.name); mutex_init(&ftdi_module_lock); INIT_LIST_HEAD(&ftdi_static_list); - status_queue = create_singlethread_workqueue("ftdi-status-control"); - if (!status_queue) - goto err_status_queue; - command_queue = create_singlethread_workqueue("ftdi-command-engine"); - if (!command_queue) - goto err_command_queue; - respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); - if (!respond_queue) - goto err_respond_queue; result = usb_register(&ftdi_elan_driver); if (result) { - destroy_workqueue(status_queue); - destroy_workqueue(command_queue); - destroy_workqueue(respond_queue); pr_err("usb_register failed. Error number %d\n", result); } return result; -err_respond_queue: - destroy_workqueue(command_queue); -err_command_queue: - destroy_workqueue(status_queue); -err_status_queue: - pr_err("%s couldn't create workqueue\n", ftdi_elan_driver.name); - return -ENOMEM; } static void __exit ftdi_elan_exit(void) @@ -2882,15 +2850,7 @@ static void __exit ftdi_elan_exit(void) ftdi_status_cancel_work(ftdi); ftdi_command_cancel_work(ftdi); ftdi_response_cancel_work(ftdi); - } flush_workqueue(status_queue); - destroy_workqueue(status_queue); - status_queue = NULL; - flush_workqueue(command_queue); - destroy_workqueue(command_queue); - command_queue = NULL; - flush_workqueue(respond_queue); - destroy_workqueue(respond_queue); - respond_queue = NULL; + } } diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 1950e87..7defa34 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -413,8 +413,6 @@ static ssize_t iowarrior_write(struct file *file, int_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!int_out_urb) { retval = -ENOMEM; - dev_dbg(&dev->interface->dev, - "Unable to allocate urb\n"); goto error_no_urb; } buf = usb_alloc_coherent(dev->udev, dev->report_size, @@ -812,10 +810,8 @@ static int iowarrior_probe(struct usb_interface *interface, /* create the urb and buffer for reading */ dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->int_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->int_in_urb) goto error; - } dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); if (!dev->int_in_buffer) { dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index cce22ff..8489079 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -714,10 +714,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) : udev->descriptor.bMaxPacketSize0; dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); @@ -726,10 +724,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; if (dev->interrupt_out_endpoint) dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 7771be3..52b41fb 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -881,20 +881,16 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(idev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(idev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(idev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 86b4e4b..9c49334 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -34,8 +34,6 @@ struct lvs_rh { struct usb_hub_descriptor descriptor; /* urb for polling interrupt pipe */ struct urb *urb; - /* LVS RH work queue */ - struct workqueue_struct *rh_queue; /* LVH RH work */ struct work_struct rh_work; /* RH port status */ @@ -355,7 +353,7 @@ static void lvs_rh_irq(struct urb *urb) { struct lvs_rh *lvs = urb->context; - queue_work(lvs->rh_queue, &lvs->rh_work); + schedule_work(&lvs->rh_work); } static int lvs_rh_probe(struct usb_interface *intf, @@ -397,24 +395,15 @@ static int lvs_rh_probe(struct usb_interface *intf, /* submit urb to poll interrupt endpoint */ lvs->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!lvs->urb) { - dev_err(&intf->dev, "couldn't allocate lvs urb\n"); + if (!lvs->urb) return -ENOMEM; - } - - lvs->rh_queue = create_singlethread_workqueue("lvs_rh_queue"); - if (!lvs->rh_queue) { - dev_err(&intf->dev, "couldn't create workqueue\n"); - ret = -ENOMEM; - goto free_urb; - } INIT_WORK(&lvs->rh_work, lvs_rh_work); ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group); if (ret < 0) { dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret); - goto destroy_queue; + goto free_urb; } pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); @@ -432,8 +421,6 @@ static int lvs_rh_probe(struct usb_interface *intf, sysfs_remove: sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); -destroy_queue: - destroy_workqueue(lvs->rh_queue); free_urb: usb_free_urb(lvs->urb); return ret; @@ -444,7 +431,7 @@ static void lvs_rh_disconnect(struct usb_interface *intf) struct lvs_rh *lvs = usb_get_intfdata(intf); sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); - destroy_workqueue(lvs->rh_queue); + flush_work(&lvs->rh_work); usb_free_urb(lvs->urb); } diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 02abfcd..05bd39d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3084,7 +3084,6 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL); if (!sisusb->sisurbin) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3093,8 +3092,6 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL); if (!sisusb->sisurbout[i]) { - dev_err(&sisusb->sisusb_dev->dev, - "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } diff --git a/drivers/usb/misc/usb4604.c b/drivers/usb/misc/usb4604.c new file mode 100644 index 0000000..e9f37fb --- /dev/null +++ b/drivers/usb/misc/usb4604.c @@ -0,0 +1,175 @@ +/* + * Driver for SMSC USB4604 USB HSIC 4-port 2.0 hub controller driver + * Based on usb3503 driver + * + * Copyright (c) 2012-2013 Dongjin Kim (tobetter@gmail.com) + * Copyright (c) 2016 Linaro Ltd. + * + * 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. + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/gpio/consumer.h> + +enum usb4604_mode { + USB4604_MODE_UNKNOWN, + USB4604_MODE_HUB, + USB4604_MODE_STANDBY, +}; + +struct usb4604 { + enum usb4604_mode mode; + struct device *dev; + struct gpio_desc *gpio_reset; +}; + +static void usb4604_reset(struct usb4604 *hub, int state) +{ + gpiod_set_value_cansleep(hub->gpio_reset, state); + + /* Wait for i2c logic to come up */ + if (state) + msleep(250); +} + +static int usb4604_connect(struct usb4604 *hub) +{ + struct device *dev = hub->dev; + struct i2c_client *client = to_i2c_client(dev); + int err; + u8 connect_cmd[] = { 0xaa, 0x55, 0x00 }; + + usb4604_reset(hub, 1); + + err = i2c_master_send(client, connect_cmd, ARRAY_SIZE(connect_cmd)); + if (err < 0) { + usb4604_reset(hub, 0); + return err; + } + + hub->mode = USB4604_MODE_HUB; + dev_dbg(dev, "switched to HUB mode\n"); + + return 0; +} + +static int usb4604_switch_mode(struct usb4604 *hub, enum usb4604_mode mode) +{ + struct device *dev = hub->dev; + int err = 0; + + switch (mode) { + case USB4604_MODE_HUB: + err = usb4604_connect(hub); + break; + + case USB4604_MODE_STANDBY: + usb4604_reset(hub, 0); + dev_dbg(dev, "switched to STANDBY mode\n"); + break; + + default: + dev_err(dev, "unknown mode is requested\n"); + err = -EINVAL; + break; + } + + return err; +} + +static int usb4604_probe(struct usb4604 *hub) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + struct gpio_desc *gpio; + u32 mode = USB4604_MODE_HUB; + + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + hub->gpio_reset = gpio; + + if (of_property_read_u32(np, "initial-mode", &hub->mode)) + hub->mode = mode; + + return usb4604_switch_mode(hub, hub->mode); +} + +static int usb4604_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct usb4604 *hub; + + hub = devm_kzalloc(&i2c->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + i2c_set_clientdata(i2c, hub); + hub->dev = &i2c->dev; + + return usb4604_probe(hub); +} + +#ifdef CONFIG_PM_SLEEP +static int usb4604_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb4604 *hub = i2c_get_clientdata(client); + + usb4604_switch_mode(hub, USB4604_MODE_STANDBY); + + return 0; +} + +static int usb4604_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb4604 *hub = i2c_get_clientdata(client); + + usb4604_switch_mode(hub, hub->mode); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(usb4604_i2c_pm_ops, usb4604_i2c_suspend, + usb4604_i2c_resume); + +static const struct i2c_device_id usb4604_id[] = { + { "usb4604", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, usb4604_id); + +#ifdef CONFIG_OF +static const struct of_device_id usb4604_of_match[] = { + { .compatible = "smsc,usb4604" }, + {} +}; +MODULE_DEVICE_TABLE(of, usb4604_of_match); +#endif + +static struct i2c_driver usb4604_i2c_driver = { + .driver = { + .name = "usb4604", + .pm = &usb4604_i2c_pm_ops, + .of_match_table = of_match_ptr(usb4604_of_match), + }, + .probe = usb4604_i2c_probe, + .id_table = usb4604_id, +}; +module_i2c_driver(usb4604_i2c_driver); + +MODULE_DESCRIPTION("USB4604 USB HUB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index bbd029c..256d02d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -162,7 +162,6 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p rq->urb = usb_alloc_urb(0, mem_flags); if (!rq->urb) { kref_put(&rq->ref_count, destroy_async); - dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } rq->dr = kmalloc(sizeof(*rq->dr), mem_flags); diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 343fa6f..bb606bd 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -231,10 +231,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate control URB */ dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->cntl_urb) { - dev_err(&interface->dev, "Could not allocate control URB\n"); + if (!dev->cntl_urb) goto error; - } /* allocate buffer for control req */ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); @@ -269,10 +267,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate interrupt URB */ dev->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urb) { - dev_err(&interface->dev, "Could not allocate URB\n"); + if (!dev->urb) goto error; - } /* allocate buffer for interrupt in */ dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index ef2d8cd..c8afd2d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -794,10 +794,8 @@ static int usb_stor_acquire_resources(struct us_data *us) struct task_struct *th; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!us->current_urb) { - usb_stor_dbg(us, "URB allocation failed\n"); + if (!us->current_urb) return -ENOMEM; - } /* * Just before we start our control thread, initialize @@ -1070,17 +1068,17 @@ int usb_stor_probe2(struct us_data *us) result = usb_stor_acquire_resources(us); if (result) goto BadDevice; + usb_autopm_get_interface_no_resume(us->pusb_intf); snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s", dev_name(&us->pusb_intf->dev)); result = scsi_add_host(us_to_host(us), dev); if (result) { dev_warn(dev, "Unable to add the scsi host\n"); - goto BadDevice; + goto HostAddErr; } /* Submit the delayed_work for SCSI-device scanning */ - usb_autopm_get_interface_no_resume(us->pusb_intf); set_bit(US_FLIDX_SCAN_PENDING, &us->dflags); if (delay_use > 0) @@ -1090,6 +1088,8 @@ int usb_stor_probe2(struct us_data *us) return 0; /* We come here if there are any problems */ +HostAddErr: + usb_autopm_put_interface_no_suspend(us->pusb_intf); BadDevice: usb_stor_dbg(us, "storage_probe() failed\n"); release_everything(us); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 545d09b..89e02a7 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -532,11 +532,8 @@ static int skel_probe(struct usb_interface *interface, goto error; } dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->bulk_in_urb) { - dev_err(&interface->dev, - "Could not allocate bulk_in_urb\n"); + if (!dev->bulk_in_urb) goto error; - } } if (!dev->bulk_out_endpointAddr && diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index 17646b2..29492c7 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -24,6 +24,27 @@ config USBIP_VHCI_HCD To compile this driver as a module, choose M here: the module will be called vhci-hcd. +config USBIP_VHCI_HC_PORTS + int "Number of ports per USB/IP virtual host controller" + range 1 31 + default 8 + depends on USBIP_VHCI_HCD + ---help--- + To increase number of ports available for USB/IP virtual + host controller driver, this defines number of ports per + USB/IP virtual host controller. + +config USBIP_VHCI_NR_HCS + int "Number of USB/IP virtual host controllers" + range 1 128 + default 1 + depends on USBIP_VHCI_HCD + ---help--- + To increase number of ports available for USB/IP virtual + host controller driver, this defines number of USB/IP + virtual host controllers as if adding physical host + controllers. + config USBIP_HOST tristate "Host driver" depends on USBIP_CORE && USB diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 2df63e3..191b176 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -461,7 +461,6 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, priv->urb = usb_alloc_urb(0, GFP_KERNEL); if (!priv->urb) { - dev_err(&udev->dev, "malloc urb\n"); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h index a863a98..88b71c4 100644 --- a/drivers/usb/usbip/vhci.h +++ b/drivers/usb/usbip/vhci.h @@ -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 @@ -72,13 +73,25 @@ struct vhci_unlink { }; /* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */ -#define VHCI_NPORTS 8 +#ifdef CONFIG_USBIP_VHCI_HC_PORTS +#define VHCI_HC_PORTS CONFIG_USBIP_VHCI_HC_PORTS +#else +#define VHCI_HC_PORTS 8 +#endif + +#ifdef CONFIG_USBIP_VHCI_NR_HCS +#define VHCI_NR_HCS CONFIG_USBIP_VHCI_NR_HCS +#else +#define VHCI_NR_HCS 1 +#endif + +#define MAX_STATUS_NAME 16 /* for usb_bus.hcpriv */ struct vhci_hcd { spinlock_t lock; - u32 port_status[VHCI_NPORTS]; + u32 port_status[VHCI_HC_PORTS]; unsigned resuming:1; unsigned long re_timeout; @@ -90,14 +103,19 @@ struct vhci_hcd { * wIndex shows the port number and begins from 1. * But, the index of this array begins from 0. */ - struct vhci_device vdev[VHCI_NPORTS]; + struct vhci_device vdev[VHCI_HC_PORTS]; }; -extern struct vhci_hcd *the_controller; -extern const struct attribute_group dev_attr_group; +extern int vhci_num_controllers; +extern struct platform_device **vhci_pdevs; +extern struct attribute_group vhci_attr_group; /* vhci_hcd.c */ -void rh_port_connect(int rhport, enum usb_device_speed speed); +void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed); + +/* vhci_sysfs.c */ +int vhci_init_attr_group(void); +void vhci_finish_attr_group(void); /* vhci_rx.c */ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum); @@ -106,9 +124,14 @@ int vhci_rx_loop(void *data); /* vhci_tx.c */ int vhci_tx_loop(void *data); -static inline struct vhci_device *port_to_vdev(__u32 port) +static inline __u32 port_to_rhport(__u32 port) +{ + return port % VHCI_HC_PORTS; +} + +static inline int port_to_pdev_nr(__u32 port) { - return &the_controller->vdev[port]; + return port / VHCI_HC_PORTS; } static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd) @@ -116,14 +139,25 @@ static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd) return (struct vhci_hcd *) (hcd->hcd_priv); } +static inline struct device *hcd_dev(struct usb_hcd *hcd) +{ + return (hcd)->self.controller; +} + +static inline const char *hcd_name(struct usb_hcd *hcd) +{ + return (hcd)->self.bus_name; +} + static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci) { return container_of((void *) vhci, struct usb_hcd, hcd_priv); } -static inline struct device *vhci_dev(struct vhci_hcd *vhci) +static inline struct vhci_hcd *vdev_to_vhci(struct vhci_device *vdev) { - return vhci_to_hcd(vhci)->self.controller; + return container_of( + (void *)(vdev - vdev->rhport), struct vhci_hcd, vdev); } #endif /* __USBIP_VHCI_H */ diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 2e0450b..03eccf2 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 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 @@ -56,7 +57,9 @@ static int vhci_get_frame_number(struct usb_hcd *hcd); static const char driver_name[] = "vhci_hcd"; static const char driver_desc[] = "USB/IP Virtual Host Controller"; -struct vhci_hcd *the_controller; +int vhci_num_controllers = VHCI_NR_HCS; + +struct platform_device **vhci_pdevs; static const char * const bit_desc[] = { "CONNECTION", /*0*/ @@ -119,47 +122,59 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status) pr_debug("\n"); } -void rh_port_connect(int rhport, enum usb_device_speed speed) +void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + int rhport = vdev->rhport; + u32 status; unsigned long flags; usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + + status = vhci->port_status[rhport]; - the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION - | (1 << USB_PORT_FEAT_C_CONNECTION); + status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION); switch (speed) { case USB_SPEED_HIGH: - the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED; + status |= USB_PORT_STAT_HIGH_SPEED; break; case USB_SPEED_LOW: - the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED; + status |= USB_PORT_STAT_LOW_SPEED; break; default: break; } - spin_unlock_irqrestore(&the_controller->lock, flags); + vhci->port_status[rhport] = status; + + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + usb_hcd_poll_rh_status(vhci_to_hcd(vhci)); } -static void rh_port_disconnect(int rhport) +static void rh_port_disconnect(struct vhci_device *vdev) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + int rhport = vdev->rhport; + u32 status; unsigned long flags; usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + + status = vhci->port_status[rhport]; + + status &= ~USB_PORT_STAT_CONNECTION; + status |= (1 << USB_PORT_FEAT_C_CONNECTION); - the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; - the_controller->port_status[rhport] |= - (1 << USB_PORT_FEAT_C_CONNECTION); + vhci->port_status[rhport] = status; - spin_unlock_irqrestore(&the_controller->lock, flags); - usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + spin_unlock_irqrestore(&vhci->lock, flags); + usb_hcd_poll_rh_status(vhci_to_hcd(vhci)); } #define PORT_C_MASK \ @@ -188,7 +203,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) int changed = 0; unsigned long flags; - retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8); + retval = DIV_ROUND_UP(VHCI_HC_PORTS + 1, 8); memset(buf, 0, retval); vhci = hcd_to_vhci(hcd); @@ -200,7 +215,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) } /* check pseudo status register for each port */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { if ((vhci->port_status[rhport] & PORT_C_MASK)) { /* The status of a port has been changed, */ usbip_dbg_vhci_rh("port %d status changed\n", rhport); @@ -225,7 +240,7 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc) desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16( HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM); - desc->bNbrPorts = VHCI_NPORTS; + desc->bNbrPorts = VHCI_HC_PORTS; desc->u.hs.DeviceRemovable[0] = 0xff; desc->u.hs.DeviceRemovable[1] = 0xff; } @@ -238,7 +253,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, int rhport; unsigned long flags; - u32 prev_port_status[VHCI_NPORTS]; + u32 prev_port_status[VHCI_HC_PORTS]; if (!HCD_HW_ACCESSIBLE(hcd)) return -ETIMEDOUT; @@ -249,7 +264,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, */ usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, wIndex); - if (wIndex > VHCI_NPORTS) + if (wIndex > VHCI_HC_PORTS) pr_err("invalid port number %d\n", wIndex); rhport = ((__u8)(wIndex & 0x00ff)) - 1; @@ -315,7 +330,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetPortStatus: usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); - if (wIndex > VHCI_NPORTS || wIndex < 1) { + if (wIndex > VHCI_HC_PORTS || wIndex < 1) { pr_err("invalid port number %d\n", wIndex); retval = -EPIPE; } @@ -416,14 +431,27 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, static struct vhci_device *get_vdev(struct usb_device *udev) { - int i; + struct platform_device *pdev; + struct usb_hcd *hcd; + struct vhci_hcd *vhci; + int pdev_nr, rhport; if (!udev) return NULL; - for (i = 0; i < VHCI_NPORTS; i++) - if (the_controller->vdev[i].udev == udev) - return port_to_vdev(i); + for (pdev_nr = 0; pdev_nr < vhci_num_controllers; pdev_nr++) { + pdev = *(vhci_pdevs + pdev_nr); + if (pdev == NULL) + continue; + hcd = platform_get_drvdata(pdev); + if (hcd == NULL) + continue; + vhci = hcd_to_vhci(hcd); + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { + if (vhci->vdev[rhport].udev == udev) + return &vhci->vdev[rhport]; + } + } return NULL; } @@ -432,6 +460,7 @@ static void vhci_tx_urb(struct urb *urb) { struct vhci_device *vdev = get_vdev(urb->dev); struct vhci_priv *priv; + struct vhci_hcd *vhci = vdev_to_vhci(vdev); unsigned long flags; if (!vdev) { @@ -447,7 +476,7 @@ static void vhci_tx_urb(struct urb *urb) spin_lock_irqsave(&vdev->priv_lock, flags); - priv->seqnum = atomic_inc_return(&the_controller->seqnum); + priv->seqnum = atomic_inc_return(&vhci->seqnum); if (priv->seqnum == 0xffff) dev_info(&urb->dev->dev, "seqnum max\n"); @@ -465,7 +494,9 @@ static void vhci_tx_urb(struct urb *urb) static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); struct device *dev = &urb->dev->dev; + u8 portnum = urb->dev->portnum; int ret = 0; struct vhci_device *vdev; unsigned long flags; @@ -473,26 +504,30 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", hcd, urb, mem_flags); + if (portnum > VHCI_HC_PORTS) { + pr_err("invalid port number %d\n", portnum); + return -ENODEV; + } + vdev = &vhci->vdev[portnum-1]; + /* patch to usb_sg_init() is in 2.5.60 */ BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); if (urb->status != -EINPROGRESS) { dev_err(dev, "URB already unlinked!, status %d\n", urb->status); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return urb->status; } - vdev = port_to_vdev(urb->dev->portnum-1); - /* refuse enqueue for dead connection */ spin_lock(&vdev->ud.lock); if (vdev->ud.status == VDEV_ST_NULL || vdev->ud.status == VDEV_ST_ERROR) { dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport); spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -ENODEV; } spin_unlock(&vdev->ud.lock); @@ -565,17 +600,16 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, out: vhci_tx_urb(urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return 0; no_need_xmit: usb_hcd_unlink_urb_from_ep(hcd, urb); no_need_unlink: - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); if (!ret) - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), - urb, urb->status); + usb_hcd_giveback_urb(hcd, urb, urb->status); return ret; } @@ -627,19 +661,20 @@ no_need_unlink: */ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); struct vhci_priv *priv; struct vhci_device *vdev; unsigned long flags; pr_info("dequeue a urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); priv = urb->hcpriv; if (!priv) { /* URB was never linked! or will be soon given back by * vhci_rx. */ - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -EIDRM; } @@ -648,7 +683,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) { - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return ret; } } @@ -676,10 +711,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&the_controller->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); + spin_lock_irqsave(&vhci->lock, flags); } else { /* tcp connection is alive */ @@ -691,12 +725,12 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); if (!unlink) { spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); return -ENOMEM; } - unlink->seqnum = atomic_inc_return(&the_controller->seqnum); + unlink->seqnum = atomic_inc_return(&vhci->seqnum); if (unlink->seqnum == 0xffff) pr_info("seqnum max\n"); @@ -712,7 +746,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) spin_unlock(&vdev->priv_lock); } - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_dbg_vhci_hc("leave\n"); return 0; @@ -720,10 +754,12 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void vhci_device_unlink_cleanup(struct vhci_device *vdev) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + struct usb_hcd *hcd = vhci_to_hcd(vhci); struct vhci_unlink *unlink, *tmp; unsigned long flags; - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { @@ -752,24 +788,23 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) urb->status = -ENODEV; - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); list_del(&unlink->list); spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); + usb_hcd_giveback_urb(hcd, urb, urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->priv_lock); kfree(unlink); } spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); } /* @@ -827,7 +862,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) * is actually given back by vhci_rx after receiving its return pdu. * */ - rh_port_disconnect(vdev->rhport); + rh_port_disconnect(vdev); pr_info("disconnect device\n"); } @@ -866,7 +901,7 @@ static void vhci_device_unusable(struct usbip_device *ud) static void vhci_device_init(struct vhci_device *vdev) { - memset(vdev, 0, sizeof(*vdev)); + memset(vdev, 0, sizeof(struct vhci_device)); vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; @@ -887,17 +922,34 @@ static void vhci_device_init(struct vhci_device *vdev) usbip_start_eh(&vdev->ud); } +static int hcd_name_to_id(const char *name) +{ + char *c; + long val; + int ret; + + c = strchr(name, '.'); + if (c == NULL) + return 0; + + ret = kstrtol(c+1, 10, &val); + if (ret < 0) + return ret; + + return val; +} + static int vhci_start(struct usb_hcd *hcd) { struct vhci_hcd *vhci = hcd_to_vhci(hcd); - int rhport; + int id, rhport; int err = 0; usbip_dbg_vhci_hc("enter vhci_start\n"); /* initialize private data of usb_hcd */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; vhci_device_init(vdev); @@ -910,11 +962,26 @@ static int vhci_start(struct usb_hcd *hcd) hcd->power_budget = 0; /* no limit */ hcd->uses_new_polling = 1; + id = hcd_name_to_id(hcd_name(hcd)); + if (id < 0) { + pr_err("invalid vhci name %s\n", hcd_name(hcd)); + return -EINVAL; + } + /* vhci_hcd is now ready to be controlled through sysfs */ - err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group); - if (err) { - pr_err("create sysfs files\n"); - return err; + if (id == 0) { + err = vhci_init_attr_group(); + if (err) { + pr_err("init attr group\n"); + return err; + } + err = sysfs_create_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); + if (err) { + pr_err("create sysfs files\n"); + vhci_finish_attr_group(); + return err; + } + pr_info("created sysfs %s\n", hcd_name(hcd)); } return 0; @@ -923,15 +990,19 @@ static int vhci_start(struct usb_hcd *hcd) static void vhci_stop(struct usb_hcd *hcd) { struct vhci_hcd *vhci = hcd_to_vhci(hcd); - int rhport = 0; + int id, rhport; usbip_dbg_vhci_hc("stop VHCI controller\n"); /* 1. remove the userland interface of vhci_hcd */ - sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); + id = hcd_name_to_id(hcd_name(hcd)); + if (id == 0) { + sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); + vhci_finish_attr_group(); + } /* 2. shutdown all the ports of vhci_hcd */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); @@ -1025,9 +1096,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) } hcd->has_tt = 1; - /* this is private data for vhci_hcd */ - the_controller = hcd_to_vhci(hcd); - /* * Finish generic HCD structure initialization and register. * Call the driver's reset() and start() routines. @@ -1036,7 +1104,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) if (ret != 0) { pr_err("usb_add_hcd failed %d\n", ret); usb_put_hcd(hcd); - the_controller = NULL; return ret; } @@ -1059,7 +1126,6 @@ static int vhci_hcd_remove(struct platform_device *pdev) */ usb_remove_hcd(hcd); usb_put_hcd(hcd); - the_controller = NULL; return 0; } @@ -1070,21 +1136,24 @@ static int vhci_hcd_remove(struct platform_device *pdev) static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd; - int rhport = 0; + struct vhci_hcd *vhci; + int rhport; int connected = 0; int ret = 0; unsigned long flags; hcd = platform_get_drvdata(pdev); + if (!hcd) + return 0; + vhci = hcd_to_vhci(hcd); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) - if (the_controller->port_status[rhport] & - USB_PORT_STAT_CONNECTION) + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) + if (vhci->port_status[rhport] & USB_PORT_STAT_CONNECTION) connected += 1; - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); if (connected > 0) { dev_info(&pdev->dev, @@ -1106,6 +1175,8 @@ static int vhci_hcd_resume(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s\n", __func__); hcd = platform_get_drvdata(pdev); + if (!hcd) + return 0; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); usb_hcd_poll_rh_status(hcd); @@ -1129,52 +1200,78 @@ static struct platform_driver vhci_driver = { }, }; -/* - * The VHCI 'device' is 'virtual'; not a real plug&play hardware. - * We need to add this virtual device as a platform device arbitrarily: - * 1. platform_device_register() - */ -static void the_pdev_release(struct device *dev) +static int add_platform_device(int id) { + struct platform_device *pdev; + int dev_nr; + + if (id == 0) + dev_nr = -1; + else + dev_nr = id; + + pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + *(vhci_pdevs + id) = pdev; + return 0; } -static struct platform_device the_pdev = { - /* should be the same name as driver_name */ - .name = driver_name, - .id = -1, - .dev = { - .release = the_pdev_release, - }, -}; +static void del_platform_devices(void) +{ + struct platform_device *pdev; + int i; + + for (i = 0; i < vhci_num_controllers; i++) { + pdev = *(vhci_pdevs + i); + if (pdev != NULL) + platform_device_unregister(pdev); + *(vhci_pdevs + i) = NULL; + } + sysfs_remove_link(&platform_bus.kobj, driver_name); +} static int __init vhci_hcd_init(void) { - int ret; + int i, ret; if (usb_disabled()) return -ENODEV; + if (vhci_num_controllers < 1) + vhci_num_controllers = 1; + + vhci_pdevs = kcalloc(vhci_num_controllers, sizeof(void *), GFP_KERNEL); + if (vhci_pdevs == NULL) + return -ENOMEM; + ret = platform_driver_register(&vhci_driver); if (ret) goto err_driver_register; - ret = platform_device_register(&the_pdev); - if (ret) - goto err_platform_device_register; + for (i = 0; i < vhci_num_controllers; i++) { + ret = add_platform_device(i); + if (ret) + goto err_platform_device_register; + } pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); return ret; err_platform_device_register: + del_platform_devices(); platform_driver_unregister(&vhci_driver); err_driver_register: + kfree(vhci_pdevs); return ret; } static void __exit vhci_hcd_exit(void) { - platform_device_unregister(&the_pdev); + del_platform_devices(); platform_driver_unregister(&vhci_driver); + kfree(vhci_pdevs); } module_init(vhci_hcd_init); diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index d656e0e..fc2d319 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -70,6 +70,7 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) static void vhci_recv_ret_submit(struct vhci_device *vdev, struct usbip_header *pdu) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); struct usbip_device *ud = &vdev->ud; struct urb *urb; unsigned long flags; @@ -81,7 +82,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, if (!urb) { pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum); pr_info("max seqnum %d\n", - atomic_read(&the_controller->seqnum)); + atomic_read(&vhci->seqnum)); usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return; } @@ -105,11 +106,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); usbip_dbg_vhci_rx("Leave\n"); } @@ -142,6 +143,7 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev, static void vhci_recv_ret_unlink(struct vhci_device *vdev, struct usbip_header *pdu) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); struct vhci_unlink *unlink; struct urb *urb; unsigned long flags; @@ -174,12 +176,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, urb->status = pdu->u.ret_unlink.status; pr_info("urb->status %d\n", urb->status); - spin_lock_irqsave(&the_controller->lock, flags); - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); } kfree(unlink); diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 5b5462e..c404017 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 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 @@ -20,6 +21,8 @@ #include <linux/kthread.h> #include <linux/file.h> #include <linux/net.h> +#include <linux/platform_device.h> +#include <linux/slab.h> #include "usbip_common.h" #include "vhci.h" @@ -27,106 +30,190 @@ /* TODO: refine locking ?*/ /* Sysfs entry to show port status */ -static ssize_t status_show(struct device *dev, struct device_attribute *attr, - char *out) +static ssize_t status_show_vhci(int pdev_nr, char *out) { + struct platform_device *pdev = *(vhci_pdevs + pdev_nr); + struct vhci_hcd *vhci; char *s = out; int i = 0; unsigned long flags; - BUG_ON(!the_controller || !out); + if (!pdev || !out) { + usbip_dbg_vhci_sysfs("show status error\n"); + return 0; + } + + vhci = hcd_to_vhci(platform_get_drvdata(pdev)); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); /* * output example: - * prt sta spd dev socket local_busid - * 000 004 000 000 c5a7bb80 1-2.3 - * 001 004 000 000 d8cee980 2-3.4 + * port sta spd dev socket local_busid + * 0000 004 000 00000000 c5a7bb80 1-2.3 + * 0001 004 000 00000000 d8cee980 2-3.4 * * IP address can be retrieved from a socket pointer address by looking * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a * port number and its peer IP address. */ - out += sprintf(out, - "prt sta spd bus dev socket local_busid\n"); - - for (i = 0; i < VHCI_NPORTS; i++) { - struct vhci_device *vdev = port_to_vdev(i); + for (i = 0; i < VHCI_HC_PORTS; i++) { + struct vhci_device *vdev = &vhci->vdev[i]; spin_lock(&vdev->ud.lock); - out += sprintf(out, "%03u %03u ", i, vdev->ud.status); + out += sprintf(out, "%04u %03u ", + (pdev_nr * VHCI_HC_PORTS) + i, + vdev->ud.status); if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %08x ", - vdev->speed, vdev->devid); - out += sprintf(out, "%16p ", vdev->ud.tcp_socket); - out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); + vdev->speed, vdev->devid); + out += sprintf(out, "%16p %s", + vdev->ud.tcp_socket, + dev_name(&vdev->udev->dev)); } else { - out += sprintf(out, "000 000 000 0000000000000000 0-0"); + out += sprintf(out, "000 00000000 "); + out += sprintf(out, "0000000000000000 0-0"); } out += sprintf(out, "\n"); spin_unlock(&vdev->ud.lock); } - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); + + return out - s; +} + +static ssize_t status_show_not_ready(int pdev_nr, char *out) +{ + char *s = out; + int i = 0; + + for (i = 0; i < VHCI_HC_PORTS; i++) { + out += sprintf(out, "%04u %03u ", + (pdev_nr * VHCI_HC_PORTS) + i, + VDEV_ST_NOTASSIGNED); + out += sprintf(out, "000 00000000 0000000000000000 0-0"); + out += sprintf(out, "\n"); + } + return out - s; +} + +static int status_name_to_id(const char *name) +{ + char *c; + long val; + int ret; + + c = strchr(name, '.'); + if (c == NULL) + return 0; + ret = kstrtol(c+1, 10, &val); + if (ret < 0) + return ret; + + return val; +} + +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *out) +{ + char *s = out; + int pdev_nr; + + out += sprintf(out, + "port sta spd dev socket local_busid\n"); + + pdev_nr = status_name_to_id(attr->attr.name); + if (pdev_nr < 0) + out += status_show_not_ready(pdev_nr, out); + else + out += status_show_vhci(pdev_nr, out); + + return out - s; +} + +static ssize_t nports_show(struct device *dev, struct device_attribute *attr, + char *out) +{ + char *s = out; + + out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers); return out - s; } -static DEVICE_ATTR_RO(status); +static DEVICE_ATTR_RO(nports); /* Sysfs entry to shutdown a virtual connection */ -static int vhci_port_disconnect(__u32 rhport) +static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport) { - struct vhci_device *vdev; + struct vhci_device *vdev = &vhci->vdev[rhport]; unsigned long flags; usbip_dbg_vhci_sysfs("enter\n"); /* lock */ - spin_lock_irqsave(&the_controller->lock, flags); - - vdev = port_to_vdev(rhport); - + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->ud.lock); + if (vdev->ud.status == VDEV_ST_NULL) { pr_err("not connected %d\n", vdev->ud.status); /* unlock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -EINVAL; } /* unlock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); return 0; } +static int valid_port(__u32 pdev_nr, __u32 rhport) +{ + if (pdev_nr >= vhci_num_controllers) { + pr_err("pdev %u\n", pdev_nr); + return 0; + } + if (rhport >= VHCI_HC_PORTS) { + pr_err("rhport %u\n", rhport); + return 0; + } + return 1; +} + static ssize_t store_detach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int err; - __u32 rhport = 0; + __u32 port = 0, pdev_nr = 0, rhport = 0; + struct usb_hcd *hcd; + int ret; - if (sscanf(buf, "%u", &rhport) != 1) + if (kstrtoint(buf, 10, &port) < 0) return -EINVAL; - /* check rhport */ - if (rhport >= VHCI_NPORTS) { - dev_err(dev, "invalid port %u\n", rhport); + pdev_nr = port_to_pdev_nr(port); + rhport = port_to_rhport(port); + + if (!valid_port(pdev_nr, rhport)) return -EINVAL; + + hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); + if (hcd == NULL) { + dev_err(dev, "port is not ready %u\n", port); + return -EAGAIN; } - err = vhci_port_disconnect(rhport); - if (err < 0) + ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport); + if (ret < 0) return -EINVAL; usbip_dbg_vhci_sysfs("Leave\n"); @@ -135,16 +222,12 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); -/* Sysfs entry to establish a virtual connection */ -static int valid_args(__u32 rhport, enum usb_device_speed speed) +static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed) { - /* check rhport */ - if (rhport >= VHCI_NPORTS) { - pr_err("port %u\n", rhport); - return -EINVAL; + if (!valid_port(pdev_nr, rhport)) { + return 0; } - /* check speed */ switch (speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: @@ -154,12 +237,13 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) default: pr_err("Failed attach request for unsupported USB speed: %s\n", usb_speed_string(speed)); - return -EINVAL; + return 0; } - return 0; + return 1; } +/* Sysfs entry to establish a virtual connection */ /* * To start a new USB/IP attachment, a userland program needs to setup a TCP * connection and then write its socket descriptor with remote device @@ -174,10 +258,12 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct vhci_device *vdev; struct socket *socket; int sockfd = 0; - __u32 rhport = 0, devid = 0, speed = 0; + __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0; + struct usb_hcd *hcd; + struct vhci_hcd *vhci; + struct vhci_device *vdev; int err; unsigned long flags; @@ -187,16 +273,28 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ - if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) + if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4) return -EINVAL; + pdev_nr = port_to_pdev_nr(port); + rhport = port_to_rhport(port); - usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", - rhport, sockfd, devid, speed); + usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n", + port, pdev_nr, rhport); + usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n", + sockfd, devid, speed); /* check received parameters */ - if (valid_args(rhport, speed) < 0) + if (!valid_args(pdev_nr, rhport, speed)) return -EINVAL; + hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); + if (hcd == NULL) { + dev_err(dev, "port %d is not ready\n", port); + return -EAGAIN; + } + vhci = hcd_to_vhci(hcd); + vdev = &vhci->vdev[rhport]; + /* Extract socket from fd. */ socket = sockfd_lookup(sockfd, &err); if (!socket) @@ -205,14 +303,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, /* now need lock until setting vdev status as used */ /* begin a lock */ - spin_lock_irqsave(&the_controller->lock, flags); - vdev = port_to_vdev(rhport); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); sockfd_put(socket); @@ -220,9 +317,10 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, return -EINVAL; } - dev_info(dev, - "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", - rhport, sockfd, devid, speed, usb_speed_string(speed)); + dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", + pdev_nr, rhport, sockfd); + dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n", + devid, speed, usb_speed_string(speed)); vdev->devid = devid; vdev->speed = speed; @@ -230,26 +328,92 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->ud.status = VDEV_ST_NOTASSIGNED; spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); /* end the lock */ vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); - rh_port_connect(rhport, speed); + rh_port_connect(vdev, speed); return count; } static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); -static struct attribute *dev_attrs[] = { - &dev_attr_status.attr, - &dev_attr_detach.attr, - &dev_attr_attach.attr, - &dev_attr_usbip_debug.attr, - NULL, +#define MAX_STATUS_NAME 16 + +struct status_attr { + struct device_attribute attr; + char name[MAX_STATUS_NAME+1]; }; -const struct attribute_group dev_attr_group = { - .attrs = dev_attrs, +static struct status_attr *status_attrs; + +static void set_status_attr(int id) +{ + struct status_attr *status; + + status = status_attrs + id; + if (id == 0) + strcpy(status->name, "status"); + else + snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id); + status->attr.attr.name = status->name; + status->attr.attr.mode = S_IRUGO; + status->attr.show = status_show; +} + +static int init_status_attrs(void) +{ + int id; + + status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr), + GFP_KERNEL); + if (status_attrs == NULL) + return -ENOMEM; + + for (id = 0; id < vhci_num_controllers; id++) + set_status_attr(id); + + return 0; +} + +static void finish_status_attrs(void) +{ + kfree(status_attrs); +} + +struct attribute_group vhci_attr_group = { + .attrs = NULL, }; + +int vhci_init_attr_group(void) +{ + struct attribute **attrs; + int ret, i; + + attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *), + GFP_KERNEL); + if (attrs == NULL) + return -ENOMEM; + + ret = init_status_attrs(); + if (ret) { + kfree(attrs); + return ret; + } + *attrs = &dev_attr_nports.attr; + *(attrs + 1) = &dev_attr_detach.attr; + *(attrs + 2) = &dev_attr_attach.attr; + *(attrs + 3) = &dev_attr_usbip_debug.attr; + for (i = 0; i < vhci_num_controllers; i++) + *(attrs + i + 4) = &((status_attrs + i)->attr.attr); + vhci_attr_group.attrs = attrs; + return 0; +} + +void vhci_finish_attr_group(void) +{ + finish_status_attrs(); + kfree(vhci_attr_group.attrs); +} diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index 60a10d2..6140100 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -277,10 +277,8 @@ int wa_nep_create(struct wahc *wa, struct usb_interface *iface) goto error_nep_buffer; } wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->nep_urb == NULL) { - dev_err(dev, "Unable to allocate notification URB\n"); + if (wa->nep_urb == NULL) goto error_urb_alloc; - } usb_fill_int_urb(wa->nep_urb, usb_dev, usb_rcvintpipe(usb_dev, epd->bEndpointAddress), wa->nep_buffer, wa->nep_buffer_size, diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 69af4fd..167fcc71 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -2865,10 +2865,8 @@ int wa_dti_start(struct wahc *wa) goto out; wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->dti_urb == NULL) { - dev_err(dev, "Can't allocate DTI URB\n"); + if (wa->dti_urb == NULL) goto error_dti_urb_alloc; - } usb_fill_bulk_urb( wa->dti_urb, wa->usb_dev, usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress), diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c index 0257f35..0aa6c3c 100644 --- a/drivers/uwb/hwa-rc.c +++ b/drivers/uwb/hwa-rc.c @@ -701,10 +701,8 @@ static int hwarc_neep_init(struct uwb_rc *rc) goto error_rd_buffer; } hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (hwarc->neep_urb == NULL) { - dev_err(dev, "Unable to allocate notification URB\n"); + if (hwarc->neep_urb == NULL) goto error_urb_alloc; - } usb_fill_int_urb(hwarc->neep_urb, usb_dev, usb_rcvintpipe(usb_dev, epd->bEndpointAddress), hwarc->rd_buffer, PAGE_SIZE, |