diff options
Diffstat (limited to 'drivers/usb')
31 files changed, 611 insertions, 101 deletions
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index 14ec9f0c592..b3b1bb78b2e 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c @@ -20,7 +20,7 @@ ******************************************************************************/ #include <linux/module.h> -#include <linux/etherdevice.h> /* for random_ether_addr() */ +#include <linux/etherdevice.h> /* for eth_random_addr() */ #include "usbatm.h" @@ -163,7 +163,7 @@ static int xusbatm_atm_start(struct usbatm_data *usbatm, atm_dbg(usbatm, "%s entered\n", __func__); /* use random MAC as we've no way to get it from the device */ - random_ether_addr(atm_dev->esi); + eth_random_addr(atm_dev->esi); return 0; } diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8fd398dffce..ee469274a3f 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -500,6 +500,8 @@ retry: goto retry; } if (!desc->reslength) { /* zero length read */ + dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); + clear_bit(WDM_READ, &desc->flags); spin_unlock_irq(&desc->iuspin); goto retry; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 25a7422ee65..8fb484984c8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub) static int hub_port_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive state? */ -static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus) +/* Is a USB 3.0 port in the Inactive or Complinance Mode state? + * Port worm reset is required to recover + */ +static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) { return hub_is_superspeed(hub->hdev) && - (portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_SS_INACTIVE; + (((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_SS_INACTIVE) || + ((portstatus & USB_PORT_STAT_LINK_STATE) == + USB_SS_PORT_LS_COMP_MOD)) ; } static int hub_port_wait_reset(struct usb_hub *hub, int port1, @@ -2365,7 +2369,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, * * See https://bugzilla.kernel.org/show_bug.cgi?id=41752 */ - if (hub_port_inactive(hub, portstatus)) { + if (hub_port_warm_reset_required(hub, portstatus)) { int ret; if ((portchange & USB_PORT_STAT_C_CONNECTION)) @@ -4408,9 +4412,7 @@ static void hub_events(void) /* Warm reset a USB3 protocol port if it's in * SS.Inactive state. */ - if (hub_is_superspeed(hub->hdev) && - (portstatus & USB_PORT_STAT_LINK_STATE) - == USB_SS_PORT_LS_SS_INACTIVE) { + if (hub_port_warm_reset_required(hub, portstatus)) { dev_dbg(hub_dev, "warm reset port %d\n", i); hub_port_reset(hub, i, NULL, HUB_BH_RESET_TIME, true); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bddc8fd9a7b..271ca161d7e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -185,7 +185,7 @@ config USB_FUSB300 config USB_OMAP tristate "OMAP USB Device Controller" - depends on ARCH_OMAP + depends on ARCH_OMAP1 select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG select USB_OTG_UTILS if ARCH_OMAP help diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index a460e8c204f..89cbd2b22ab 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -44,7 +44,8 @@ #include <asm/mach-types.h> #include <plat/dma.h> -#include <plat/usb.h> + +#include <mach/usb.h> #include "omap_udc.h" diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index c46439c8dd7..5444866e13e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -294,7 +294,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd) pr_err("%s(%d)\n", __func__, __LINE__); wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } @@ -725,7 +725,7 @@ static int uasp_send_write_request(struct usbg_cmd *cmd) } wait_for_completion(&cmd->write_complete); - transport_generic_process_write(se_cmd); + target_execute_cmd(se_cmd); cleanup: return ret; } @@ -1065,16 +1065,20 @@ static void usbg_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int usbg_submit_command(struct f_uas *fu, @@ -1177,16 +1181,20 @@ static void bot_cmd_work(struct work_struct *work) tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, cmd->prio_attr, cmd->sense_iu.sense); - - transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - usbg_cleanup_cmd(cmd); - return; + goto out; } - target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, - cmd->data_len, cmd->prio_attr, dir, 0); + cmd->data_len, cmd->prio_attr, dir, 0) < 0) + goto out; + + return; + +out: + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); } static int bot_submit_command(struct f_uas *fu, @@ -1400,19 +1408,6 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) return 1; } -static int usbg_new_cmd(struct se_cmd *se_cmd) -{ - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - int ret; - - ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); - if (ret) - return ret; - - return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); -} - static void usbg_cmd_release(struct kref *ref) { struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, @@ -1902,7 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = { .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, .tpg_release_fabric_acl = usbg_release_fabric_acl, .tpg_get_inst_index = usbg_tpg_get_inst_index, - .new_cmd_map = usbg_new_cmd, .release_cmd = usbg_release_cmd, .shutdown_session = usbg_shutdown_session, .close_session = usbg_close_session, diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 47cf48b51c9..b9e1925b2df 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -724,7 +724,7 @@ static int get_ether_addr(const char *str, u8 *dev_addr) if (is_valid_ether_addr(dev_addr)) return 0; } - random_ether_addr(dev_addr); + eth_random_addr(dev_addr); return 1; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 83e58df29fe..dcfaaa91a3f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -308,7 +308,7 @@ config USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 bool "OHCI support for OMAP1/2 chips" - depends on USB_OHCI_HCD && (ARCH_OMAP1 || ARCH_OMAP2) + depends on USB_OHCI_HCD && ARCH_OMAP1 default y ---help--- Enables support for the OHCI controller on OMAP1/2 chips. diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 800be38c78b..1d9401e0990 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1349,6 +1349,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_msm_driver #endif +#ifdef CONFIG_TILE_USB +#include "ehci-tilegx.c" +#define PLATFORM_DRIVER ehci_hcd_tilegx_driver +#endif + #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP #include "ehci-pmcmsp.c" #define PLATFORM_DRIVER ehci_hcd_msp_driver diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 17cfb8a1131..c30435499a0 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -281,14 +281,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) } } + /* Hold PHYs in reset while initializing EHCI controller */ if (pdata->phy_reset) { if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_request_one(pdata->reset_gpio_port[0], - GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); + gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0); if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_request_one(pdata->reset_gpio_port[1], - GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); + gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0); /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); @@ -330,6 +329,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); ehci_reset(omap_ehci); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "failed to add hcd with err %d\n", ret); + goto err_add_hcd; + } if (pdata->phy_reset) { /* Hold the PHY in RESET for enough time till @@ -344,12 +348,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); } - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - /* root ports should always stay powered */ ehci_port_power(omap_ehci, 1); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 68548236ec4..ab8a3bf628e 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -46,8 +46,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - clk_enable(tegra->emc_clk); - clk_enable(tegra->clk); + clk_prepare_enable(tegra->emc_clk); + clk_prepare_enable(tegra->clk); tegra_usb_phy_power_on(tegra->phy); tegra->host_resumed = 1; } @@ -58,8 +58,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) tegra->host_resumed = 0; tegra_usb_phy_power_off(tegra->phy); - clk_disable(tegra->clk); - clk_disable(tegra->emc_clk); + clk_disable_unprepare(tegra->clk); + clk_disable_unprepare(tegra->emc_clk); } static int tegra_ehci_internal_port_reset( @@ -671,7 +671,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_clk; } - err = clk_enable(tegra->clk); + err = clk_prepare_enable(tegra->clk); if (err) goto fail_clken; @@ -682,7 +682,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_emc_clk; } - clk_enable(tegra->emc_clk); + clk_prepare_enable(tegra->emc_clk); clk_set_rate(tegra->emc_clk, 400000000); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -782,10 +782,10 @@ fail: fail_phy: iounmap(hcd->regs); fail_io: - clk_disable(tegra->emc_clk); + clk_disable_unprepare(tegra->emc_clk); clk_put(tegra->emc_clk); fail_emc_clk: - clk_disable(tegra->clk); + clk_disable_unprepare(tegra->clk); fail_clken: clk_put(tegra->clk); fail_clk: @@ -820,10 +820,10 @@ static int tegra_ehci_remove(struct platform_device *pdev) tegra_usb_phy_close(tegra->phy); iounmap(hcd->regs); - clk_disable(tegra->clk); + clk_disable_unprepare(tegra->clk); clk_put(tegra->clk); - clk_disable(tegra->emc_clk); + clk_disable_unprepare(tegra->emc_clk); clk_put(tegra->emc_clk); kfree(tegra); diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c new file mode 100644 index 00000000000..1d215cdb9de --- /dev/null +++ b/drivers/usb/host/ehci-tilegx.c @@ -0,0 +1,214 @@ +/* + * Copyright 2012 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +/* + * Tilera TILE-Gx USB EHCI host controller driver. + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/usb/tilegx.h> +#include <linux/usb.h> + +#include <asm/homecache.h> + +#include <gxio/iorpc_usb_host.h> +#include <gxio/usb_host.h> + +static void tilegx_start_ehc(void) +{ +} + +static void tilegx_stop_ehc(void) +{ +} + +static int tilegx_ehci_setup(struct usb_hcd *hcd) +{ + int ret = ehci_init(hcd); + + /* + * Some drivers do: + * + * struct ehci_hcd *ehci = hcd_to_ehci(hcd); + * ehci->need_io_watchdog = 0; + * + * here, but since this is a new driver we're going to leave the + * watchdog enabled. Later we may try to turn it off and see + * whether we run into any problems. + */ + + return ret; +} + +static const struct hc_driver ehci_tilegx_hc_driver = { + .description = hcd_name, + .product_desc = "Tile-Gx EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * Generic hardware linkage. + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * Basic lifecycle operations. + */ + .reset = tilegx_ehci_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * Managing I/O requests and associated device resources. + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * Scheduling support. + */ + .get_frame_number = ehci_get_frame, + + /* + * Root hub support. + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + pte_t pte = { 0 }; + int my_cpu = smp_processor_id(); + int ret; + + if (usb_disabled()) + return -ENODEV; + + /* + * Try to initialize our GXIO context; if we can't, the device + * doesn't exist. + */ + if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 1) != 0) + return -ENXIO; + + hcd = usb_create_hcd(&ehci_tilegx_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) + return -ENOMEM; + + /* + * We don't use rsrc_start to map in our registers, but seems like + * we ought to set it to something, so we use the register VA. + */ + hcd->rsrc_start = + (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); + hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); + hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); + + tilegx_start_ehc(); + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + ehci->regs = + hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl(&ehci->caps->hcs_params); + + /* Create our IRQs and register them. */ + pdata->irq = create_irq(); + if (pdata->irq < 0) { + ret = -ENXIO; + goto err_no_irq; + } + + tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); + + /* Configure interrupts. */ + ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, + cpu_x(my_cpu), cpu_y(my_cpu), + KERNEL_PL, pdata->irq); + if (ret) { + ret = -ENXIO; + goto err_have_irq; + } + + /* Register all of our memory. */ + pte = pte_set_home(pte, PAGE_HOME_HASH); + ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); + if (ret) { + ret = -ENXIO; + goto err_have_irq; + } + + ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); + if (ret == 0) { + platform_set_drvdata(pdev, hcd); + return ret; + } + +err_have_irq: + destroy_irq(pdata->irq); +err_no_irq: + tilegx_stop_ehc(); + usb_put_hcd(hcd); + gxio_usb_host_destroy(&pdata->usb_ctx); + return ret; +} + +static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + tilegx_stop_ehc(); + gxio_usb_host_destroy(&pdata->usb_ctx); + destroy_irq(pdata->irq); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void ehci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) +{ + usb_hcd_platform_shutdown(pdev); + ehci_hcd_tilegx_drv_remove(pdev); +} + +static struct platform_driver ehci_hcd_tilegx_driver = { + .probe = ehci_hcd_tilegx_drv_probe, + .remove = ehci_hcd_tilegx_drv_remove, + .shutdown = ehci_hcd_tilegx_drv_shutdown, + .driver = { + .name = "tilegx-ehci", + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:tilegx-ehci"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index e0adf5c0cf5..2b1e8d84c87 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1100,6 +1100,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_octeon_driver #endif +#ifdef CONFIG_TILE_USB +#include "ohci-tilegx.c" +#define PLATFORM_DRIVER ohci_hcd_tilegx_driver +#endif + #ifdef CONFIG_USB_CNS3XXX_OHCI #include "ohci-cns3xxx.c" #define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 9ce35d0d9d5..b02c344e2cc 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -20,14 +20,15 @@ #include <linux/clk.h> #include <linux/gpio.h> -#include <mach/hardware.h> #include <asm/io.h> #include <asm/mach-types.h> #include <plat/mux.h> -#include <mach/irqs.h> #include <plat/fpga.h> -#include <plat/usb.h> + +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/usb.h> /* OMAP-1510 OHCI has its own MMU for DMA */ diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c new file mode 100644 index 00000000000..1ae7b28a71c --- /dev/null +++ b/drivers/usb/host/ohci-tilegx.c @@ -0,0 +1,203 @@ +/* + * Copyright 2012 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +/* + * Tilera TILE-Gx USB OHCI host controller driver. + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/usb/tilegx.h> +#include <linux/usb.h> + +#include <asm/homecache.h> + +#include <gxio/iorpc_usb_host.h> +#include <gxio/usb_host.h> + +static void tilegx_start_ohc(void) +{ +} + +static void tilegx_stop_ohc(void) +{ +} + +static int tilegx_ohci_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_init(ohci); + if (ret < 0) + return ret; + + ret = ohci_run(ohci); + if (ret < 0) { + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_tilegx_hc_driver = { + .description = hcd_name, + .product_desc = "Tile-Gx OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * Generic hardware linkage. + */ + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_LOCAL_MEM | HCD_USB11, + + /* + * Basic lifecycle operations. + */ + .start = tilegx_ohci_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_hub_control, + .start_port_reset = ohci_start_port_reset, +}; + +static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data; + pte_t pte = { 0 }; + int my_cpu = smp_processor_id(); + int ret; + + if (usb_disabled()) + return -ENODEV; + + /* + * Try to initialize our GXIO context; if we can't, the device + * doesn't exist. + */ + if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 0) != 0) + return -ENXIO; + + hcd = usb_create_hcd(&ohci_tilegx_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) + return -ENOMEM; + + /* + * We don't use rsrc_start to map in our registers, but seems like + * we ought to set it to something, so we use the register VA. + */ + hcd->rsrc_start = + (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); + hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); + hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); + + tilegx_start_ohc(); + + /* Create our IRQs and register them. */ + pdata->irq = create_irq(); + if (pdata->irq < 0) { + ret = -ENXIO; + goto err_no_irq; + } + + tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); + + /* Configure interrupts. */ + ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, + cpu_x(my_cpu), cpu_y(my_cpu), + KERNEL_PL, pdata->irq); + if (ret) { + ret = -ENXIO; + goto err_have_irq; + } + + /* Register all of our memory. */ + pte = pte_set_home(pte, PAGE_HOME_HASH); + ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); + if (ret) { + ret = -ENXIO; + goto err_have_irq; + } + + ohci_hcd_init(hcd_to_ohci(hcd)); + + ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); + if (ret == 0) { + platform_set_drvdata(pdev, hcd); + return ret; + } + +err_have_irq: + destroy_irq(pdata->irq); +err_no_irq: + tilegx_stop_ohc(); + usb_put_hcd(hcd); + gxio_usb_host_destroy(&pdata->usb_ctx); + return ret; +} + +static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data; + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); + tilegx_stop_ohc(); + gxio_usb_host_destroy(&pdata->usb_ctx); + destroy_irq(pdata->irq); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void ohci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) +{ + usb_hcd_platform_shutdown(pdev); + ohci_hcd_tilegx_drv_remove(pdev); +} + +static struct platform_driver ohci_hcd_tilegx_driver = { + .probe = ohci_hcd_tilegx_drv_probe, + .remove = ohci_hcd_tilegx_drv_remove, + .shutdown = ohci_hcd_tilegx_drv_shutdown, + .driver = { + .name = "tilegx-ohci", + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:tilegx-ohci"); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 2732ef660c5..7b01094d799 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, } } +/* Updates Link Status for super Speed port */ +static void xhci_hub_report_link_state(u32 *status, u32 status_reg) +{ + u32 pls = status_reg & PORT_PLS_MASK; + + /* resume state is a xHCI internal state. + * Do not report it to usb core. + */ + if (pls == XDEV_RESUME) + return; + + /* When the CAS bit is set then warm reset + * should be performed on port + */ + if (status_reg & PORT_CAS) { + /* The CAS bit can be set while the port is + * in any link state. + * Only roothubs have CAS bit, so we + * pretend to be in compliance mode + * unless we're already in compliance + * or the inactive state. + */ + if (pls != USB_SS_PORT_LS_COMP_MOD && + pls != USB_SS_PORT_LS_SS_INACTIVE) { + pls = USB_SS_PORT_LS_COMP_MOD; + } + /* Return also connection bit - + * hub state machine resets port + * when this bit is set. + */ + pls |= USB_PORT_STAT_CONNECTION; + } + /* update status field */ + *status |= pls; +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, else status |= USB_PORT_STAT_POWER; } - /* Port Link State */ + /* Update Port Link State for super speed ports*/ if (hcd->speed == HCD_USB3) { - /* resume state is a xHCI internal state. - * Do not report it to usb core. - */ - if ((temp & PORT_PLS_MASK) != XDEV_RESUME) - status |= (temp & PORT_PLS_MASK); + xhci_hub_report_link_state(&status, temp); } if (bus_state->port_c_suspend & (1 << wIndex)) status |= 1 << USB_PORT_FEAT_C_SUSPEND; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 23b4aefd103..8275645889d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, num_trbs_free_temp = ep_ring->num_trbs_free; dequeue_temp = ep_ring->dequeue; + /* If we get two back-to-back stalls, and the first stalled transfer + * ends just before a link TRB, the dequeue pointer will be left on + * the link TRB by the code in the while loop. So we have to update + * the dequeue pointer one segment further, or we'll jump off + * the segment into la-la-land. + */ + if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { + ep_ring->deq_seg = ep_ring->deq_seg->next; + ep_ring->dequeue = ep_ring->deq_seg->trbs; + } + while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { /* We have more usable TRBs */ ep_ring->num_trbs_free++; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index de3d6e3e57b..55c0785810c 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -341,7 +341,11 @@ struct xhci_op_regs { #define PORT_PLC (1 << 22) /* port configure error change - port failed to configure its link partner */ #define PORT_CEC (1 << 23) -/* bit 24 reserved */ +/* Cold Attach Status - xHC can set this bit to report device attached during + * Sx state. Warm port reset should be perfomed to clear this bit and move port + * to connected state. + */ +#define PORT_CAS (1 << 24) /* wake on connect (enable) */ #define PORT_WKCONN_E (1 << 25) /* wake on disconnect (enable) */ diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index 70cf5d7bca4..e0558dfcfaf 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c @@ -36,9 +36,9 @@ #include <asm/irq.h> #include <asm/mach-types.h> -#include <plat/usb.h> #include <plat/mux.h> +#include <mach/usb.h> #ifndef DEBUG #undef VERBOSE diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index a165490bae4..8c9bb1ad306 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -19,7 +19,7 @@ #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/sysfs.h> -#include "./common.h" +#include "common.h" /* * image of renesas_usbhs diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 3f3ccd35875..dddf40a59de 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -22,8 +22,8 @@ struct usbhs_priv; -#include "./mod.h" -#include "./pipe.h" +#include "mod.h" +#include "pipe.h" /* * diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 6ec7f838d7f..30b757a3f59 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -17,8 +17,8 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/scatterlist.h> -#include "./common.h" -#include "./pipe.h" +#include "common.h" +#include "pipe.h" #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) #define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) @@ -994,7 +994,7 @@ static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) * * usbhs doesn't recognize id = 0 as valid DMA */ - if (0 == slave->slave_id) + if (0 == slave->shdma_slave.slave_id) return false; chan->private = slave; @@ -1173,8 +1173,8 @@ int usbhs_fifo_probe(struct usbhs_priv *priv) fifo->port = D0FIFO; fifo->sel = D0FIFOSEL; fifo->ctr = D0FIFOCTR; - fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); - fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); + fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); + fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); /* D1FIFO */ fifo = usbhsf_get_d1fifo(priv); @@ -1182,8 +1182,8 @@ int usbhs_fifo_probe(struct usbhs_priv *priv) fifo->port = D1FIFO; fifo->sel = D1FIFOSEL; fifo->ctr = D1FIFOCTR; - fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); - fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); + fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); + fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); return 0; } diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 0871e816df4..82a628f96c0 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -16,8 +16,8 @@ */ #include <linux/interrupt.h> -#include "./common.h" -#include "./mod.h" +#include "common.h" +#include "mod.h" #define usbhs_priv_to_modinfo(priv) (&priv->mod_info) #define usbhs_mod_info_call(priv, func, param...) \ diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h index 6c6875533f0..1ef5bf60407 100644 --- a/drivers/usb/renesas_usbhs/mod.h +++ b/drivers/usb/renesas_usbhs/mod.h @@ -19,7 +19,7 @@ #include <linux/spinlock.h> #include <linux/usb/renesas_usbhs.h> -#include "./common.h" +#include "common.h" /* * struct diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index feb06d6d281..122526cfd32 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -16,8 +16,8 @@ */ #include <linux/delay.h> #include <linux/slab.h> -#include "./common.h" -#include "./pipe.h" +#include "common.h" +#include "pipe.h" /* * macros diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index fa18b7dc2b2..08786c06dcf 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -17,8 +17,8 @@ #ifndef RENESAS_USB_PIPE_H #define RENESAS_USB_PIPE_H -#include "./common.h" -#include "./fifo.h" +#include "common.h" +#include "fifo.h" /* * struct diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 81423f7361d..d47eb06fe46 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) metro_priv->throttled = 0; spin_unlock_irqrestore(&metro_priv->lock, flags); - /* - * Force low_latency on so that our tty_push actually forces the data - * through, otherwise it is scheduled, and with high data rates (like - * with OHCI) data can get lost. - */ - if (tty) - tty->low_latency = 1; - /* Clear the urb pipe. */ usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index adf8ce72be5..417ab1b0aa3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb); /* MediaTek products */ #define MEDIATEK_VENDOR_ID 0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 +#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM 0x7101 +#define MEDIATEK_PRODUCT_7208_2COM 0x7102 +#define MEDIATEK_PRODUCT_FP_1COM 0x0003 +#define MEDIATEK_PRODUCT_FP_2COM 0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 /* Cellient products */ #define CELLIENT_VENDOR_ID 0x2692 @@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = { .reserved = BIT(1), }; +static const struct option_blacklist_info net_intf2_blacklist = { + .reserved = BIT(2), +}; + static const struct option_blacklist_info net_intf3_blacklist = { .reserved = BIT(3), }; @@ -1099,6 +1112,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, @@ -1240,6 +1255,17 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 11418da9bc0..a3d54366afc 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -236,6 +236,11 @@ static int slave_configure(struct scsi_device *sdev) US_FL_SCM_MULT_TARG)) && us->protocol == USB_PR_BULK) us->use_last_sector_hacks = 1; + + /* Check if write cache default on flag is set or not */ + if (us->fflags & US_FL_WRITE_CACHE) + sdev->wce_default_on = 1; + } else { /* Non-disk-type devices don't need to blacklist any pages diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 1719886bb9b..62a31bea063 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1267,6 +1267,12 @@ UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000, USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0 ), +/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */ +UNUSUAL_DEV(0x0bc2, 0x2300, 0x0000, 0x9999, + "Seagate", + "Portable HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE), + /* Reported by Ben Efros <ben@pc-doctor.com> */ UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000, "Seagate", @@ -1468,6 +1474,12 @@ UNUSUAL_DEV( 0x1058, 0x0704, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE), +/* Reported by Namjae Jeon <namjae.jeon@samsung.com> */ +UNUSUAL_DEV(0x1058, 0x070a, 0x0000, 0x9999, + "Western Digital", + "My Passport HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_WRITE_CACHE), + /* Reported by Fabio Venturi <f.venturi@tdnet.it> * The device reports a vendor-specific bDeviceClass. */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index e23c30ab66d..d012fe4329e 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -473,7 +473,7 @@ static void adjust_quirks(struct us_data *us) US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT | US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | - US_FL_INITIAL_READ10); + US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE); p = quirks; while (*p) { @@ -529,6 +529,9 @@ static void adjust_quirks(struct us_data *us) case 'o': f |= US_FL_CAPACITY_OK; break; + case 'p': + f |= US_FL_WRITE_CACHE; + break; case 'r': f |= US_FL_IGNORE_RESIDUE; break; |