From 4d175f340c9c055482688d2205038413dc7b6f1e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 11 Aug 2013 15:26:04 +0100 Subject: usb: phy: nop: Defer clock prepare until PHY init Since we only enable the PHY clock on init and the PHY init and shutdown does not occur in atomitc context there is no need to prepare the clock before it is enabled. Move the clk_prepare() operations to go along with the enables, allowing the clock to be fully idle when not in use. Signed-off-by: Mark Brown Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 5 ++--- drivers/usb/phy/phy-generic.c | 24 +++--------------------- drivers/usb/phy/phy-generic.h | 1 - 3 files changed, 5 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index c4d614d1f173..f836dc68104c 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -59,15 +59,14 @@ static int am335x_phy_probe(struct platform_device *pdev) ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy); if (ret) - goto err_add; + return ret; am_phy->usb_phy_gen.phy.init = am335x_init; am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown; platform_set_drvdata(pdev, am_phy); + return 0; -err_add: - usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen); return ret; } diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index efe59f3f7fda..fcc31045fda7 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -74,7 +74,7 @@ int usb_gen_phy_init(struct usb_phy *phy) } if (!IS_ERR(nop->clk)) - clk_enable(nop->clk); + clk_prepare_enable(nop->clk); if (!IS_ERR(nop->reset)) { /* De-assert RESET */ @@ -97,7 +97,7 @@ void usb_gen_phy_shutdown(struct usb_phy *phy) } if (!IS_ERR(nop->clk)) - clk_disable(nop->clk); + clk_disable_unprepare(nop->clk); if (!IS_ERR(nop->vcc)) { if (regulator_disable(nop->vcc)) @@ -160,14 +160,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, } } - if (!IS_ERR(nop->clk)) { - err = clk_prepare(nop->clk); - if (err) { - dev_err(dev, "Error preparing clock\n"); - return err; - } - } - nop->vcc = devm_regulator_get(dev, "vcc"); if (IS_ERR(nop->vcc)) { dev_dbg(dev, "Error getting vcc regulator: %ld\n", @@ -200,13 +192,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, } EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); -void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) -{ - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); -} -EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); - static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -252,15 +237,13 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", err); - goto err_add; + return err; } platform_set_drvdata(pdev, nop); return 0; -err_add: - usb_phy_gen_cleanup_phy(nop); return err; } @@ -268,7 +251,6 @@ static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) { struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); - usb_phy_gen_cleanup_phy(nop); usb_remove_phy(&nop->phy); return 0; diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index 61687d5a965b..386d11b375aa 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -15,6 +15,5 @@ void usb_gen_phy_shutdown(struct usb_phy *phy); int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, enum usb_phy_type type, u32 clk_rate, bool needs_vcc, bool needs_reset); -void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop); #endif -- cgit v1.2.3 From a12226394e7d19734d129766676a5668efd50d5c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 19 Aug 2013 12:39:44 +0200 Subject: usb: phy: am335x: add wakeup support This is based on George Cherian's patch which added power & wakeup support to am335x and does no longer apply since I took some if the code apart in favor of the multi instance support. This compiles and I boots and later it detects a device after I plug it in :) Could somebody please test it so it does what it should? Cc: George Cherian Reviewed-by: Roger Quadros Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x-control.c | 42 ++++++++++++++++++++++++++++++++++++ drivers/usb/phy/phy-am335x.c | 35 ++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 22cf07d62e4c..0fac976b63b5 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -26,6 +26,41 @@ struct am335x_control_usb { #define USBPHY_OTGVDET_EN (1 << 19) #define USBPHY_OTGSESSEND_EN (1 << 20) +#define AM335X_PHY0_WK_EN (1 << 0) +#define AM335X_PHY1_WK_EN (1 << 8) + +static void am335x_phy_wkup(struct phy_control *phy_ctrl, u32 id, bool on) +{ + struct am335x_control_usb *usb_ctrl; + u32 val; + u32 reg; + + usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + + switch (id) { + case 0: + reg = AM335X_PHY0_WK_EN; + break; + case 1: + reg = AM335X_PHY1_WK_EN; + break; + default: + WARN_ON(1); + return; + } + + spin_lock(&usb_ctrl->lock); + val = readl(usb_ctrl->wkup); + + if (on) + val |= reg; + else + val &= ~reg; + + writel(val, usb_ctrl->wkup); + spin_unlock(&usb_ctrl->lock); +} + static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) { struct am335x_control_usb *usb_ctrl; @@ -59,6 +94,7 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on) static const struct phy_control ctrl_am335x = { .phy_power = am335x_phy_power, + .phy_wkup = am335x_phy_wkup, }; static const struct of_device_id omap_control_usb_id_table[] = { @@ -117,6 +153,12 @@ static int am335x_control_usb_probe(struct platform_device *pdev) ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ctrl_usb->phy_reg)) return PTR_ERR(ctrl_usb->phy_reg); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wakeup"); + ctrl_usb->wkup = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ctrl_usb->wkup)) + return PTR_ERR(ctrl_usb->wkup); + spin_lock_init(&ctrl_usb->lock); ctrl_usb->phy_ctrl = *phy_ctrl; diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index f836dc68104c..f3478a856edb 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -78,6 +78,40 @@ static int am335x_phy_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_RUNTIME + +static int am335x_phy_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct am335x_phy *am_phy = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) + phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true); + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); + return 0; +} + +static int am335x_phy_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct am335x_phy *am_phy = platform_get_drvdata(pdev); + + phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + if (device_may_wakeup(dev)) + phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false); + return 0; +} + +static const struct dev_pm_ops am335x_pm_ops = { + SET_RUNTIME_PM_OPS(am335x_phy_runtime_suspend, + am335x_phy_runtime_resume, NULL) +}; + +#define DEV_PM_OPS (&am335x_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + static const struct of_device_id am335x_phy_ids[] = { { .compatible = "ti,am335x-usb-phy" }, { } @@ -90,6 +124,7 @@ static struct platform_driver am335x_phy_driver = { .driver = { .name = "am335x-phy-driver", .owner = THIS_MODULE, + .pm = DEV_PM_OPS, .of_match_table = of_match_ptr(am335x_phy_ids), }, }; -- cgit v1.2.3 From 1860c925f87b826925fdff57eedd938f1bd1f43b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 6 Sep 2013 18:09:06 +0200 Subject: usb: musb: name ux500 platforms more broadly The Kconfig help text is talking about the U5500 which is no longer supported by the kernel. Name the help text after the config symbol which is more correct. Signed-off-by: Linus Walleij Signed-off-by: Felipe Balbi --- drivers/usb/musb/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index c258a97ef1b0..0fc5bc371940 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -90,7 +90,7 @@ config USB_MUSB_BLACKFIN depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) config USB_MUSB_UX500 - tristate "U8500 and U5500" + tristate "Ux500 platforms" endchoice @@ -112,7 +112,7 @@ choice allow using DMA on multiplatform kernels. config USB_UX500_DMA - bool 'ST Ericsson U8500 and U5500' + bool 'ST Ericsson Ux500' depends on USB_MUSB_UX500 help Enable DMA transfers on UX500 platforms. -- cgit v1.2.3 From 80d2e76c2e162264dff1c5107a31b8d99e816cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 18 Sep 2013 19:03:33 +0200 Subject: usb: musb: Add missing ATOMIC_INIT_NOTIFIER_HEAD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit &twl->phy.notifier is not initalized Signed-off-by: Pali Rohár Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-twl4030-usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c index 90730c8762b8..5baa9c7267f4 100644 --- a/drivers/usb/phy/phy-twl4030-usb.c +++ b/drivers/usb/phy/phy-twl4030-usb.c @@ -705,6 +705,8 @@ static int twl4030_usb_probe(struct platform_device *pdev) if (device_create_file(&pdev->dev, &dev_attr_vbus)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); + /* Our job is to use irqs and status from the power module * to keep the transceiver disabled when nothing's connected. * -- cgit v1.2.3 From 6fa7178ce72764a564b5f5b7d2826d3697b89e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 18 Sep 2013 19:03:34 +0200 Subject: usb: musb: Call atomic_notifier_call_chain when status is changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More power supply drivers depends on vbus events and without it they not working. Power supply drivers using usb_register_notifier, so to deliver events it is needed to call atomic_notifier_call_chain. So without atomic notifier power supply driver isp1704 not retrieving vbus status and reporting bogus values to userspace and also to board platform data functions. Without proper data charger drivers trying to charge battery also when charger is disconnected or do not start charging when wallcharger connects. Atomic notifier in musb driver was used before v3.5 and was replaced with omap mailbox. This patch adding atomic_notifier_call_chain call from function omap_musb_set_mailbox. Signed-off-by: Pali Rohár Signed-off-by: Felipe Balbi --- drivers/usb/musb/omap2430.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 59d2245db1c8..cefafdcbe3a6 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -305,6 +305,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) default: dev_dbg(dev, "ID float\n"); } + + atomic_notifier_call_chain(&musb->xceiv->notifier, + musb->xceiv->last_event, NULL); } -- cgit v1.2.3 From 36ed03f7796a6695ee1b6c4893ef022328a50e70 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 9 Sep 2013 16:48:29 +0800 Subject: usb: gadget: zero: Add flexible auto remote wakeup test method In order to increase test coverage, we can change the interval between two remote wakeups every time, and the interval can be any user defined value. This change will no affect current behavior if the user does not use two introduced module paramters. Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/zero.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0deb9d6cde26..0dd07ae1555d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -95,6 +95,18 @@ unsigned autoresume = DEFAULT_AUTORESUME; module_param(autoresume, uint, S_IRUGO); MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); +/* Maximum Autoresume time */ +unsigned max_autoresume; +module_param(max_autoresume, uint, S_IRUGO); +MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup"); + +/* Interval between two remote wakeups */ +unsigned autoresume_interval_ms; +module_param(autoresume_interval_ms, uint, S_IRUGO); +MODULE_PARM_DESC(autoresume_interval_ms, + "milliseconds to increase successive wakeup delays"); + +static unsigned autoresume_step_ms; /*-------------------------------------------------------------------------*/ static struct usb_device_descriptor device_desc = { @@ -183,8 +195,16 @@ static void zero_suspend(struct usb_composite_dev *cdev) return; if (autoresume) { - mod_timer(&autoresume_timer, jiffies + (HZ * autoresume)); - DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume); + if (max_autoresume && + (autoresume_step_ms > max_autoresume * 1000)) + autoresume_step_ms = autoresume * 1000; + + mod_timer(&autoresume_timer, jiffies + + msecs_to_jiffies(autoresume_step_ms)); + DBG(cdev, "suspend, wakeup in %d milliseconds\n", + autoresume_step_ms); + + autoresume_step_ms += autoresume_interval_ms; } else DBG(cdev, "%s\n", __func__); } @@ -316,6 +336,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) if (autoresume) { sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + autoresume_step_ms = autoresume * 1000; } /* support OTG systems */ -- cgit v1.2.3 From 88200995ecf35c126374376ac4c39bc32dfe6fa4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 12 Sep 2013 15:25:44 +0900 Subject: usb: gadget: amd5536udc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/amd5536udc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index a9a4346c83aa..54a1e2954cea 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -3078,8 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev) if (dev->active) pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - udc_remove(dev); } -- cgit v1.2.3 From 1f0186305b08f61e62383fdb11dfb6dfd45ebc1f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 12 Sep 2013 15:27:09 +0900 Subject: usb: gadget: goku_udc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/goku_udc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index c64deb9e3d62..74bb8df82876 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1701,7 +1701,6 @@ static void goku_remove(struct pci_dev *pdev) if (dev->enabled) pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); dev->regs = NULL; INFO(dev, "unbind\n"); -- cgit v1.2.3 From 42ab3d24f8f5ee3b2f5b9f353fd51aa5a5372fbd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 12 Sep 2013 15:27:58 +0900 Subject: usb: gadget: pch_udc: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/pch_udc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 24174e1d1564..32d5e923750b 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -3080,7 +3080,6 @@ static void pch_udc_remove(struct pci_dev *pdev) if (dev->active) pci_disable_device(pdev); kfree(dev); - pci_set_drvdata(pdev, NULL); } #ifdef CONFIG_PM -- cgit v1.2.3 From d1d7e3f537d3cddc79f51c2f0285991446fb6837 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 12 Sep 2013 15:28:45 +0900 Subject: usb: gadget: net2280: remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Felipe Balbi --- drivers/usb/gadget/net2280.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0781bff70015..9fbc8fe5ecc0 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2680,7 +2680,6 @@ static void net2280_remove (struct pci_dev *pdev) if (dev->enabled) pci_disable_device (pdev); device_remove_file (&pdev->dev, &dev_attr_registers); - pci_set_drvdata (pdev, NULL); INFO (dev, "unbind\n"); } -- cgit v1.2.3 From af3848757204a16670d7da94f72beb45564955cc Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 20 Sep 2013 00:14:38 +0100 Subject: usb: musb: use platform_device_register_full() to avoid directly messing with dma masks Use platform_device_register_full() for those drivers which can, to avoid messing directly with DMA masks. This can only be done when the driver does not need to access the allocated musb platform device from within its callbacks, which may be called during the musb device probing. Signed-off-by: Russell King Signed-off-by: Felipe Balbi --- drivers/usb/musb/am35x.c | 50 +++++++++++++++------------------------------ drivers/usb/musb/da8xx.c | 49 +++++++++++++++----------------------------- drivers/usb/musb/davinci.c | 48 +++++++++++++++---------------------------- drivers/usb/musb/tusb6010.c | 49 +++++++++++++++----------------------------- 4 files changed, 68 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 5c310c664218..790b22b296b1 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -89,7 +89,6 @@ struct am35x_glue { struct clk *phy_clk; struct clk *clk; }; -#define glue_to_musb(g) platform_get_drvdata(g->musb) /* * am35x_musb_enable - enable interrupts @@ -452,14 +451,18 @@ static const struct musb_platform_ops am35x_ops = { .set_vbus = am35x_musb_set_vbus, }; -static u64 am35x_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info am35x_dev_info = { + .name = "musb-hdrc", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; static int am35x_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct am35x_glue *glue; - + struct platform_device_info pinfo; struct clk *phy_clk; struct clk *clk; @@ -471,12 +474,6 @@ static int am35x_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - phy_clk = clk_get(&pdev->dev, "fck"); if (IS_ERR(phy_clk)) { dev_err(&pdev->dev, "failed to get PHY clock\n"); @@ -503,12 +500,7 @@ static int am35x_probe(struct platform_device *pdev) goto err6; } - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &am35x_dmamask; - musb->dev.coherent_dma_mask = am35x_dmamask; - glue->dev = &pdev->dev; - glue->musb = musb; glue->phy_clk = phy_clk; glue->clk = clk; @@ -516,22 +508,17 @@ static int am35x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, glue); - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err7; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err7; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); + pinfo = am35x_dev_info; + pinfo.parent = &pdev->dev; + pinfo.res = pdev->resource; + pinfo.num_res = pdev->num_resources; + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + + glue->musb = musb = platform_device_register_full(&pinfo); + if (IS_ERR(musb)) { + ret = PTR_ERR(musb); + dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); goto err7; } @@ -550,9 +537,6 @@ err4: clk_put(phy_clk); err3: - platform_device_put(musb); - -err1: kfree(glue); err0: diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d9ddf4122f37..2f2c1cb36421 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -472,7 +472,11 @@ static const struct musb_platform_ops da8xx_ops = { .set_vbus = da8xx_musb_set_vbus, }; -static u64 da8xx_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info da8xx_dev_info = { + .name = "musb-hdrc", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; static int da8xx_probe(struct platform_device *pdev) { @@ -480,7 +484,7 @@ static int da8xx_probe(struct platform_device *pdev) struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct da8xx_glue *glue; - + struct platform_device_info pinfo; struct clk *clk; int ret = -ENOMEM; @@ -491,12 +495,6 @@ static int da8xx_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - clk = clk_get(&pdev->dev, "usb20"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); @@ -510,12 +508,7 @@ static int da8xx_probe(struct platform_device *pdev) goto err4; } - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &da8xx_dmamask; - musb->dev.coherent_dma_mask = da8xx_dmamask; - glue->dev = &pdev->dev; - glue->musb = musb; glue->clk = clk; pdata->platform_ops = &da8xx_ops; @@ -535,22 +528,17 @@ static int da8xx_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; - ret = platform_device_add_resources(musb, musb_resources, - ARRAY_SIZE(musb_resources)); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err5; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err5; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); + pinfo = da8xx_dev_info; + pinfo.parent = &pdev->dev; + pinfo.res = musb_resources; + pinfo.num_res = ARRAY_SIZE(musb_resources); + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + + glue->musb = musb = platform_device_register_full(&pinfo); + if (IS_ERR(musb)) { + ret = PTR_ERR(musb); + dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); goto err5; } @@ -563,9 +551,6 @@ err4: clk_put(clk); err3: - platform_device_put(musb); - -err1: kfree(glue); err0: diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index ed0834e2b72e..45aae0bbb8df 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -505,7 +505,11 @@ static const struct musb_platform_ops davinci_ops = { .set_vbus = davinci_musb_set_vbus, }; -static u64 davinci_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info davinci_dev_info = { + .name = "musb-hdrc", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; static int davinci_probe(struct platform_device *pdev) { @@ -513,6 +517,7 @@ static int davinci_probe(struct platform_device *pdev) struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct davinci_glue *glue; + struct platform_device_info pinfo; struct clk *clk; int ret = -ENOMEM; @@ -523,12 +528,6 @@ static int davinci_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - clk = clk_get(&pdev->dev, "usb"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); @@ -542,12 +541,7 @@ static int davinci_probe(struct platform_device *pdev) goto err4; } - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &davinci_dmamask; - musb->dev.coherent_dma_mask = davinci_dmamask; - glue->dev = &pdev->dev; - glue->musb = musb; glue->clk = clk; pdata->platform_ops = &davinci_ops; @@ -567,22 +561,17 @@ static int davinci_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; - ret = platform_device_add_resources(musb, musb_resources, - ARRAY_SIZE(musb_resources)); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err5; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err5; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); + pinfo = davinci_dev_info; + pinfo.parent = &pdev->dev; + pinfo.res = musb_resources; + pinfo.num_res = ARRAY_SIZE(musb_resources); + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + + glue->musb = musb = platform_device_register_full(&pinfo); + if (IS_ERR(musb)) { + ret = PTR_ERR(musb); + dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); goto err5; } @@ -595,9 +584,6 @@ err4: clk_put(clk); err3: - platform_device_put(musb); - -err1: kfree(glue); err0: diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index b3b3ed723882..4432314d70ee 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1152,7 +1152,11 @@ static const struct musb_platform_ops tusb_ops = { .set_vbus = tusb_musb_set_vbus, }; -static u64 tusb_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info tusb_dev_info = { + .name = "musb-hdrc", + .id = PLATFORM_DEVID_AUTO, + .dma_mask = DMA_BIT_MASK(32), +}; static int tusb_probe(struct platform_device *pdev) { @@ -1160,7 +1164,7 @@ static int tusb_probe(struct platform_device *pdev) struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct tusb6010_glue *glue; - + struct platform_device_info pinfo; int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -1169,18 +1173,7 @@ static int tusb_probe(struct platform_device *pdev) goto err0; } - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &tusb_dmamask; - musb->dev.coherent_dma_mask = tusb_dmamask; - glue->dev = &pdev->dev; - glue->musb = musb; pdata->platform_ops = &tusb_ops; @@ -1204,31 +1197,23 @@ static int tusb_probe(struct platform_device *pdev) musb_resources[2].end = pdev->resource[2].end; musb_resources[2].flags = pdev->resource[2].flags; - ret = platform_device_add_resources(musb, musb_resources, - ARRAY_SIZE(musb_resources)); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err3; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err3; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); + pinfo = tusb_dev_info; + pinfo.parent = &pdev->dev; + pinfo.res = musb_resources; + pinfo.num_res = ARRAY_SIZE(musb_resources); + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + + glue->musb = musb = platform_device_register_full(&pinfo); + if (IS_ERR(musb)) { + ret = PTR_ERR(musb); + dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); goto err3; } return 0; err3: - platform_device_put(musb); - -err1: kfree(glue); err0: -- cgit v1.2.3 From 161bfa98ba6f5b8970234e4392de1f5df4062452 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 20 Sep 2013 15:16:34 +0530 Subject: usb: dwc3: Remove redundant pci_set_drvdata Driver core sets driver data to NULL upon failure or remove. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 2e252aae51ca..31443aeedcdb 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -165,7 +165,6 @@ static int dwc3_pci_probe(struct pci_dev *pci, return 0; err3: - pci_set_drvdata(pci, NULL); platform_device_put(dwc3); err1: pci_disable_device(pci); @@ -180,7 +179,6 @@ static void dwc3_pci_remove(struct pci_dev *pci) platform_device_unregister(glue->dwc3); platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - pci_set_drvdata(pci, NULL); pci_disable_device(pci); } -- cgit v1.2.3 From f51a08da6d1d591c021c1aa0ee6dd23f7caf3639 Mon Sep 17 00:00:00 2001 From: Valentin Ilie Date: Sat, 21 Sep 2013 12:30:15 +0300 Subject: usb: gadget: mv_u3d_core: fix memory leaks When trb_hw is NULL, trb should be free'd before return. Signed-off-by: Valentin Ilie Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_u3d_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index 561b30efb8ee..4d31177d5d99 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -310,6 +310,7 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req, */ trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma); if (!trb_hw) { + kfree(trb); dev_err(u3d->dev, "%s, dma_pool_alloc fail\n", __func__); return NULL; @@ -454,6 +455,7 @@ static int mv_u3d_req_to_trb(struct mv_u3d_req *req) trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC); if (!trb_hw) { + kfree(trb); dev_err(u3d->dev, "%s, trb_hw alloc fail\n", __func__); return -ENOMEM; -- cgit v1.2.3 From d9681ee0812a7502838032bc5f935c2af650b036 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Mon, 23 Sep 2013 09:08:28 +0530 Subject: usb: dwc3: Remove additional delay of 100ms when resuming This delay got introduced in: "7415f17 usb: dwc3: core: add power management support" which reflected similar code in dwc3_core_soft_reset() function. However, originally the delay of 100ms in dwc3_core_soft_reset() was meant to assist USB2PHY and USB3PHY reset, not for usb_phy_init() sequence. We should get rid of this delay, since things will still work fine without this. Reviewed-by: Jingoo Han Signed-off-by: Vivek Gautam Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 474162e9d01d..e88ffae80cac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -691,7 +691,6 @@ static int dwc3_resume(struct device *dev) usb_phy_init(dwc->usb3_phy); usb_phy_init(dwc->usb2_phy); - msleep(100); spin_lock_irqsave(&dwc->lock, flags); -- cgit v1.2.3 From 77a3a0aa39da49499c4029ee8c4227dac362a076 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Tue, 24 Sep 2013 00:03:43 +0800 Subject: usb: usbtest: bmAttributes would better be masked When transfer type is isochronous, the other bits (bits 5..2) of bmAttributes in endpoint descriptor might not be set zero. So it's better to use usb_endpoint_type routine to mask bmAttributes with USB_ENDPOINT_XFERTYPE_MASK to judge the transfter type later. Acked-by: Alan Stern Signed-off-by: Huang Rui Signed-off-by: Felipe Balbi --- drivers/usb/misc/usbtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index aa28ac8c7607..3e91d3e98ee8 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -120,7 +120,7 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf) struct usb_host_endpoint *e; e = alt->endpoint + ep; - switch (e->desc.bmAttributes) { + switch (usb_endpoint_type(&e->desc)) { case USB_ENDPOINT_XFER_BULK: break; case USB_ENDPOINT_XFER_ISOC: -- cgit v1.2.3 From ea78201e2e08f8a91e30100c4c4a908b5cf295fc Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 22 Sep 2013 01:43:58 +0400 Subject: usb: musb: davinci: fix resources passed to MUSB driver for DM6467 After commit 09fc7d22b024692b2fe8a943b246de1af307132b (usb: musb: fix incorrect usage of resource pointer), CPPI DMA driver on DaVinci DM6467 can't detect its dedicated IRQ and so the MUSB IRQ is erroneously used instead. This is because only 2 resources are passed to the MUSB driver from the DaVinci glue layer, so fix this by always copying 3 resources (it's safe since a placeholder for the 3rd resource is always there) and passing 'pdev->num_resources' instead of the size of musb_resources[] to platform_device_add_resources(). Cc: # 3.11+ Signed-off-by: Sergei Shtylyov Signed-off-by: Felipe Balbi --- drivers/usb/musb/davinci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 45aae0bbb8df..1121fd741bf8 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -513,7 +513,7 @@ static const struct platform_device_info davinci_dev_info = { static int davinci_probe(struct platform_device *pdev) { - struct resource musb_resources[2]; + struct resource musb_resources[3]; struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); struct platform_device *musb; struct davinci_glue *glue; @@ -561,6 +561,15 @@ static int davinci_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; + /* + * For DM6467 3 resources are passed. A placeholder for the 3rd + * resource is always there, so it's safe to always copy it... + */ + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + pinfo = davinci_dev_info; pinfo.parent = &pdev->dev; pinfo.res = musb_resources; -- cgit v1.2.3 From a346941152878d8cab198fb10ba45dd706ed5ea1 Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Thu, 26 Sep 2013 15:55:25 +0800 Subject: usb: gadget: Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...)) trivial patch converting ERR_PTR(PTR_ERR()) into ERR_CAST(). No functional changes. Signed-off-by: Duan Jiong Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 8f0d6141e5e6..1bfacbfca1d8 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -557,7 +557,7 @@ static struct config_group *function_make( fi = usb_get_function_instance(func_name); if (IS_ERR(fi)) - return ERR_PTR(PTR_ERR(fi)); + return ERR_CAST(fi); ret = config_item_set_name(&fi->group.cg_item, name); if (ret) { -- cgit v1.2.3 From 092a4bd069fcca09f345a79c8abdc945cf6b1b57 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 26 Sep 2013 14:38:15 +0200 Subject: usb: gadget: configfs: add a method to unregister the gadget Add a method to unregister the gadget using its config_item. There can be functions (e.g. mass storage), which in some circumstances need the gadget stopped. Add a method of stopping the gadget. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 8 ++++++++ drivers/usb/gadget/configfs.h | 6 ++++++ 2 files changed, 14 insertions(+) create mode 100644 drivers/usb/gadget/configfs.h (limited to 'drivers') diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 1bfacbfca1d8..25885112fa35 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -991,6 +991,14 @@ static struct configfs_subsystem gadget_subsys = { .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex), }; +void unregister_gadget_item(struct config_item *item) +{ + struct gadget_info *gi = to_gadget_info(item); + + unregister_gadget(gi); +} +EXPORT_SYMBOL(unregister_gadget_item); + static int __init gadget_cfs_init(void) { int ret; diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h new file mode 100644 index 000000000000..a7b564a913d1 --- /dev/null +++ b/drivers/usb/gadget/configfs.h @@ -0,0 +1,6 @@ +#ifndef USB__GADGET__CONFIGFS__H +#define USB__GADGET__CONFIGFS__H + +void unregister_gadget_item(struct config_item *item); + +#endif /* USB__GADGET__CONFIGFS__H */ -- cgit v1.2.3 From 6fdc5dd25e0cd5afc114fe65427150c65f0eb67b Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 26 Sep 2013 14:38:16 +0200 Subject: usb: gadget: create a utility module for mass_storage Converting to configfs requires making the f_mass_storage.c a module. But first we need to get rid of "#include "storage_common.c". This patch makes storage_common.c a separately compiled file, which is built as a utility module named u_ms.ko. After all mass storage users are converted to the new function interface this module can be eliminated by merging it with the mass storage function's module. USB descriptors are exported so that they can be accessed from f_mass_storage. FSG_VENDOR_ID and FSG_PRODUCT_ID are moved to their only user. Handling of CONFIG_USB_GADGET_DEBUG_FILES is moved to f_mass_storage.c. The fsg_num_buffers static is moved to FSG_MODULE_PARAMETER users, so instead of using a global variable the f_mass_storage introduces fsg_num_buffers member in fsg_common (and fsg_config). fsg_strings and fsg_stringtab are moved to f_mass_storage.c. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 6 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/acm_ms.c | 17 +- drivers/usb/gadget/f_mass_storage.c | 106 ++++++++++-- drivers/usb/gadget/mass_storage.c | 25 ++- drivers/usb/gadget/multi.c | 17 +- drivers/usb/gadget/storage_common.c | 331 +++++++----------------------------- drivers/usb/gadget/storage_common.h | 210 +++++++++++++++++++++++ 8 files changed, 423 insertions(+), 291 deletions(-) create mode 100644 drivers/usb/gadget/storage_common.h (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 48cddf3cd6b8..98220dcca315 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -525,6 +525,9 @@ config USB_F_SUBSET config USB_F_RNDIS tristate +config USB_U_MS + tristate + choice tristate "USB Gadget Drivers" default USB_ETH @@ -878,6 +881,7 @@ config USB_MASS_STORAGE tristate "Mass Storage Gadget" depends on BLOCK select USB_LIBCOMPOSITE + select USB_U_MS help The Mass Storage Gadget acts as a USB Mass Storage disk drive. As its storage repository it can use a regular file or a block @@ -1001,6 +1005,7 @@ config USB_G_ACM_MS select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_F_ACM + select USB_U_MS help This driver provides two functions in one configuration: a mass storage, and a CDC ACM (serial port) link. @@ -1017,6 +1022,7 @@ config USB_G_MULTI select USB_U_ETHER select USB_U_RNDIS select USB_F_ACM + select USB_U_MS help The Multifunction Composite Gadget provides Ethernet (RNDIS and/or CDC Ethernet), mass storage and ACM serial link diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 386db9daf1d9..d90a0b079182 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -60,6 +60,8 @@ usb_f_ecm_subset-y := f_subset.o obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o usb_f_rndis-y := f_rndis.o obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o +u_ms-y := storage_common.o +obj-$(CONFIG_USB_U_MS) += u_ms.o # # USB gadget drivers diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 4b947bb50f62..992ffb00272f 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -104,6 +104,20 @@ static struct usb_gadget_strings *dev_strings[] = { /****************************** Configurations ******************************/ static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; @@ -167,7 +181,8 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) void *retp; /* set up mass storage function */ - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); + retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data, + fsg_num_buffers); if (IS_ERR(retp)) { status = PTR_ERR(retp); return PTR_ERR(retp); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index a01d7d38c016..def3426108b4 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -228,8 +228,18 @@ static const char fsg_string_interface[] = "Mass Storage"; -#include "storage_common.c" +#include "storage_common.h" +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +static struct usb_string fsg_strings[] = { + {FSG_STRING_INTERFACE, fsg_string_interface}, + {} +}; + +static struct usb_gadget_strings fsg_stringtab = { + .language = 0x0409, /* en-us */ + .strings = fsg_strings, +}; /*-------------------------------------------------------------------------*/ @@ -268,6 +278,7 @@ struct fsg_common { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; struct fsg_buffhd *buffhds; + unsigned int fsg_num_buffers; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -332,6 +343,7 @@ struct fsg_config { const char *product_name; /* 16 characters or less */ char can_stall; + unsigned int fsg_num_buffers; }; struct fsg_dev { @@ -2244,7 +2256,7 @@ reset: if (common->fsg) { fsg = common->fsg; - for (i = 0; i < fsg_num_buffers; ++i) { + for (i = 0; i < common->fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; if (bh->inreq) { @@ -2303,7 +2315,7 @@ reset: clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { + for (i = 0; i < common->fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2372,7 +2384,7 @@ static void handle_exception(struct fsg_common *common) /* Cancel all the pending transfers */ if (likely(common->fsg)) { - for (i = 0; i < fsg_num_buffers; ++i) { + for (i = 0; i < common->fsg_num_buffers; ++i) { bh = &common->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2384,7 +2396,7 @@ static void handle_exception(struct fsg_common *common) /* Wait until everything is idle */ for (;;) { int num_active = 0; - for (i = 0; i < fsg_num_buffers; ++i) { + for (i = 0; i < common->fsg_num_buffers; ++i) { bh = &common->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2407,7 +2419,7 @@ static void handle_exception(struct fsg_common *common) */ spin_lock_irq(&common->lock); - for (i = 0; i < fsg_num_buffers; ++i) { + for (i = 0; i < common->fsg_num_buffers; ++i) { bh = &common->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -2580,6 +2592,41 @@ static int fsg_main_thread(void *common_) /*************************** DEVICE ATTRIBUTES ***************************/ +static ssize_t ro_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return fsg_show_ro(dev, attr, buf); +} + +static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return fsg_show_nofua(dev, attr, buf); +} + +static ssize_t file_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return fsg_show_file(dev, attr, buf); +} + +static ssize_t ro_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return fsg_store_ro(dev, attr, buf, count); +} + +static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return fsg_store_nofua(dev, attr, buf, count); +} + +static ssize_t file_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return fsg_store_file(dev, attr, buf, count); +} + static DEVICE_ATTR_RW(ro); static DEVICE_ATTR_RW(nofua); static DEVICE_ATTR_RW(file); @@ -2607,6 +2654,16 @@ static inline void fsg_common_put(struct fsg_common *common) kref_put(&common->ref, fsg_common_release); } +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) +{ + if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) + return 0; + pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", + fsg_num_buffers, 2, 4); + return -EINVAL; +} + static struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2618,7 +2675,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, int nluns, i, rc; char *pathbuf; - rc = fsg_num_buffers_validate(); + rc = fsg_num_buffers_validate(cfg->fsg_num_buffers); if (rc != 0) return ERR_PTR(rc); @@ -2640,7 +2697,8 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, common->free_storage_on_release = 0; } - common->buffhds = kcalloc(fsg_num_buffers, + common->fsg_num_buffers = cfg->fsg_num_buffers; + common->buffhds = kcalloc(common->fsg_num_buffers, sizeof *(common->buffhds), GFP_KERNEL); if (!common->buffhds) { if (common->free_storage_on_release) @@ -2727,7 +2785,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, /* Data buffers cyclic list */ bh = common->buffhds; - i = fsg_num_buffers; + i = common->fsg_num_buffers; goto buffhds_first_it; do { bh->next = bh + 1; @@ -2847,7 +2905,7 @@ static void fsg_common_release(struct kref *ref) { struct fsg_buffhd *bh = common->buffhds; - unsigned i = fsg_num_buffers; + unsigned i = common->fsg_num_buffers; do { kfree(bh->buf); } while (++bh, --i); @@ -3009,7 +3067,7 @@ struct fsg_module_parameters { S_IRUGO); \ MODULE_PARM_DESC(prefix ## name, desc) -#define FSG_MODULE_PARAMETERS(prefix, params) \ +#define __FSG_MODULE_PARAMETERS(prefix, params) \ _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \ "names of backing files or devices"); \ _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \ @@ -3025,9 +3083,24 @@ struct fsg_module_parameters { _FSG_MODULE_PARAM(prefix, params, stall, bool, \ "false to prevent bulk stalls") +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#define FSG_MODULE_PARAMETERS(prefix, params) \ + __FSG_MODULE_PARAMETERS(prefix, params); \ + module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);\ + MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers") +#else + +#define FSG_MODULE_PARAMETERS(prefix, params) \ + __FSG_MODULE_PARAMETERS(prefix, params) + +#endif + + static void fsg_config_from_params(struct fsg_config *cfg, - const struct fsg_module_parameters *params) + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers) { struct fsg_lun_config *lun; unsigned i; @@ -3055,19 +3128,22 @@ fsg_config_from_params(struct fsg_config *cfg, /* Finalise */ cfg->can_stall = params->stall; + cfg->fsg_num_buffers = fsg_num_buffers; } static inline struct fsg_common * fsg_common_from_params(struct fsg_common *common, struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers) __attribute__((unused)); static inline struct fsg_common * fsg_common_from_params(struct fsg_common *common, struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers) { struct fsg_config cfg; - fsg_config_from_params(&cfg, params); + fsg_config_from_params(&cfg, params, fsg_num_buffers); return fsg_common_init(common, cdev, &cfg); } diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 080e577773d5..4723d1b04cff 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -37,6 +37,15 @@ #define DRIVER_DESC "Mass Storage Gadget" #define DRIVER_VERSION "2009/09/11" +/* + * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define FSG_VENDOR_ID 0x0525 /* NetChip */ +#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + /*-------------------------------------------------------------------------*/ /* @@ -102,6 +111,20 @@ static struct usb_gadget_strings *dev_strings[] = { static struct fsg_module_parameters mod_data = { .stall = 1 }; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); static unsigned long msg_registered; @@ -129,7 +152,7 @@ static int __init msg_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - fsg_config_from_params(&config, &mod_data); + fsg_config_from_params(&config, &mod_data, fsg_num_buffers); config.ops = &ops; retp = fsg_common_init(&common, c->cdev, &config); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 23393254a8a3..6867d9dbbca4 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -132,6 +132,20 @@ static struct usb_gadget_strings *dev_strings[] = { /****************************** Configurations ******************************/ static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; @@ -294,7 +308,8 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) /* set up mass storage function */ { void *retp; - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); + retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data, + fsg_num_buffers); if (IS_ERR(retp)) { status = PTR_ERR(retp); goto fail1; diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 08a1a3210a21..3e2500f19140 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -23,242 +23,22 @@ * The valid range of num_buffers is: num >= 2 && num <= 4. */ +#include +#include +#include +#include +#include -#include -#include -#include - - -/* - * Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#define FSG_VENDOR_ID 0x0525 /* NetChip */ -#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ - - -/*-------------------------------------------------------------------------*/ - - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) - - -#ifdef DUMP_MSGS - -# define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { \ - if (length < 512) { \ - DBG(fsg, "%s, length %u:\n", label, length); \ - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ - 16, 1, buf, length, 0); \ - } \ -} while (0) - -# define dump_cdb(fsg) do { } while (0) - -#else - -# define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -# ifdef VERBOSE_DEBUG - -# define dump_cdb(fsg) \ - print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ - 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ - -# else - -# define dump_cdb(fsg) do { } while (0) - -# endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - -/*-------------------------------------------------------------------------*/ - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE 16 - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE 0 -#define SS_COMMUNICATION_FAILURE 0x040800 -#define SS_INVALID_COMMAND 0x052000 -#define SS_INVALID_FIELD_IN_CDB 0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 -#define SS_MEDIUM_NOT_PRESENT 0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 -#define SS_RESET_OCCURRED 0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 -#define SS_UNRECOVERED_READ_ERROR 0x031100 -#define SS_WRITE_ERROR 0x030c02 -#define SS_WRITE_PROTECTED 0x072700 - -#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ -#define ASC(x) ((u8) ((x) >> 8)) -#define ASCQ(x) ((u8) (x)) - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_lun { - struct file *filp; - loff_t file_length; - loff_t num_sectors; - - unsigned int initially_ro:1; - unsigned int ro:1; - unsigned int removable:1; - unsigned int cdrom:1; - unsigned int prevent_medium_removal:1; - unsigned int registered:1; - unsigned int info_valid:1; - unsigned int nofua:1; - - u32 sense_data; - u32 sense_data_info; - u32 unit_attention_data; - - unsigned int blkbits; /* Bits of logical block size of bound block device */ - unsigned int blksize; /* logical block size of bound block device */ - struct device dev; -}; - -static inline bool fsg_lun_is_open(struct fsg_lun *curlun) -{ - return curlun->filp != NULL; -} +#include "storage_common.h" static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) { return container_of(dev, struct fsg_lun, dev); } - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE 256 -#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); -MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); - -#else - -/* - * Number of buffers we will use. - * 2 is usually enough for good buffering pipeline - */ -#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(void) -{ - if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) - return 0; - pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", - fsg_num_buffers, 2 ,4); - return -EINVAL; -} - -/* Default size of buffer length. */ -#define FSG_BUFLEN ((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 - -enum fsg_buffer_state { - BUF_STATE_EMPTY = 0, - BUF_STATE_FULL, - BUF_STATE_BUSY -}; - -struct fsg_buffhd { - void *buf; - enum fsg_buffer_state state; - struct fsg_buffhd *next; - - /* - * The NetChip 2280 is faster, and handles some protocol faults - * better, if we don't submit any short bulk-out read requests. - * So we will record the intended request length here. - */ - unsigned int bulk_out_intended_length; - - struct usb_request *inreq; - int inreq_busy; - struct usb_request *outreq; - int outreq_busy; -}; - -enum fsg_state { - /* This one isn't used anywhere */ - FSG_STATE_COMMAND_PHASE = -10, - FSG_STATE_DATA_PHASE, - FSG_STATE_STATUS_PHASE, - - FSG_STATE_IDLE = 0, - FSG_STATE_ABORT_BULK_OUT, - FSG_STATE_RESET, - FSG_STATE_INTERFACE_CHANGE, - FSG_STATE_CONFIG_CHANGE, - FSG_STATE_DISCONNECT, - FSG_STATE_EXIT, - FSG_STATE_TERMINATED -}; - -enum data_direction { - DATA_DIR_UNKNOWN = 0, - DATA_DIR_FROM_HOST, - DATA_DIR_TO_HOST, - DATA_DIR_NONE -}; - - -/*-------------------------------------------------------------------------*/ - - -static inline u32 get_unaligned_be24(u8 *buf) -{ - return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - - -/*-------------------------------------------------------------------------*/ - - -enum { - FSG_STRING_INTERFACE -}; - - /* There is only one interface. */ -static struct usb_interface_descriptor -fsg_intf_desc = { +struct usb_interface_descriptor fsg_intf_desc = { .bLength = sizeof fsg_intf_desc, .bDescriptorType = USB_DT_INTERFACE, @@ -268,14 +48,14 @@ fsg_intf_desc = { .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ .iInterface = FSG_STRING_INTERFACE, }; +EXPORT_SYMBOL(fsg_intf_desc); /* * Three full-speed endpoint descriptors: bulk-in, bulk-out, and * interrupt-in. */ -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -283,9 +63,9 @@ fsg_fs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; +EXPORT_SYMBOL(fsg_fs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -293,13 +73,15 @@ fsg_fs_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */ }; +EXPORT_SYMBOL(fsg_fs_bulk_out_desc); -static struct usb_descriptor_header *fsg_fs_function[] = { +struct usb_descriptor_header *fsg_fs_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, NULL, }; +EXPORT_SYMBOL(fsg_fs_function); /* @@ -310,8 +92,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = { * and a "device qualifier" ... plus more construction options * for the configuration descriptor. */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -319,9 +100,9 @@ fsg_hs_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; +EXPORT_SYMBOL(fsg_hs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -330,17 +111,18 @@ fsg_hs_bulk_out_desc = { .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, /* NAK every 1 uframe */ }; +EXPORT_SYMBOL(fsg_hs_bulk_out_desc); -static struct usb_descriptor_header *fsg_hs_function[] = { +struct usb_descriptor_header *fsg_hs_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, NULL, }; +EXPORT_SYMBOL(fsg_hs_function); -static struct usb_endpoint_descriptor -fsg_ss_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -348,16 +130,17 @@ fsg_ss_bulk_in_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; +EXPORT_SYMBOL(fsg_ss_bulk_in_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, /*.bMaxBurst = DYNAMIC, */ }; +EXPORT_SYMBOL(fsg_ss_bulk_in_comp_desc); -static struct usb_endpoint_descriptor -fsg_ss_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -365,15 +148,17 @@ fsg_ss_bulk_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; +EXPORT_SYMBOL(fsg_ss_bulk_out_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { .bLength = sizeof(fsg_ss_bulk_in_comp_desc), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, /*.bMaxBurst = DYNAMIC, */ }; +EXPORT_SYMBOL(fsg_ss_bulk_out_comp_desc); -static struct usb_descriptor_header *fsg_ss_function[] = { +struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_intf_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, @@ -381,17 +166,7 @@ static struct usb_descriptor_header *fsg_ss_function[] = { (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, NULL, }; - -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string fsg_strings[] = { - {FSG_STRING_INTERFACE, fsg_string_interface}, - {} -}; - -static struct usb_gadget_strings fsg_stringtab = { - .language = 0x0409, /* en-us */ - .strings = fsg_strings, -}; +EXPORT_SYMBOL(fsg_ss_function); /*-------------------------------------------------------------------------*/ @@ -401,7 +176,7 @@ static struct usb_gadget_strings fsg_stringtab = { * the caller must own fsg->filesem for writing. */ -static void fsg_lun_close(struct fsg_lun *curlun) +void fsg_lun_close(struct fsg_lun *curlun) { if (curlun->filp) { LDBG(curlun, "close backing file\n"); @@ -409,9 +184,9 @@ static void fsg_lun_close(struct fsg_lun *curlun) curlun->filp = NULL; } } +EXPORT_SYMBOL(fsg_lun_close); - -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) +int fsg_lun_open(struct fsg_lun *curlun, const char *filename) { int ro; struct file *filp = NULL; @@ -508,6 +283,7 @@ out: fput(filp); return rc; } +EXPORT_SYMBOL(fsg_lun_open); /*-------------------------------------------------------------------------*/ @@ -516,7 +292,7 @@ out: * Sync the file data, don't bother with the metadata. * This code was copied from fs/buffer.c:sys_fdatasync(). */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) +int fsg_lun_fsync_sub(struct fsg_lun *curlun) { struct file *filp = curlun->filp; @@ -524,8 +300,9 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun) return 0; return vfs_fsync(filp, 1); } +EXPORT_SYMBOL(fsg_lun_fsync_sub); -static void store_cdrom_address(u8 *dest, int msf, u32 addr) +void store_cdrom_address(u8 *dest, int msf, u32 addr) { if (msf) { /* Convert to Minutes-Seconds-Frames */ @@ -542,13 +319,13 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr) put_unaligned_be32(addr, dest); } } - +EXPORT_SYMBOL(store_cdrom_address); /*-------------------------------------------------------------------------*/ -static ssize_t ro_show(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, + char *buf) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); @@ -556,17 +333,19 @@ static ssize_t ro_show(struct device *dev, struct device_attribute *attr, ? curlun->ro : curlun->initially_ro); } +EXPORT_SYMBOL(fsg_show_ro); -static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, + char *buf) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); return sprintf(buf, "%u\n", curlun->nofua); } +EXPORT_SYMBOL(fsg_show_nofua); -static ssize_t file_show(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, + char *buf) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); struct rw_semaphore *filesem = dev_get_drvdata(dev); @@ -591,10 +370,11 @@ static ssize_t file_show(struct device *dev, struct device_attribute *attr, up_read(filesem); return rc; } +EXPORT_SYMBOL(fsg_show_file); -static ssize_t ro_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t rc; struct fsg_lun *curlun = fsg_lun_from_dev(dev); @@ -622,9 +402,10 @@ static ssize_t ro_store(struct device *dev, struct device_attribute *attr, up_read(filesem); return rc; } +EXPORT_SYMBOL(fsg_store_ro); -static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +ssize_t fsg_store_nofua(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); unsigned nofua; @@ -642,9 +423,10 @@ static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, return count; } +EXPORT_SYMBOL(fsg_store_nofua); -static ssize_t file_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct fsg_lun *curlun = fsg_lun_from_dev(dev); struct rw_semaphore *filesem = dev_get_drvdata(dev); @@ -674,3 +456,6 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr, up_write(filesem); return (rc < 0 ? rc : count); } +EXPORT_SYMBOL(fsg_store_file); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h new file mode 100644 index 000000000000..1fcda2bfef6c --- /dev/null +++ b/drivers/usb/gadget/storage_common.h @@ -0,0 +1,210 @@ +#ifndef USB_STORAGE_COMMON_H +#define USB_STORAGE_COMMON_H + +#include +#include +#include +#include + +#ifndef DEBUG +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* !DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VLDBG LDBG +#else +#define VLDBG(lun, fmt, args...) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define LDBG(lun, fmt, args...) dev_dbg(&(lun)->dev, fmt, ## args) +#define LERROR(lun, fmt, args...) dev_err(&(lun)->dev, fmt, ## args) +#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) +#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) + +#ifdef DUMP_MSGS + +# define dump_msg(fsg, /* const char * */ label, \ + /* const u8 * */ buf, /* unsigned */ length) \ +do { \ + if (length < 512) { \ + DBG(fsg, "%s, length %u:\n", label, length); \ + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ + 16, 1, buf, length, 0); \ + } \ +} while (0) + +# define dump_cdb(fsg) do { } while (0) + +#else + +# define dump_msg(fsg, /* const char * */ label, \ + /* const u8 * */ buf, /* unsigned */ length) do { } while (0) + +# ifdef VERBOSE_DEBUG + +# define dump_cdb(fsg) \ + print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ + 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ + +# else + +# define dump_cdb(fsg) do { } while (0) + +# endif /* VERBOSE_DEBUG */ + +#endif /* DUMP_MSGS */ + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE 16 + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + +struct fsg_lun { + struct file *filp; + loff_t file_length; + loff_t num_sectors; + + unsigned int initially_ro:1; + unsigned int ro:1; + unsigned int removable:1; + unsigned int cdrom:1; + unsigned int prevent_medium_removal:1; + unsigned int registered:1; + unsigned int info_valid:1; + unsigned int nofua:1; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; + + unsigned int blkbits; /* Bits of logical block size + of bound block device */ + unsigned int blksize; /* logical block size of bound block device */ + struct device dev; +}; + +static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +{ + return curlun->filp != NULL; +} + +/* Big enough to hold our biggest descriptor */ +#define EP0_BUFSIZE 256 +#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ + +/* Default size of buffer length. */ +#define FSG_BUFLEN ((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS 8 + +enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +struct fsg_buffhd { + void *buf; + enum fsg_buffer_state state; + struct fsg_buffhd *next; + + /* + * The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. + * So we will record the intended request length here. + */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; + int inreq_busy; + struct usb_request *outreq; + int outreq_busy; +}; + +enum fsg_state { + /* This one isn't used anywhere */ + FSG_STATE_COMMAND_PHASE = -10, + FSG_STATE_DATA_PHASE, + FSG_STATE_STATUS_PHASE, + + FSG_STATE_IDLE = 0, + FSG_STATE_ABORT_BULK_OUT, + FSG_STATE_RESET, + FSG_STATE_INTERFACE_CHANGE, + FSG_STATE_CONFIG_CHANGE, + FSG_STATE_DISCONNECT, + FSG_STATE_EXIT, + FSG_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +static inline u32 get_unaligned_be24(u8 *buf) +{ + return 0xffffff & (u32) get_unaligned_be32(buf - 1); +} + +enum { + FSG_STRING_INTERFACE +}; + +extern struct usb_interface_descriptor fsg_intf_desc; + +extern struct usb_endpoint_descriptor fsg_fs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_fs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_fs_function[]; + +extern struct usb_endpoint_descriptor fsg_hs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_hs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_hs_function[]; + +extern struct usb_endpoint_descriptor fsg_ss_bulk_in_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc; +extern struct usb_endpoint_descriptor fsg_ss_bulk_out_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc; +extern struct usb_descriptor_header *fsg_ss_function[]; + +void fsg_lun_close(struct fsg_lun *curlun); +int fsg_lun_open(struct fsg_lun *curlun, const char *filename); +int fsg_lun_fsync_sub(struct fsg_lun *curlun); +void store_cdrom_address(u8 *dest, int msf, u32 addr); +ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, + char *buf); +ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, + char *buf); +ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, + char *buf); +ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); +ssize_t fsg_store_nofua(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +#endif /* USB_STORAGE_COMMON_H */ -- cgit v1.2.3 From f3fed36749a1f9a948afdc3b21008e7f65e43220 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 26 Sep 2013 14:38:17 +0200 Subject: usb: gadget: f_mass_storage: factor out a header file In order to prepare for the new function interface the f_mass_storage.c needs to be compiled as a module, and so a header file will be required. This patch factors out some code to a new f_mass_storage.h. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 117 ++------------------------------- drivers/usb/gadget/f_mass_storage.h | 126 ++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 110 deletions(-) create mode 100644 drivers/usb/gadget/f_mass_storage.h (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index def3426108b4..3cdd8359efda 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -229,6 +229,7 @@ static const char fsg_string_interface[] = "Mass Storage"; #include "storage_common.h" +#include "f_mass_storage.h" /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string fsg_strings[] = { @@ -246,18 +247,6 @@ static struct usb_gadget_strings fsg_stringtab = { struct fsg_dev; struct fsg_common; -/* FSF callback functions */ -struct fsg_operations { - /* - * Callback function to call when thread exits. If no - * callback is set or it returns value lower then zero MSF - * will force eject all LUNs it operates on (including those - * marked as non-removable or with prevent_medium_removal flag - * set). - */ - int (*thread_exits)(struct fsg_common *common); -}; - /* Data shared by all the FSG instances. */ struct fsg_common { struct usb_gadget *gadget; @@ -324,28 +313,6 @@ struct fsg_common { struct kref ref; }; -struct fsg_config { - unsigned nluns; - struct fsg_lun_config { - const char *filename; - char ro; - char removable; - char cdrom; - char nofua; - } luns[FSG_MAX_LUNS]; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ - - char can_stall; - unsigned int fsg_num_buffers; -}; - struct fsg_dev { struct usb_function function; struct usb_gadget *gadget; /* Copy of cdev->gadget */ @@ -2644,12 +2611,12 @@ static void fsg_lun_release(struct device *dev) /* Nothing needs to be done */ } -static inline void fsg_common_get(struct fsg_common *common) +void fsg_common_get(struct fsg_common *common) { kref_get(&common->ref); } -static inline void fsg_common_put(struct fsg_common *common) +void fsg_common_put(struct fsg_common *common) { kref_put(&common->ref, fsg_common_release); } @@ -2664,9 +2631,9 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } -static struct fsg_common *fsg_common_init(struct fsg_common *common, - struct usb_composite_dev *cdev, - struct fsg_config *cfg) +struct fsg_common *fsg_common_init(struct fsg_common *common, + struct usb_composite_dev *cdev, + struct fsg_config *cfg) { struct usb_gadget *gadget = cdev->gadget; struct fsg_buffhd *bh; @@ -3043,62 +3010,8 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, /************************* Module parameters *************************/ -struct fsg_module_parameters { - char *file[FSG_MAX_LUNS]; - bool ro[FSG_MAX_LUNS]; - bool removable[FSG_MAX_LUNS]; - bool cdrom[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - - unsigned int file_count, ro_count, removable_count, cdrom_count; - unsigned int nofua_count; - unsigned int luns; /* nluns */ - bool stall; /* can_stall */ -}; - -#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \ - module_param_array_named(prefix ## name, params.name, type, \ - &prefix ## params.name ## _count, \ - S_IRUGO); \ - MODULE_PARM_DESC(prefix ## name, desc) - -#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \ - module_param_named(prefix ## name, params.name, type, \ - S_IRUGO); \ - MODULE_PARM_DESC(prefix ## name, desc) - -#define __FSG_MODULE_PARAMETERS(prefix, params) \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \ - "names of backing files or devices"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \ - "true to force read-only"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \ - "true to simulate removable media"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \ - "true to simulate CD-ROM instead of disk"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \ - "true to ignore SCSI WRITE(10,12) FUA bit"); \ - _FSG_MODULE_PARAM(prefix, params, luns, uint, \ - "number of LUNs"); \ - _FSG_MODULE_PARAM(prefix, params, stall, bool, \ - "false to prevent bulk stalls") - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -#define FSG_MODULE_PARAMETERS(prefix, params) \ - __FSG_MODULE_PARAMETERS(prefix, params); \ - module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);\ - MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers") -#else - -#define FSG_MODULE_PARAMETERS(prefix, params) \ - __FSG_MODULE_PARAMETERS(prefix, params) - -#endif - -static void -fsg_config_from_params(struct fsg_config *cfg, +void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers) { @@ -3131,19 +3044,3 @@ fsg_config_from_params(struct fsg_config *cfg, cfg->fsg_num_buffers = fsg_num_buffers; } -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params, - unsigned int fsg_num_buffers) - __attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params, - unsigned int fsg_num_buffers) -{ - struct fsg_config cfg; - fsg_config_from_params(&cfg, params, fsg_num_buffers); - return fsg_common_init(common, cdev, &cfg); -} diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h new file mode 100644 index 000000000000..b64761d836f6 --- /dev/null +++ b/drivers/usb/gadget/f_mass_storage.h @@ -0,0 +1,126 @@ +#ifndef USB_F_MASS_STORAGE_H +#define USB_F_MASS_STORAGE_H + +#include "storage_common.h" + +struct fsg_module_parameters { + char *file[FSG_MAX_LUNS]; + bool ro[FSG_MAX_LUNS]; + bool removable[FSG_MAX_LUNS]; + bool cdrom[FSG_MAX_LUNS]; + bool nofua[FSG_MAX_LUNS]; + + unsigned int file_count, ro_count, removable_count, cdrom_count; + unsigned int nofua_count; + unsigned int luns; /* nluns */ + bool stall; /* can_stall */ +}; + +#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \ + module_param_array_named(prefix ## name, params.name, type, \ + &prefix ## params.name ## _count, \ + S_IRUGO); \ + MODULE_PARM_DESC(prefix ## name, desc) + +#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \ + module_param_named(prefix ## name, params.name, type, \ + S_IRUGO); \ + MODULE_PARM_DESC(prefix ## name, desc) + +#define __FSG_MODULE_PARAMETERS(prefix, params) \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \ + "names of backing files or devices"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \ + "true to force read-only"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \ + "true to simulate removable media"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \ + "true to simulate CD-ROM instead of disk"); \ + _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \ + "true to ignore SCSI WRITE(10,12) FUA bit"); \ + _FSG_MODULE_PARAM(prefix, params, luns, uint, \ + "number of LUNs"); \ + _FSG_MODULE_PARAM(prefix, params, stall, bool, \ + "false to prevent bulk stalls") + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#define FSG_MODULE_PARAMETERS(prefix, params) \ + __FSG_MODULE_PARAMETERS(prefix, params); \ + module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);\ + MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers") +#else + +#define FSG_MODULE_PARAMETERS(prefix, params) \ + __FSG_MODULE_PARAMETERS(prefix, params) + +#endif + +struct fsg_common; + +/* FSF callback functions */ +struct fsg_operations { + /* + * Callback function to call when thread exits. If no + * callback is set or it returns value lower then zero MSF + * will force eject all LUNs it operates on (including those + * marked as non-removable or with prevent_medium_removal flag + * set). + */ + int (*thread_exits)(struct fsg_common *common); +}; + +struct fsg_lun_config { + const char *filename; + char ro; + char removable; + char cdrom; + char nofua; +}; + +struct fsg_config { + unsigned nluns; + struct fsg_lun_config luns[FSG_MAX_LUNS]; + + /* Callback functions. */ + const struct fsg_operations *ops; + /* Gadget's private data. */ + void *private_data; + + const char *vendor_name; /* 8 characters or less */ + const char *product_name; /* 16 characters or less */ + + char can_stall; + unsigned int fsg_num_buffers; +}; + +void fsg_common_get(struct fsg_common *common); + +void fsg_common_put(struct fsg_common *common); + +struct fsg_common *fsg_common_init(struct fsg_common *common, + struct usb_composite_dev *cdev, + struct fsg_config *cfg); + +void fsg_config_from_params(struct fsg_config *cfg, + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers); + +static inline struct fsg_common * +fsg_common_from_params(struct fsg_common *common, + struct usb_composite_dev *cdev, + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers) + __attribute__((unused)); +static inline struct fsg_common * +fsg_common_from_params(struct fsg_common *common, + struct usb_composite_dev *cdev, + const struct fsg_module_parameters *params, + unsigned int fsg_num_buffers) +{ + struct fsg_config cfg; + fsg_config_from_params(&cfg, params, fsg_num_buffers); + return fsg_common_init(common, cdev, &cfg); +} + +#endif /* USB_F_MASS_STORAGE_H */ -- cgit v1.2.3 From 8b903fd7f97cdeb2cd927853025e9a667379a434 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 26 Sep 2013 14:38:18 +0200 Subject: usb: gadget: f_mass_storage: add a level of indirection for luns storage This is needed to prepare for configfs integration. So far the luns have been allocated during gadget's initialization, based on the nluns module parameter's value; the exact number is known when the gadget is initialized and that number of luns is allocated in one go; they all will be used. When configfs is in place, the luns will be created one-by-one by the user. Once the user is satisfied with the number of luns, they activate the gadget. The number of luns must be <= FSG_MAX_LUN (currently 8), but other than that it is not known up front and the user need not use contiguous numbering (apart from the default lun #0). On the other hand, the function code uses lun numbers to identify them and the number needs to be used as an index into an array. Given the above, an array needs to be allocated, but it might happen that 7 out of its 8 elements will not be used. On my machine sizeof(struct fsg_lun) == 462, so > 3k of memory is allocated but not used in the worst case. By adding another level of indirection (allocating an array of pointers to struct fsg_lun and then allocating individual luns instead of an array of struct fsg_luns) at most 7 pointers are wasted, which is much less. This patch also changes some for/while loops to cope with the fact that in the luns array some entries are potentially empty. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 60 +++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 3cdd8359efda..6b6c7f1b773f 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -274,7 +274,7 @@ struct fsg_common { unsigned int nluns; unsigned int lun; - struct fsg_lun *luns; + struct fsg_lun **luns; struct fsg_lun *curlun; unsigned int bulk_out_maxpacket; @@ -2151,7 +2151,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; if (common->lun < common->nluns) - common->curlun = &common->luns[common->lun]; + common->curlun = common->luns[common->lun]; else common->curlun = NULL; common->tag = cbw->Tag; @@ -2299,7 +2299,9 @@ reset: common->running = 1; for (i = 0; i < common->nluns; ++i) - common->luns[i].unit_attention_data = SS_RESET_OCCURRED; + if (common->luns[i]) + common->luns[i]->unit_attention_data = + SS_RESET_OCCURRED; return rc; } @@ -2399,7 +2401,9 @@ static void handle_exception(struct fsg_common *common) common->state = FSG_STATE_STATUS_PHASE; else { for (i = 0; i < common->nluns; ++i) { - curlun = &common->luns[i]; + curlun = common->luns[i]; + if (!curlun) + continue; curlun->prevent_medium_removal = 0; curlun->sense_data = SS_NO_SENSE; curlun->unit_attention_data = SS_NO_SENSE; @@ -2441,8 +2445,9 @@ static void handle_exception(struct fsg_common *common) * CONFIG_CHANGE cases. */ /* for (i = 0; i < common->nluns; ++i) */ - /* common->luns[i].unit_attention_data = */ - /* SS_RESET_OCCURRED; */ + /* if (common->luns[i]) */ + /* common->luns[i]->unit_attention_data = */ + /* SS_RESET_OCCURRED; */ break; case FSG_STATE_CONFIG_CHANGE: @@ -2538,12 +2543,13 @@ static int fsg_main_thread(void *common_) if (!common->ops || !common->ops->thread_exits || common->ops->thread_exits(common) < 0) { - struct fsg_lun *curlun = common->luns; + struct fsg_lun **curlun_it = common->luns; unsigned i = common->nluns; down_write(&common->filesem); - for (; i--; ++curlun) { - if (!fsg_lun_is_open(curlun)) + for (; i--; ++curlun_it) { + struct fsg_lun *curlun = *curlun_it; + if (!curlun || !fsg_lun_is_open(curlun)) continue; fsg_lun_close(curlun); @@ -2637,7 +2643,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, { struct usb_gadget *gadget = cdev->gadget; struct fsg_buffhd *bh; - struct fsg_lun *curlun; + struct fsg_lun **curlun_it; struct fsg_lun_config *lcfg; int nluns, i, rc; char *pathbuf; @@ -2694,16 +2700,26 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, * Create the LUNs, open their backing files, and register the * LUN devices in sysfs. */ - curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); - if (unlikely(!curlun)) { + curlun_it = kcalloc(nluns, sizeof(*curlun_it), GFP_KERNEL); + if (unlikely(!curlun_it)) { rc = -ENOMEM; goto error_release; } - common->luns = curlun; + common->luns = curlun_it; init_rwsem(&common->filesem); - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { + for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { + struct fsg_lun *curlun; + + curlun = kzalloc(sizeof(*curlun), GFP_KERNEL); + if (!curlun) { + rc = -ENOMEM; + common->nluns = i; + goto error_release; + } + *curlun_it = curlun; + curlun->cdrom = !!lcfg->cdrom; curlun->ro = lcfg->cdrom || lcfg->ro; curlun->initially_ro = curlun->ro; @@ -2719,6 +2735,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, INFO(common, "failed to register LUN%d: %d\n", i, rc); common->nluns = i; put_device(&curlun->dev); + kfree(curlun); goto error_release; } @@ -2771,7 +2788,7 @@ buffhds_first_it: snprintf(common->inquiry_string, sizeof common->inquiry_string, "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", /* Assume product name dependent on the first LUN */ - cfg->product_name ?: (common->luns->cdrom + cfg->product_name ?: ((*common->luns)->cdrom ? "File-CD Gadget" : "File-Stor Gadget"), i); @@ -2802,9 +2819,10 @@ buffhds_first_it: INFO(common, "Number of LUNs=%d\n", common->nluns); pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0, nluns = common->nluns, curlun = common->luns; + for (i = 0, nluns = common->nluns, curlun_it = common->luns; i < nluns; - ++curlun, ++i) { + ++curlun_it, ++i) { + struct fsg_lun *curlun = *curlun_it; char *p = "(no medium)"; if (fsg_lun_is_open(curlun)) { p = "(error)"; @@ -2849,11 +2867,14 @@ static void fsg_common_release(struct kref *ref) } if (likely(common->luns)) { - struct fsg_lun *lun = common->luns; + struct fsg_lun **lun_it = common->luns; unsigned i = common->nluns; /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun) { + for (; i; --i, ++lun_it) { + struct fsg_lun *lun = *lun_it; + if (!lun) + continue; device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, lun->cdrom @@ -2865,6 +2886,7 @@ static void fsg_common_release(struct kref *ref) : &dev_attr_file_nonremovable); fsg_lun_close(lun); device_unregister(&lun->dev); + kfree(lun); } kfree(common->luns); -- cgit v1.2.3 From 4610f19b4a7b0566f39aca490f7dde5b68e10243 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 26 Sep 2013 14:38:19 +0200 Subject: usb: gadget: f_mass_storage: use usb_gstrings_attach Prepare for handling with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6b6c7f1b773f..32e5ab73f746 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -242,6 +242,11 @@ static struct usb_gadget_strings fsg_stringtab = { .strings = fsg_strings, }; +static struct usb_gadget_strings *fsg_strings_array[] = { + &fsg_stringtab, + NULL, +}; + /*-------------------------------------------------------------------------*/ struct fsg_dev; @@ -2645,6 +2650,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, struct fsg_buffhd *bh; struct fsg_lun **curlun_it; struct fsg_lun_config *lcfg; + struct usb_string *us; int nluns, i, rc; char *pathbuf; @@ -2687,14 +2693,13 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, common->ep0req = cdev->req; common->cdev = cdev; - /* Maybe allocate device-global string IDs, and patch descriptors */ - if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { - rc = usb_string_id(cdev); - if (unlikely(rc < 0)) - goto error_release; - fsg_strings[FSG_STRING_INTERFACE].id = rc; - fsg_intf_desc.iInterface = rc; + us = usb_gstrings_attach(cdev, fsg_strings_array, + ARRAY_SIZE(fsg_strings)); + if (IS_ERR(us)) { + rc = PTR_ERR(us); + goto error_release; } + fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id; /* * Create the LUNs, open their backing files, and register the @@ -2988,11 +2993,6 @@ autoconf_fail: /****************************** ADD FUNCTION ******************************/ -static struct usb_gadget_strings *fsg_strings_array[] = { - &fsg_stringtab, - NULL, -}; - static int fsg_bind_config(struct usb_composite_dev *cdev, struct usb_configuration *c, struct fsg_common *common) @@ -3005,7 +3005,6 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, return -ENOMEM; fsg->function.name = FSG_DRIVER_DESC; - fsg->function.strings = fsg_strings_array; fsg->function.bind = fsg_bind; fsg->function.unbind = fsg_unbind; fsg->function.setup = fsg_setup; -- cgit v1.2.3 From b432cb837480d7b93f95c2c5766828e9ac7f036a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:44:44 +0530 Subject: usb: musb_dsps: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Cc: Ravi B Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 4047cbb91bac..c7fe16db6bb6 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -628,7 +628,7 @@ static struct platform_driver dsps_usbss_driver = { .remove = dsps_remove, .driver = { .name = "musb-dsps", - .of_match_table = of_match_ptr(musb_dsps_of_match), + .of_match_table = musb_dsps_of_match, }, }; -- cgit v1.2.3 From c4df9ae0d6a84890b5a877a8a32b7a7a1bca00a9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:44:45 +0530 Subject: usb: phy: am335x-control: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x-control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 0fac976b63b5..634f49acd20e 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -171,7 +171,7 @@ static struct platform_driver am335x_control_driver = { .driver = { .name = "am335x-control-usb", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(omap_control_usb_id_table), + .of_match_table = omap_control_usb_id_table, }, }; -- cgit v1.2.3 From b99fffca7ddd46b78322757cfd77e9d2cdcdc7ad Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:44:46 +0530 Subject: usb: phy: am335x: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index f3478a856edb..1495cdc751ad 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -125,7 +125,7 @@ static struct platform_driver am335x_phy_driver = { .name = "am335x-phy-driver", .owner = THIS_MODULE, .pm = DEV_PM_OPS, - .of_match_table = of_match_ptr(am335x_phy_ids), + .of_match_table = am335x_phy_ids, }, }; -- cgit v1.2.3 From 78723920a6a57f6284574133d10f3e94b06b5979 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:44:47 +0530 Subject: usb: phy: tegra-usb: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Cc: Stephen Warren Cc: linux-tegra@vger.kernel.org Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index e9cb1cb8abc7..82232acf1ab6 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1090,7 +1090,7 @@ static struct platform_driver tegra_usb_phy_driver = { .driver = { .name = "tegra-phy", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tegra_usb_phy_id_table), + .of_match_table = tegra_usb_phy_id_table, }, }; module_platform_driver(tegra_usb_phy_driver); -- cgit v1.2.3 From a49be8f231ee0815d149d6d6c23dcc56a6f68410 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Sep 2013 21:02:07 +0200 Subject: usb: musb: am35x: use SIMPLE_DEV_PM_OPS This makes am35x_pm_ops const and will stub the struct out in case CONFIG_PM_SLEEP is not set. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/am35x.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 790b22b296b1..ca45b39db5b9 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -599,23 +599,16 @@ static int am35x_resume(struct device *dev) return 0; } - -static struct dev_pm_ops am35x_pm_ops = { - .suspend = am35x_suspend, - .resume = am35x_resume, -}; - -#define DEV_PM_OPS &am35x_pm_ops -#else -#define DEV_PM_OPS NULL #endif +static SIMPLE_DEV_PM_OPS(am35x_pm_ops, am35x_suspend, am35x_resume); + static struct platform_driver am35x_driver = { .probe = am35x_probe, .remove = am35x_remove, .driver = { .name = "musb-am35x", - .pm = DEV_PM_OPS, + .pm = &am35x_pm_ops, }, }; -- cgit v1.2.3 From 0967313b6fe14f34d87b1ef278f7771ed8900eb1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Sep 2013 21:02:08 +0200 Subject: usb: musb: blackfin: use SIMPLE_DEV_PM_OPS This makes bfin_pm_ops const and will stub the struct out in case CONFIG_PM_SLEEP is not set. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/blackfin.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 72e2056b6082..d9692f78e227 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -561,23 +561,16 @@ static int bfin_resume(struct device *dev) return 0; } - -static struct dev_pm_ops bfin_pm_ops = { - .suspend = bfin_suspend, - .resume = bfin_resume, -}; - -#define DEV_PM_OPS &bfin_pm_ops -#else -#define DEV_PM_OPS NULL #endif +static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); + static struct platform_driver bfin_driver = { .probe = bfin_probe, .remove = __exit_p(bfin_remove), .driver = { .name = "musb-blackfin", - .pm = DEV_PM_OPS, + .pm = &bfin_pm_ops, }, }; -- cgit v1.2.3 From a89adb098ac33934b6b0a773853a12220376d600 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Sep 2013 21:02:09 +0200 Subject: usb: musb: ux500: use SIMPLE_DEV_PM_OPS This removes the DEV_PM_OPS macro and brings this file in line with the other musb platform drivers. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/ux500.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 59256b12f746..f483d1924c28 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -376,17 +376,10 @@ static int ux500_resume(struct device *dev) return 0; } - -static const struct dev_pm_ops ux500_pm_ops = { - .suspend = ux500_suspend, - .resume = ux500_resume, -}; - -#define DEV_PM_OPS (&ux500_pm_ops) -#else -#define DEV_PM_OPS NULL #endif +static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume); + static const struct of_device_id ux500_match[] = { { .compatible = "stericsson,db8500-musb", }, {} @@ -397,7 +390,7 @@ static struct platform_driver ux500_driver = { .remove = ux500_remove, .driver = { .name = "musb-ux500", - .pm = DEV_PM_OPS, + .pm = &ux500_pm_ops, .of_match_table = ux500_match, }, }; -- cgit v1.2.3 From a023da331c1d2a26669161031fe6e2c8e0a2009e Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 30 Sep 2013 14:56:02 +0200 Subject: usb: gadget: s3c-hsotg: fix CodingStyle issues checkpatch.pl has some valid complaints about style in s3c-hsotg.c: - macro with 'if' should be really enclosed in 'do {} while (0)' - seq_puts() is going to be slightly faster than seq_printf() - pr_err() is shorter than printk(KERN_ERR ...) Signed-off-by: Pavel Machek [bzolnier: minor fixes] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6bddf1aa2347..24973d71e29a 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2092,12 +2092,14 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, } #define call_gadget(_hs, _entry) \ +do { \ if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ (_hs)->driver && (_hs)->driver->_entry) { \ spin_unlock(&_hs->lock); \ (_hs)->driver->_entry(&(_hs)->gadget); \ spin_lock(&_hs->lock); \ - } + } \ +} while (0) /** * s3c_hsotg_disconnect - disconnect service @@ -2903,7 +2905,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, int ret; if (!hsotg) { - printk(KERN_ERR "%s: called with no device\n", __func__); + pr_err("%s: called with no device\n", __func__); return -ENODEV; } @@ -3200,7 +3202,7 @@ static int state_show(struct seq_file *seq, void *v) readl(regs + GNPTXSTS), readl(regs + GRXSTSR)); - seq_printf(seq, "\nEndpoint status:\n"); + seq_puts(seq, "\nEndpoint status:\n"); for (idx = 0; idx < 15; idx++) { u32 in, out; @@ -3217,7 +3219,7 @@ static int state_show(struct seq_file *seq, void *v) seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", in, out); - seq_printf(seq, "\n"); + seq_puts(seq, "\n"); } return 0; @@ -3251,7 +3253,7 @@ static int fifo_show(struct seq_file *seq, void *v) u32 val; int idx; - seq_printf(seq, "Non-periodic FIFOs:\n"); + seq_puts(seq, "Non-periodic FIFOs:\n"); seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); val = readl(regs + GNPTXFSIZ); @@ -3259,7 +3261,7 @@ static int fifo_show(struct seq_file *seq, void *v) val >> GNPTXFSIZ_NPTxFDep_SHIFT, val & GNPTXFSIZ_NPTxFStAddr_MASK); - seq_printf(seq, "\nPeriodic TXFIFOs:\n"); + seq_puts(seq, "\nPeriodic TXFIFOs:\n"); for (idx = 1; idx <= 15; idx++) { val = readl(regs + DPTXFSIZn(idx)); @@ -3330,7 +3332,7 @@ static int ep_show(struct seq_file *seq, void *v) readl(regs + DIEPTSIZ(index)), readl(regs + DOEPTSIZ(index))); - seq_printf(seq, "\n"); + seq_puts(seq, "\n"); seq_printf(seq, "mps %d\n", ep->ep.maxpacket); seq_printf(seq, "total_data=%ld\n", ep->total_data); @@ -3341,7 +3343,7 @@ static int ep_show(struct seq_file *seq, void *v) list_for_each_entry(req, &ep->queue, queue) { if (--show_limit < 0) { - seq_printf(seq, "not showing more requests...\n"); + seq_puts(seq, "not showing more requests...\n"); break; } -- cgit v1.2.3 From e79c8a06afe4a7d4b4df686e05028cd5660bea96 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:44:43 +0530 Subject: usb: musb_am335x: Remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_am335x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c index 41ac5b5b57ce..8be9b02c3cc2 100644 --- a/drivers/usb/musb/musb_am335x.c +++ b/drivers/usb/musb/musb_am335x.c @@ -46,7 +46,7 @@ static struct platform_driver am335x_child_driver = { .remove = am335x_child_remove, .driver = { .name = "am335x-usb-childs", - .of_match_table = of_match_ptr(am335x_child_of_match), + .of_match_table = am335x_child_of_match, }, }; -- cgit v1.2.3 From bd27fa44e13830d2baa278d5702e766380659cb3 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 24 Sep 2013 11:53:48 +0300 Subject: usb: phy: generic: Don't use regulator framework for RESET line Modelling the RESET line as a regulator supply wasn't a good idea as it kind of abuses the regulator framework and also makes adaptation code more complex. Instead, manage the RESET gpio line directly in the driver. Update the device tree binding information. This also makes us easy to migrate to a dedicated GPIO RESET controller whenever it becomes available. Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-am335x.c | 2 +- drivers/usb/phy/phy-generic.c | 84 ++++++++++++++++++++++++++++--------------- drivers/usb/phy/phy-generic.h | 6 ++-- 3 files changed, 60 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 1495cdc751ad..6370e50649d7 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -53,7 +53,7 @@ static int am335x_phy_probe(struct platform_device *pdev) } ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, - USB_PHY_TYPE_USB2, 0, false, false); + USB_PHY_TYPE_USB2, 0, false); if (ret) return ret; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index fcc31045fda7..fce3a9e9bb5d 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include "phy-generic.h" @@ -64,6 +67,23 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) return 0; } +static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted) +{ + int value; + + if (!gpio_is_valid(nop->gpio_reset)) + return; + + value = asserted; + if (nop->reset_active_low) + value = !value; + + gpio_set_value_cansleep(nop->gpio_reset, value); + + if (!asserted) + usleep_range(10000, 20000); +} + int usb_gen_phy_init(struct usb_phy *phy) { struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); @@ -76,11 +96,8 @@ int usb_gen_phy_init(struct usb_phy *phy) if (!IS_ERR(nop->clk)) clk_prepare_enable(nop->clk); - if (!IS_ERR(nop->reset)) { - /* De-assert RESET */ - if (regulator_enable(nop->reset)) - dev_err(phy->dev, "Failed to de-assert reset\n"); - } + /* De-assert RESET */ + nop_reset_set(nop, 0); return 0; } @@ -90,11 +107,8 @@ void usb_gen_phy_shutdown(struct usb_phy *phy) { struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); - if (!IS_ERR(nop->reset)) { - /* Assert RESET */ - if (regulator_disable(nop->reset)) - dev_err(phy->dev, "Failed to assert reset\n"); - } + /* Assert RESET */ + nop_reset_set(nop, 1); if (!IS_ERR(nop->clk)) clk_disable_unprepare(nop->clk); @@ -136,8 +150,7 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) } int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - enum usb_phy_type type, u32 clk_rate, bool needs_vcc, - bool needs_reset) + enum usb_phy_type type, u32 clk_rate, bool needs_vcc) { int err; @@ -168,12 +181,22 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, return -EPROBE_DEFER; } - nop->reset = devm_regulator_get(dev, "reset"); - if (IS_ERR(nop->reset)) { - dev_dbg(dev, "Error getting reset regulator: %ld\n", - PTR_ERR(nop->reset)); - if (needs_reset) - return -EPROBE_DEFER; + if (gpio_is_valid(nop->gpio_reset)) { + unsigned long gpio_flags; + + /* Assert RESET */ + if (nop->reset_active_low) + gpio_flags = GPIOF_OUT_INIT_LOW; + else + gpio_flags = GPIOF_OUT_INIT_HIGH; + + err = devm_gpio_request_one(dev, nop->gpio_reset, + gpio_flags, dev_name(dev)); + if (err) { + dev_err(dev, "Error requesting RESET GPIO %d\n", + nop->gpio_reset); + return err; + } } nop->dev = dev; @@ -202,31 +225,36 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) int err; u32 clk_rate = 0; bool needs_vcc = false; - bool needs_reset = false; + + nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); + if (!nop) + return -ENOMEM; + + nop->reset_active_low = true; /* default behaviour */ if (dev->of_node) { struct device_node *node = dev->of_node; + enum of_gpio_flags flags; if (of_property_read_u32(node, "clock-frequency", &clk_rate)) clk_rate = 0; needs_vcc = of_property_read_bool(node, "vcc-supply"); - needs_reset = of_property_read_bool(node, "reset-supply"); + nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", + 0, &flags); + if (nop->gpio_reset == -EPROBE_DEFER) + return -EPROBE_DEFER; + + nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; } else if (pdata) { type = pdata->type; clk_rate = pdata->clk_rate; needs_vcc = pdata->needs_vcc; - needs_reset = pdata->needs_reset; + nop->gpio_reset = pdata->gpio_reset; } - nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL); - if (!nop) - return -ENOMEM; - - - err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, - needs_reset); + err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc); if (err) return err; diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index 386d11b375aa..d2a220d81734 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -6,14 +6,14 @@ struct usb_phy_gen_xceiv { struct device *dev; struct clk *clk; struct regulator *vcc; - struct regulator *reset; + int gpio_reset; + bool reset_active_low; }; int usb_gen_phy_init(struct usb_phy *phy); void usb_gen_phy_shutdown(struct usb_phy *phy); int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, - enum usb_phy_type type, u32 clk_rate, bool needs_vcc, - bool needs_reset); + enum usb_phy_type type, u32 clk_rate, bool needs_vcc); #endif -- cgit v1.2.3 From f8cffc84a2ff8efc2ecca6128485877109e499f5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 28 Sep 2013 00:05:34 -0300 Subject: usb: gadget: udc-core: Do not report -EISNAM error from gadgetfs When mounting a gadgetfs the following error message is seen: $ modprobe gadgetfs gadgetfs: USB Gadget filesystem, version 24 Aug 2004 $ mkdir /dev/gadget $ mount -t gadgetfs none /dev/gadget nop ci_hdrc.0: failed to start (null): -120 The error comes from gadgetfs_probe(), which returns -EISNAM (-120). As Alan Stern explains[1], this is the normal behavior: "It is a temporary measure, used only when the file system is set up initially. The real bind routine is gadgetfs_bind(), which gets called when userspace configures the gadget. In short, this is how it is intended to work. It isn't a bug." [1] http://marc.info/?l=linux-usb&m=138029668707075&w=2 So in order to prevent the error message, do not report EISNAM as an error. Acked-by: Alan Stern Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 59891b1c48fc..27768a7d986a 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -356,7 +356,8 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); return 0; err1: - dev_err(&udc->dev, "failed to start %s: %d\n", + if (ret != -EISNAM) + dev_err(&udc->dev, "failed to start %s: %d\n", udc->driver->function, ret); udc->driver = NULL; udc->dev.driver = NULL; -- cgit v1.2.3 From da8cc16724da2965c94ca15e1377cb9939776dda Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Pass OTG FSM pointer to callback functions struct otg_fsm may be embedded to device's context structure. The callbacks may require pointer to struct otg_fsm to obtain necessary data for its operation (example: regulator reference for drv_vbus()). Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.c | 30 +++++++++++++++--------------- drivers/usb/phy/phy-fsl-usb.h | 4 ++-- drivers/usb/phy/phy-fsm-usb.h | 28 ++++++++++++++-------------- 3 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index fa7c9f9628b5..8b34694ac48f 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -134,7 +134,7 @@ int write_ulpi(u8 addr, u8 data) /* Operations that will be called from OTG Finite State Machine */ /* Charge vbus for vbus pulsing in SRP */ -void fsl_otg_chrg_vbus(int on) +void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on) { u32 tmp; @@ -170,7 +170,7 @@ void fsl_otg_dischrg_vbus(int on) } /* A-device driver vbus, controlled through PP bit in PORTSC */ -void fsl_otg_drv_vbus(int on) +void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on) { u32 tmp; @@ -188,7 +188,7 @@ void fsl_otg_drv_vbus(int on) * Pull-up D+, signalling connect by periperal. Also used in * data-line pulsing in SRP */ -void fsl_otg_loc_conn(int on) +void fsl_otg_loc_conn(struct otg_fsm *fsm, int on) { u32 tmp; @@ -207,7 +207,7 @@ void fsl_otg_loc_conn(int on) * port. In host mode, controller will automatically send SOF. * Suspend will block the data on the port. */ -void fsl_otg_loc_sof(int on) +void fsl_otg_loc_sof(struct otg_fsm *fsm, int on) { u32 tmp; @@ -222,7 +222,7 @@ void fsl_otg_loc_sof(int on) } /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */ -void fsl_otg_start_pulse(void) +void fsl_otg_start_pulse(struct otg_fsm *fsm) { u32 tmp; @@ -235,7 +235,7 @@ void fsl_otg_start_pulse(void) fsl_otg_loc_conn(1); #endif - fsl_otg_add_timer(b_data_pulse_tmr); + fsl_otg_add_timer(fsm, b_data_pulse_tmr); } void b_data_pulse_end(unsigned long foo) @@ -252,14 +252,14 @@ void b_data_pulse_end(unsigned long foo) void fsl_otg_pulse_vbus(void) { srp_wait_done = 0; - fsl_otg_chrg_vbus(1); + fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1); /* start the timer to end vbus charge */ - fsl_otg_add_timer(b_vbus_pulse_tmr); + fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr); } void b_vbus_pulse_end(unsigned long foo) { - fsl_otg_chrg_vbus(0); + fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0); /* * As USB3300 using the same a_sess_vld and b_sess_vld voltage @@ -267,7 +267,7 @@ void b_vbus_pulse_end(unsigned long foo) * residual voltage of vbus pulsing and A device pull up */ fsl_otg_dischrg_vbus(1); - fsl_otg_add_timer(b_srp_wait_tmr); + fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr); } void b_srp_end(unsigned long foo) @@ -289,7 +289,7 @@ void a_wait_enum(unsigned long foo) { VDBG("a_wait_enum timeout\n"); if (!fsl_otg_dev->phy.otg->host->b_hnp_enable) - fsl_otg_add_timer(a_wait_enum_tmr); + fsl_otg_add_timer(&fsl_otg_dev->fsm, a_wait_enum_tmr); else otg_statemachine(&fsl_otg_dev->fsm); } @@ -376,7 +376,7 @@ void fsl_otg_uninit_timers(void) } /* Add timer to timer list */ -void fsl_otg_add_timer(void *gtimer) +void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer) { struct fsl_otg_timer *timer = gtimer; struct fsl_otg_timer *tmp_timer; @@ -395,7 +395,7 @@ void fsl_otg_add_timer(void *gtimer) } /* Remove timer from the timer list; clear timeout status */ -void fsl_otg_del_timer(void *gtimer) +void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer) { struct fsl_otg_timer *timer = gtimer; struct fsl_otg_timer *tmp_timer, *del_tmp; @@ -468,7 +468,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) retval = dev->driver->pm->resume(dev); if (fsm->id) { /* default-b */ - fsl_otg_drv_vbus(1); + fsl_otg_drv_vbus(fsm, 1); /* * Workaround: b_host can't driver * vbus, but PP in PORTSC needs to @@ -493,7 +493,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) retval = dev->driver->pm->suspend(dev); if (fsm->id) /* default-b */ - fsl_otg_drv_vbus(0); + fsl_otg_drv_vbus(fsm, 0); } otg_dev->host_working = 0; } diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index e1859b8ef567..7365170a2f23 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -401,6 +401,6 @@ struct fsl_otg_config { #define GET_A_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 8, int) #define GET_B_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 9, int) -void fsl_otg_add_timer(void *timer); -void fsl_otg_del_timer(void *timer); +void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer); +void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer); void fsl_otg_pulse_vbus(void); diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index fbe586206f33..75344bec4679 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -83,13 +83,13 @@ struct otg_fsm { }; struct otg_fsm_ops { - void (*chrg_vbus)(int on); - void (*drv_vbus)(int on); - void (*loc_conn)(int on); - void (*loc_sof)(int on); - void (*start_pulse)(void); - void (*add_timer)(void *timer); - void (*del_timer)(void *timer); + void (*chrg_vbus)(struct otg_fsm *fsm, int on); + void (*drv_vbus)(struct otg_fsm *fsm, int on); + void (*loc_conn)(struct otg_fsm *fsm, int on); + void (*loc_sof)(struct otg_fsm *fsm, int on); + void (*start_pulse)(struct otg_fsm *fsm); + void (*add_timer)(struct otg_fsm *fsm, void *timer); + void (*del_timer)(struct otg_fsm *fsm, void *timer); int (*start_host)(struct otg_fsm *fsm, int on); int (*start_gadget)(struct otg_fsm *fsm, int on); }; @@ -97,14 +97,14 @@ struct otg_fsm_ops { static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on) { - fsm->ops->chrg_vbus(on); + fsm->ops->chrg_vbus(fsm, on); } static inline void otg_drv_vbus(struct otg_fsm *fsm, int on) { if (fsm->drv_vbus != on) { fsm->drv_vbus = on; - fsm->ops->drv_vbus(on); + fsm->ops->drv_vbus(fsm, on); } } @@ -112,7 +112,7 @@ static inline void otg_loc_conn(struct otg_fsm *fsm, int on) { if (fsm->loc_conn != on) { fsm->loc_conn = on; - fsm->ops->loc_conn(on); + fsm->ops->loc_conn(fsm, on); } } @@ -120,23 +120,23 @@ static inline void otg_loc_sof(struct otg_fsm *fsm, int on) { if (fsm->loc_sof != on) { fsm->loc_sof = on; - fsm->ops->loc_sof(on); + fsm->ops->loc_sof(fsm, on); } } static inline void otg_start_pulse(struct otg_fsm *fsm) { - fsm->ops->start_pulse(); + fsm->ops->start_pulse(fsm); } static inline void otg_add_timer(struct otg_fsm *fsm, void *timer) { - fsm->ops->add_timer(timer); + fsm->ops->add_timer(fsm, timer); } static inline void otg_del_timer(struct otg_fsm *fsm, void *timer) { - fsm->ops->del_timer(timer); + fsm->ops->del_timer(fsm, timer); } int otg_statemachine(struct otg_fsm *fsm); -- cgit v1.2.3 From 737cc66eac350d674c72a3f903541644098ec47e Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Check OTG FSM callback existance in helper functions Existence of callback must be checked to avoid NULL pointer dereferncing. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsm-usb.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 75344bec4679..0f3f7d87f887 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -95,48 +95,69 @@ struct otg_fsm_ops { }; -static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on) +static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on) { + if (!fsm->ops->chrg_vbus) + return -EOPNOTSUPP; fsm->ops->chrg_vbus(fsm, on); + return 0; } -static inline void otg_drv_vbus(struct otg_fsm *fsm, int on) +static inline int otg_drv_vbus(struct otg_fsm *fsm, int on) { + if (!fsm->ops->drv_vbus) + return -EOPNOTSUPP; if (fsm->drv_vbus != on) { fsm->drv_vbus = on; fsm->ops->drv_vbus(fsm, on); } + return 0; } -static inline void otg_loc_conn(struct otg_fsm *fsm, int on) +static inline int otg_loc_conn(struct otg_fsm *fsm, int on) { + if (!fsm->ops->loc_conn) + return -EOPNOTSUPP; if (fsm->loc_conn != on) { fsm->loc_conn = on; fsm->ops->loc_conn(fsm, on); } + return 0; } -static inline void otg_loc_sof(struct otg_fsm *fsm, int on) +static inline int otg_loc_sof(struct otg_fsm *fsm, int on) { + if (!fsm->ops->loc_sof) + return -EOPNOTSUPP; if (fsm->loc_sof != on) { fsm->loc_sof = on; fsm->ops->loc_sof(fsm, on); } + return 0; } -static inline void otg_start_pulse(struct otg_fsm *fsm) +static inline int otg_start_pulse(struct otg_fsm *fsm) { + if (!fsm->ops->start_pulse) + return -EOPNOTSUPP; fsm->ops->start_pulse(fsm); + return 0; } -static inline void otg_add_timer(struct otg_fsm *fsm, void *timer) +static inline int otg_add_timer(struct otg_fsm *fsm, void *timer) { + if (!fsm->ops->add_timer) + return -EOPNOTSUPP; fsm->ops->add_timer(fsm, timer); + return 0; } -static inline void otg_del_timer(struct otg_fsm *fsm, void *timer) +static inline int otg_del_timer(struct otg_fsm *fsm, void *timer) { + if (!fsm->ops->del_timer) + return -EOPNOTSUPP; fsm->ops->del_timer(fsm, timer); + return 0; } int otg_statemachine(struct otg_fsm *fsm); -- cgit v1.2.3 From 425d710172cee47ed5e18eefd3308d88643de76d Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Add and use missed helper functions This patch implements missed helper functions for start_gadget() and start_host() OTG FSM callbacks. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsm-usb.c | 8 ++++---- drivers/usb/phy/phy-fsm-usb.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index 7f4596606e18..78984591ee74 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -41,17 +41,17 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) fsm->protocol, protocol); /* stop old protocol */ if (fsm->protocol == PROTO_HOST) - ret = fsm->ops->start_host(fsm, 0); + ret = otg_start_host(fsm, 0); else if (fsm->protocol == PROTO_GADGET) - ret = fsm->ops->start_gadget(fsm, 0); + ret = otg_start_gadget(fsm, 0); if (ret) return ret; /* start new protocol */ if (protocol == PROTO_HOST) - ret = fsm->ops->start_host(fsm, 1); + ret = otg_start_host(fsm, 1); else if (protocol == PROTO_GADGET) - ret = fsm->ops->start_gadget(fsm, 1); + ret = otg_start_gadget(fsm, 1); if (ret) return ret; diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 0f3f7d87f887..157f10672767 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -160,6 +160,20 @@ static inline int otg_del_timer(struct otg_fsm *fsm, void *timer) return 0; } +static inline int otg_start_host(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->start_host) + return -EOPNOTSUPP; + return fsm->ops->start_host(fsm, on); +} + +static inline int otg_start_gadget(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->start_gadget) + return -EOPNOTSUPP; + return fsm->ops->start_gadget(fsm, on); +} + int otg_statemachine(struct otg_fsm *fsm); /* Defined by device specific driver, for different timer implementation */ -- cgit v1.2.3 From f6de27eed372f41646b7bd95d6903923f5308517 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Fix OTG FSM timer handling Get rid of using OTG driver specific timers by passing timer type to corresponding callbacks. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.c | 60 +++++++++++++++++++++++++++++++++++++++++-- drivers/usb/phy/phy-fsm-usb.c | 28 ++++++++++---------- drivers/usb/phy/phy-fsm-usb.h | 24 ++++++++++------- 3 files changed, 87 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 8b34694ac48f..649586169be5 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -375,6 +375,40 @@ void fsl_otg_uninit_timers(void) kfree(b_vbus_pulse_tmr); } +static struct fsl_otg_timer *fsl_otg_get_timer(enum otg_fsm_timer t) +{ + struct fsl_otg_timer *timer; + + /* REVISIT: use array of pointers to timers instead */ + switch (t) { + case A_WAIT_VRISE: + timer = a_wait_vrise_tmr; + break; + case A_WAIT_BCON: + timer = a_wait_vrise_tmr; + break; + case A_AIDL_BDIS: + timer = a_wait_vrise_tmr; + break; + case B_ASE0_BRST: + timer = a_wait_vrise_tmr; + break; + case B_SE0_SRP: + timer = a_wait_vrise_tmr; + break; + case B_SRP_FAIL: + timer = a_wait_vrise_tmr; + break; + case A_WAIT_ENUM: + timer = a_wait_vrise_tmr; + break; + default: + timer = NULL; + } + + return timer; +} + /* Add timer to timer list */ void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer) { @@ -394,6 +428,17 @@ void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer) list_add_tail(&timer->list, &active_timers); } +static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct fsl_otg_timer *timer; + + timer = fsl_otg_get_timer(t); + if (!timer) + return; + + fsl_otg_add_timer(fsm, timer); +} + /* Remove timer from the timer list; clear timeout status */ void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer) { @@ -405,6 +450,17 @@ void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer) list_del(&timer->list); } +static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ + struct fsl_otg_timer *timer; + + timer = fsl_otg_get_timer(t); + if (!timer) + return; + + fsl_otg_del_timer(fsm, timer); +} + /* * Reduce timer count by 1, and find timeout conditions. * Called by fsl_otg 1ms timer interrupt @@ -757,8 +813,8 @@ static struct otg_fsm_ops fsl_otg_ops = { .loc_sof = fsl_otg_loc_sof, .start_pulse = fsl_otg_start_pulse, - .add_timer = fsl_otg_add_timer, - .del_timer = fsl_otg_del_timer, + .add_timer = fsl_otg_fsm_add_timer, + .del_timer = fsl_otg_fsm_del_timer, .start_host = fsl_otg_start_host, .start_gadget = fsl_otg_start_gadget, diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index 78984591ee74..f8fe7ec620e6 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -69,7 +69,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) { switch (old_state) { case OTG_STATE_B_IDLE: - otg_del_timer(fsm, b_se0_srp_tmr); + otg_del_timer(fsm, B_SE0_SRP); fsm->b_se0_srp = 0; break; case OTG_STATE_B_SRP_INIT: @@ -78,7 +78,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) case OTG_STATE_B_PERIPHERAL: break; case OTG_STATE_B_WAIT_ACON: - otg_del_timer(fsm, b_ase0_brst_tmr); + otg_del_timer(fsm, B_ASE0_BRST); fsm->b_ase0_brst_tmout = 0; break; case OTG_STATE_B_HOST: @@ -86,25 +86,25 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) case OTG_STATE_A_IDLE: break; case OTG_STATE_A_WAIT_VRISE: - otg_del_timer(fsm, a_wait_vrise_tmr); + otg_del_timer(fsm, A_WAIT_VRISE); fsm->a_wait_vrise_tmout = 0; break; case OTG_STATE_A_WAIT_BCON: - otg_del_timer(fsm, a_wait_bcon_tmr); + otg_del_timer(fsm, A_WAIT_BCON); fsm->a_wait_bcon_tmout = 0; break; case OTG_STATE_A_HOST: - otg_del_timer(fsm, a_wait_enum_tmr); + otg_del_timer(fsm, A_WAIT_ENUM); break; case OTG_STATE_A_SUSPEND: - otg_del_timer(fsm, a_aidl_bdis_tmr); + otg_del_timer(fsm, A_AIDL_BDIS); fsm->a_aidl_bdis_tmout = 0; fsm->a_suspend_req = 0; break; case OTG_STATE_A_PERIPHERAL: break; case OTG_STATE_A_WAIT_VFALL: - otg_del_timer(fsm, a_wait_vrise_tmr); + otg_del_timer(fsm, A_WAIT_VRISE); break; case OTG_STATE_A_VBUS_ERR: break; @@ -128,13 +128,13 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_UNDEF); - otg_add_timer(fsm, b_se0_srp_tmr); + otg_add_timer(fsm, B_SE0_SRP); break; case OTG_STATE_B_SRP_INIT: otg_start_pulse(fsm); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_UNDEF); - otg_add_timer(fsm, b_srp_fail_tmr); + otg_add_timer(fsm, B_SRP_FAIL); break; case OTG_STATE_B_PERIPHERAL: otg_chrg_vbus(fsm, 0); @@ -147,7 +147,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, b_ase0_brst_tmr); + otg_add_timer(fsm, B_ASE0_BRST); fsm->a_bus_suspend = 0; break; case OTG_STATE_B_HOST: @@ -170,14 +170,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_wait_vrise_tmr); + otg_add_timer(fsm, A_WAIT_VRISE); break; case OTG_STATE_A_WAIT_BCON: otg_drv_vbus(fsm, 1); otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_wait_bcon_tmr); + otg_add_timer(fsm, A_WAIT_BCON); break; case OTG_STATE_A_HOST: otg_drv_vbus(fsm, 1); @@ -189,14 +189,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) * suspend too fast to complete a_set_b_hnp_en */ if (!fsm->a_bus_req || fsm->a_suspend_req) - otg_add_timer(fsm, a_wait_enum_tmr); + otg_add_timer(fsm, A_WAIT_ENUM); break; case OTG_STATE_A_SUSPEND: otg_drv_vbus(fsm, 1); otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_aidl_bdis_tmr); + otg_add_timer(fsm, A_AIDL_BDIS); break; case OTG_STATE_A_PERIPHERAL: diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 157f10672767..b47b32c6ed1f 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -34,6 +34,17 @@ #define PROTO_HOST (1) #define PROTO_GADGET (2) +enum otg_fsm_timer { + A_WAIT_VRISE, + A_WAIT_BCON, + A_AIDL_BDIS, + B_ASE0_BRST, + B_SE0_SRP, + B_SRP_FAIL, + A_WAIT_ENUM, + NUM_OTG_FSM_TIMERS, +}; + /* OTG state machine according to the OTG spec */ struct otg_fsm { /* Input */ @@ -88,8 +99,8 @@ struct otg_fsm_ops { void (*loc_conn)(struct otg_fsm *fsm, int on); void (*loc_sof)(struct otg_fsm *fsm, int on); void (*start_pulse)(struct otg_fsm *fsm); - void (*add_timer)(struct otg_fsm *fsm, void *timer); - void (*del_timer)(struct otg_fsm *fsm, void *timer); + void (*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); + void (*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); int (*start_host)(struct otg_fsm *fsm, int on); int (*start_gadget)(struct otg_fsm *fsm, int on); }; @@ -144,7 +155,7 @@ static inline int otg_start_pulse(struct otg_fsm *fsm) return 0; } -static inline int otg_add_timer(struct otg_fsm *fsm, void *timer) +static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) { if (!fsm->ops->add_timer) return -EOPNOTSUPP; @@ -152,7 +163,7 @@ static inline int otg_add_timer(struct otg_fsm *fsm, void *timer) return 0; } -static inline int otg_del_timer(struct otg_fsm *fsm, void *timer) +static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) { if (!fsm->ops->del_timer) return -EOPNOTSUPP; @@ -175,8 +186,3 @@ static inline int otg_start_gadget(struct otg_fsm *fsm, int on) } int otg_statemachine(struct otg_fsm *fsm); - -/* Defined by device specific driver, for different timer implementation */ -extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, - *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr, - *a_wait_enum_tmr; -- cgit v1.2.3 From 3294908bc0f178bfd67971fdb4432f3d4e50921e Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Add and use missed OTG FSM timers a_bidl_adis_tmr and a_wait_vfall_tmr OTG timers missed in current FSM implementation. This patch adds and makes use of the timers as speicfied in OTG and EH supplement to USB2.0. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsm-usb.c | 12 +++++++++--- drivers/usb/phy/phy-fsm-usb.h | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index f8fe7ec620e6..5e899edcaf39 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -102,8 +102,12 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) fsm->a_suspend_req = 0; break; case OTG_STATE_A_PERIPHERAL: + otg_del_timer(fsm, A_BIDL_ADIS); + fsm->a_bidl_adis_tmout = 0; break; case OTG_STATE_A_WAIT_VFALL: + otg_del_timer(fsm, A_WAIT_VFALL); + fsm->a_wait_vfall_tmout = 0; otg_del_timer(fsm, A_WAIT_VRISE); break; case OTG_STATE_A_VBUS_ERR: @@ -204,12 +208,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_GADGET); otg_drv_vbus(fsm, 1); + otg_add_timer(fsm, A_BIDL_ADIS); break; case OTG_STATE_A_WAIT_VFALL: otg_drv_vbus(fsm, 0); otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); otg_set_protocol(fsm, PROTO_HOST); + otg_add_timer(fsm, A_WAIT_VFALL); break; case OTG_STATE_A_VBUS_ERR: otg_drv_vbus(fsm, 0); @@ -324,14 +330,14 @@ int otg_statemachine(struct otg_fsm *fsm) case OTG_STATE_A_PERIPHERAL: if (fsm->id || fsm->a_bus_drop) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); - else if (fsm->b_bus_suspend) + else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend) otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); else if (!fsm->a_vbus_vld) otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); break; case OTG_STATE_A_WAIT_VFALL: - if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld && - !fsm->b_conn)) + if (fsm->a_wait_vfall_tmout || fsm->id || fsm->a_bus_req || + (!fsm->a_sess_vld && !fsm->b_conn)) otg_set_state(fsm, OTG_STATE_A_IDLE); break; case OTG_STATE_A_VBUS_ERR: diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index b47b32c6ed1f..a74e14aaa839 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -35,13 +35,19 @@ #define PROTO_GADGET (2) enum otg_fsm_timer { + /* Standard OTG timers */ A_WAIT_VRISE, + A_WAIT_VFALL, A_WAIT_BCON, A_AIDL_BDIS, B_ASE0_BRST, + A_BIDL_ADIS, + + /* Auxiliary timers */ B_SE0_SRP, B_SRP_FAIL, A_WAIT_ENUM, + NUM_OTG_FSM_TIMERS, }; @@ -69,9 +75,11 @@ struct otg_fsm { /* Timeout indicator for timers */ int a_wait_vrise_tmout; + int a_wait_vfall_tmout; int a_wait_bcon_tmout; int a_aidl_bdis_tmout; int b_ase0_brst_tmout; + int a_bidl_adis_tmout; /* Informative variables */ int a_bus_drop; -- cgit v1.2.3 From cff4dab4cb95d394e9fd73f668326dac06e57b10 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Rename OTG FSM informative variables Mark informative variables with suffix '_inf' to distinguish them from other non-informative variables with the same name. If such non-informative varialbes were missed, they are created. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.c | 2 +- drivers/usb/phy/phy-fsm-usb.c | 6 +++--- drivers/usb/phy/phy-fsm-usb.h | 14 +++++++++----- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 649586169be5..d13ccd58a423 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -1113,7 +1113,7 @@ static long fsl_otg_ioctl(struct file *file, unsigned int cmd, break; case SET_A_SUSPEND_REQ: - fsl_otg_dev->fsm.a_suspend_req = arg; + fsl_otg_dev->fsm.a_suspend_req_inf = arg; break; case SET_A_BUS_DROP: diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index 5e899edcaf39..cb0367c8e7a7 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -99,7 +99,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) case OTG_STATE_A_SUSPEND: otg_del_timer(fsm, A_AIDL_BDIS); fsm->a_aidl_bdis_tmout = 0; - fsm->a_suspend_req = 0; + fsm->a_suspend_req_inf = 0; break; case OTG_STATE_A_PERIPHERAL: otg_del_timer(fsm, A_BIDL_ADIS); @@ -192,7 +192,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) * When HNP is triggered while a_bus_req = 0, a_host will * suspend too fast to complete a_set_b_hnp_en */ - if (!fsm->a_bus_req || fsm->a_suspend_req) + if (!fsm->a_bus_req || fsm->a_suspend_req_inf) otg_add_timer(fsm, A_WAIT_ENUM); break; case OTG_STATE_A_SUSPEND: @@ -307,7 +307,7 @@ int otg_statemachine(struct otg_fsm *fsm) otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); break; case OTG_STATE_A_HOST: - if ((!fsm->a_bus_req || fsm->a_suspend_req) && + if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) && fsm->otg->host->b_hnp_enable) otg_set_state(fsm, OTG_STATE_A_SUSPEND); else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop) diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index a74e14aaa839..4049e5cc4abb 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -54,9 +54,12 @@ enum otg_fsm_timer { /* OTG state machine according to the OTG spec */ struct otg_fsm { /* Input */ + int a_bus_drop; + int a_bus_req; int a_bus_resume; int a_bus_suspend; int a_conn; + int b_bus_req; int a_sess_vld; int a_srp_det; int a_vbus_vld; @@ -72,6 +75,7 @@ struct otg_fsm { int a_set_b_hnp_en; int b_srp_done; int b_hnp_enable; + int a_clr_err; /* Timeout indicator for timers */ int a_wait_vrise_tmout; @@ -82,11 +86,11 @@ struct otg_fsm { int a_bidl_adis_tmout; /* Informative variables */ - int a_bus_drop; - int a_bus_req; - int a_clr_err; - int a_suspend_req; - int b_bus_req; + int a_bus_drop_inf; + int a_bus_req_inf; + int a_clr_err_inf; + int a_suspend_req_inf; + int b_bus_req_inf; /* Output */ int drv_vbus; -- cgit v1.2.3 From 68041785d0c69884c4adb3bcab48f92ac3e75629 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Rename "B-device session end SRP" OTG FSM input In accordance with OTG and EH supplement, the correct name of the FSM input is b_ssend_srp. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.c | 4 ++-- drivers/usb/phy/phy-fsm-usb.c | 2 +- drivers/usb/phy/phy-fsm-usb.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index d13ccd58a423..7f3c73b967ce 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -1067,7 +1067,7 @@ static int show_fsl_usb2_otg_state(struct device *dev, "b_bus_suspend: %d\n" "b_conn: %d\n" "b_se0_srp: %d\n" - "b_sess_end: %d\n" + "b_ssend_srp: %d\n" "b_sess_vld: %d\n" "id: %d\n", fsm->a_bus_req, @@ -1082,7 +1082,7 @@ static int show_fsl_usb2_otg_state(struct device *dev, fsm->b_bus_suspend, fsm->b_conn, fsm->b_se0_srp, - fsm->b_sess_end, + fsm->b_ssend_srp, fsm->b_sess_vld, fsm->id); size -= t; diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index cb0367c8e7a7..d5c6db004531 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -256,7 +256,7 @@ int otg_statemachine(struct otg_fsm *fsm) otg_set_state(fsm, OTG_STATE_A_IDLE); else if (fsm->b_sess_vld && fsm->otg->gadget) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); - else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp) + else if (fsm->b_bus_req && fsm->b_ssend_srp && fsm->b_se0_srp) otg_set_state(fsm, OTG_STATE_B_SRP_INIT); break; case OTG_STATE_B_SRP_INIT: diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 4049e5cc4abb..2f185ed0f54f 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -67,7 +67,7 @@ struct otg_fsm { int b_bus_suspend; int b_conn; int b_se0_srp; - int b_sess_end; + int b_ssend_srp; int b_sess_vld; int id; -- cgit v1.2.3 From ec04996a080d825f8acdf0f8fbb2f3ebd5963cf3 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Add and use missed OTG FSM inputs/outputs Several input/output variables missed in current FSM implementation. This patch adds and makes use of them as specified in OTG and EH supplement to USB2.0. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsm-usb.c | 18 +++++++++++++++--- drivers/usb/phy/phy-fsm-usb.h | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index d5c6db004531..329c2d2f8595 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -71,8 +71,11 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) case OTG_STATE_B_IDLE: otg_del_timer(fsm, B_SE0_SRP); fsm->b_se0_srp = 0; + fsm->adp_sns = 0; + fsm->adp_prb = 0; break; case OTG_STATE_B_SRP_INIT: + fsm->data_pulse = 0; fsm->b_srp_done = 0; break; case OTG_STATE_B_PERIPHERAL: @@ -84,6 +87,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) case OTG_STATE_B_HOST: break; case OTG_STATE_A_IDLE: + fsm->adp_prb = 0; break; case OTG_STATE_A_WAIT_VRISE: otg_del_timer(fsm, A_WAIT_VRISE); @@ -131,6 +135,11 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_chrg_vbus(fsm, 0); otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); + /* + * Driver is responsible for starting ADP probing + * if ADP sensing times out. + */ + otg_start_adp_sns(fsm); otg_set_protocol(fsm, PROTO_UNDEF); otg_add_timer(fsm, B_SE0_SRP); break; @@ -167,6 +176,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) otg_chrg_vbus(fsm, 0); otg_loc_conn(fsm, 0); otg_loc_sof(fsm, 0); + otg_start_adp_prb(fsm); otg_set_protocol(fsm, PROTO_HOST); break; case OTG_STATE_A_WAIT_VRISE: @@ -256,7 +266,8 @@ int otg_statemachine(struct otg_fsm *fsm) otg_set_state(fsm, OTG_STATE_A_IDLE); else if (fsm->b_sess_vld && fsm->otg->gadget) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); - else if (fsm->b_bus_req && fsm->b_ssend_srp && fsm->b_se0_srp) + else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) && + fsm->b_ssend_srp && fsm->b_se0_srp) otg_set_state(fsm, OTG_STATE_B_SRP_INIT); break; case OTG_STATE_B_SRP_INIT: @@ -283,13 +294,14 @@ int otg_statemachine(struct otg_fsm *fsm) case OTG_STATE_B_HOST: if (!fsm->id || !fsm->b_sess_vld) otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (!fsm->b_bus_req || !fsm->a_conn) + else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device) otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); break; case OTG_STATE_A_IDLE: if (fsm->id) otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det)) + else if (!fsm->a_bus_drop && (fsm->a_bus_req || + fsm->a_srp_det || fsm->adp_change || fsm->power_up)) otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); break; case OTG_STATE_A_WAIT_VRISE: diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 2f185ed0f54f..6ce3b3cfd7b5 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -54,6 +54,9 @@ enum otg_fsm_timer { /* OTG state machine according to the OTG spec */ struct otg_fsm { /* Input */ + int adp_change; + int power_up; + int test_device; int a_bus_drop; int a_bus_req; int a_bus_resume; @@ -93,9 +96,12 @@ struct otg_fsm { int b_bus_req_inf; /* Output */ + int data_pulse; int drv_vbus; int loc_conn; int loc_sof; + int adp_prb; + int adp_sns; struct otg_fsm_ops *ops; struct usb_otg *otg; @@ -111,6 +117,8 @@ struct otg_fsm_ops { void (*loc_conn)(struct otg_fsm *fsm, int on); void (*loc_sof)(struct otg_fsm *fsm, int on); void (*start_pulse)(struct otg_fsm *fsm); + void (*start_adp_prb)(struct otg_fsm *fsm); + void (*start_adp_sns)(struct otg_fsm *fsm); void (*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); void (*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); int (*start_host)(struct otg_fsm *fsm, int on); @@ -163,7 +171,33 @@ static inline int otg_start_pulse(struct otg_fsm *fsm) { if (!fsm->ops->start_pulse) return -EOPNOTSUPP; - fsm->ops->start_pulse(fsm); + if (!fsm->data_pulse) { + fsm->data_pulse = 1; + fsm->ops->start_pulse(fsm); + } + return 0; +} + +static inline int otg_start_adp_prb(struct otg_fsm *fsm) +{ + if (!fsm->ops->start_adp_prb) + return -EOPNOTSUPP; + if (!fsm->adp_prb) { + fsm->adp_sns = 0; + fsm->adp_prb = 1; + fsm->ops->start_adp_prb(fsm); + } + return 0; +} + +static inline int otg_start_adp_sns(struct otg_fsm *fsm) +{ + if (!fsm->ops->start_adp_sns) + return -EOPNOTSUPP; + if (!fsm->adp_sns) { + fsm->adp_sns = 1; + fsm->ops->start_adp_sns(fsm); + } return 0; } -- cgit v1.2.3 From 4662e5ef54f01ff5333474a825f90ab74f95bc3d Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Thu, 3 Oct 2013 12:42:04 +0900 Subject: usb: phy: Reordering of OTG FSM variables Reorder variables in struct otg_fsm as they appear in OTG and EH supplement to USB2.0. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsm-usb.h | 46 ++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h index 6ce3b3cfd7b5..7441b46a27f1 100644 --- a/drivers/usb/phy/phy-fsm-usb.h +++ b/drivers/usb/phy/phy-fsm-usb.h @@ -54,25 +54,34 @@ enum otg_fsm_timer { /* OTG state machine according to the OTG spec */ struct otg_fsm { /* Input */ + int id; int adp_change; int power_up; int test_device; int a_bus_drop; int a_bus_req; + int a_srp_det; + int a_vbus_vld; + int b_conn; int a_bus_resume; int a_bus_suspend; int a_conn; int b_bus_req; - int a_sess_vld; - int a_srp_det; - int a_vbus_vld; - int b_bus_resume; - int b_bus_suspend; - int b_conn; int b_se0_srp; int b_ssend_srp; int b_sess_vld; - int id; + /* Auxilary inputs */ + int a_sess_vld; + int b_bus_resume; + int b_bus_suspend; + + /* Output */ + int data_pulse; + int drv_vbus; + int loc_conn; + int loc_sof; + int adp_prb; + int adp_sns; /* Internal variables */ int a_set_b_hnp_en; @@ -80,6 +89,14 @@ struct otg_fsm { int b_hnp_enable; int a_clr_err; + /* Informative variables */ + int a_bus_drop_inf; + int a_bus_req_inf; + int a_clr_err_inf; + int b_bus_req_inf; + /* Auxilary informative variables */ + int a_suspend_req_inf; + /* Timeout indicator for timers */ int a_wait_vrise_tmout; int a_wait_vfall_tmout; @@ -88,21 +105,6 @@ struct otg_fsm { int b_ase0_brst_tmout; int a_bidl_adis_tmout; - /* Informative variables */ - int a_bus_drop_inf; - int a_bus_req_inf; - int a_clr_err_inf; - int a_suspend_req_inf; - int b_bus_req_inf; - - /* Output */ - int data_pulse; - int drv_vbus; - int loc_conn; - int loc_sof; - int adp_prb; - int adp_sns; - struct otg_fsm_ops *ops; struct usb_otg *otg; -- cgit v1.2.3 From 13613c133bb8dc70ec404b61345496ba75611dbd Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 2 Oct 2013 11:17:29 +0200 Subject: usb: gadget: s3c-hsotg: fix maxpacket size This patch changes ep maxpacket value from 512 to 1024, because it's needed to handle interupt and isochronous endpoints in high-speed mode. This change doesn't affect on driver functioning, because fifo size (3072) is still enough for the maximum transaction payload (3*1024 for high-speed high-bandwidtch endpoints). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 24973d71e29a..4691df732c42 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3068,7 +3068,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, hs_ep->parent = hsotg; hs_ep->ep.name = hs_ep->name; - hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; + hs_ep->ep.maxpacket = epnum ? 1024 : EP0_MPS_LIMIT; hs_ep->ep.ops = &s3c_hsotg_ep_ops; /* -- cgit v1.2.3 From 7fc031e612238a7bbf6e989001abc5ce274bcba6 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Fri, 4 Oct 2013 15:30:21 -0700 Subject: usb: g_ffs: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If USB_FUNCTIONFS is selected without USB_FUNCTIONFS_ETH and USB_FUNCTIONFS_RNIS, u_ether.h won't be included and then USB_ETHERNET_MODULE_PARAMAETERS macro won't be available causing the following warning compilation: drivers/usb/gadget/g_ffs.c:81:1: warning: data definition has no type or storage class [enabled by default] drivers/usb/gadget/g_ffs.c:81:1: warning: type defaults to ‘int’ in declaration of ‘USB_ETHERNET_MODULE_PARAMETERS’ [-Wimplicit-int] drivers/usb/gadget/g_ffs.c:81:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] This patch fixes the warning by making USB_ETHERNET_MODULE_PARAMETERS to be used iff u_ether.h is included, otherwise it is not needed. Signed-off-by: David Cohen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/g_ffs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 5327c82472ed..2344efe4f4ce 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -76,7 +76,9 @@ struct gfs_ffs_obj { USB_GADGET_COMPOSITE_OPTIONS(); +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS USB_ETHERNET_MODULE_PARAMETERS(); +#endif static struct usb_device_descriptor gfs_dev_desc = { .bLength = sizeof gfs_dev_desc, -- cgit v1.2.3 From dc807576d239239433cbb95d891ea23a820528c1 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Sun, 6 Oct 2013 08:44:35 +0200 Subject: usb: gadget: mv_u3d_core: remove deprecated IRQF_DISABLED This patch proposes to remove the use of the IRQF_DISABLED flag It's a NOOP since 2.6.35 and it will be removed one day. Signed-off-by: Michael Opdenacker Signed-off-by: Felipe Balbi --- drivers/usb/gadget/mv_u3d_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index 4d31177d5d99..234711eabea1 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -1938,7 +1938,7 @@ static int mv_u3d_probe(struct platform_device *dev) } u3d->irq = r->start; if (request_irq(u3d->irq, mv_u3d_irq, - IRQF_DISABLED | IRQF_SHARED, driver_name, u3d)) { + IRQF_SHARED, driver_name, u3d)) { u3d->irq = 0; dev_err(&dev->dev, "Request irq %d for u3d failed\n", u3d->irq); -- cgit v1.2.3 From e9edd199d69034fa163c97ef310ca72dca9cf030 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 9 Oct 2013 08:20:02 +0200 Subject: usb: gadget: s3c-hsotg: fix set_ep_maxpacket function This patch fixes max packet size check in s3c_hsotg_set_ep_maxpacket() function. According USB specification, bits 10..0 of mps specifies maximum packet size, so there is bitwise AND between mps and 0x7ff value. Also added check if maxpacket isn't grater than 1024 which is maximum size od single USB transaction. In s3c_hsotg_ep_enable() function added s3c_hsotg_set_ep_maxpacket() call instead of setting ep.maxpacket value directly. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 4691df732c42..424b2ad00ec7 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1705,15 +1705,14 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, mpsval = s3c_hsotg_ep0_mps(mps); if (mpsval > 3) goto bad_mps; + hs_ep->ep.maxpacket = mps; } else { - if (mps >= DxEPCTL_MPS_LIMIT+1) + mpsval = mps & DxEPCTL_MPS_MASK; + if (mpsval > 1024) goto bad_mps; - - mpsval = mps; + hs_ep->ep.maxpacket = mpsval; } - hs_ep->ep.maxpacket = mps; - /* * update both the in and out endpoint controldir_ registers, even * if one of the directions may not be in use. @@ -2579,7 +2578,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, epctrl |= DxEPCTL_SNAK; /* update the endpoint state */ - hs_ep->ep.maxpacket = mps; + s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); /* default, set to non-periodic */ hs_ep->periodic = 0; -- cgit v1.2.3 From 8502d66d33704d66d29c715ba5e91192b554cef0 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:52 +0200 Subject: usb: gadget: f_mass_storage: create _fsg_common_free_buffers When configfs is in place, gadgets will have to be able to free fsg buffers. Add a helper function. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 32e5ab73f746..59a12c168cc5 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2642,6 +2642,18 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } +static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) +{ + if (buffhds) { + struct fsg_buffhd *bh = buffhds; + while (n--) { + kfree(bh->buf); + ++bh; + } + kfree(buffhds); + } +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2897,15 +2909,7 @@ static void fsg_common_release(struct kref *ref) kfree(common->luns); } - { - struct fsg_buffhd *bh = common->buffhds; - unsigned i = common->fsg_num_buffers; - do { - kfree(bh->buf); - } while (++bh, --i); - } - - kfree(common->buffhds); + _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); if (common->free_storage_on_release) kfree(common); } -- cgit v1.2.3 From bd528d4e699b212a763eecda9cacffb4b85a5fe6 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:53 +0200 Subject: usb: gadget: f_mass_storage: make sysfs interface optional When configfs is in place, the luns will not be represented in sysfs, so there will be no struct device associated with a lun. In order to maintain compatibility and allow configfs adoption sysfs is made optional in this patch. As a consequence some debug macros need to be adjusted. Two new fields are added to struct fsg_lun: name and name_pfx. The "name" is for storing a string which is presented to the user instead of the dev_name. The "name_pfx", if non-NULL, is prepended to the "name" at printing time. The name_pfx is for a future lun.0, which will be a default group in mass_storage.. By design at USB function configfs group's creation time its name is not known (but instead set a bit later in drivers/usb/gadget/configfs.c:function_make) and it is this name that serves the purpose of the said name prefix. So instead of copying a yet-unknown string a pointer to it is stored in struct fsg_lun. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 51 +++++++++++++++++++++++++++++-------- drivers/usb/gadget/f_mass_storage.h | 2 ++ drivers/usb/gadget/storage_common.h | 20 ++++++++++++--- 3 files changed, 59 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 59a12c168cc5..7034d9c8363f 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -299,6 +299,7 @@ struct fsg_common { unsigned int short_packet_received:1; unsigned int bad_lun_okay:1; unsigned int running:1; + unsigned int sysfs:1; int thread_wakeup_needed; struct completion thread_notifier; @@ -2642,6 +2643,11 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) +{ + common->sysfs = sysfs; +} + static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) { if (buffhds) { @@ -2654,6 +2660,34 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) } } +static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) +{ + device_remove_file(&lun->dev, &dev_attr_nofua); + /* + * device_remove_file() => + * + * here the attr (e.g. dev_attr_ro) is only used to be passed to: + * + * sysfs_remove_file() => + * + * here e.g. both dev_attr_ro_cdrom and dev_attr_ro are in + * the same namespace and + * from here only attr->name is passed to: + * + * sysfs_hash_and_remove() + * + * attr->name is the same for dev_attr_ro_cdrom and + * dev_attr_ro + * attr->name is the same for dev_attr_file and + * dev_attr_file_nonremovable + * + * so we don't differentiate between removing e.g. dev_attr_ro_cdrom + * and dev_attr_ro + */ + device_remove_file(&lun->dev, &dev_attr_ro); + device_remove_file(&lun->dev, &dev_attr_file); +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2687,6 +2721,8 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, memset(common, 0, sizeof *common); common->free_storage_on_release = 0; } + fsg_common_set_sysfs(common, true); + common->state = FSG_STATE_IDLE; common->fsg_num_buffers = cfg->fsg_num_buffers; common->buffhds = kcalloc(common->fsg_num_buffers, @@ -2746,6 +2782,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, /* curlun->dev.driver = &fsg_driver.driver; XXX */ dev_set_drvdata(&curlun->dev, &common->filesem); dev_set_name(&curlun->dev, "lun%d", i); + curlun->name = dev_name(&curlun->dev); rc = device_register(&curlun->dev); if (rc) { @@ -2892,17 +2929,11 @@ static void fsg_common_release(struct kref *ref) struct fsg_lun *lun = *lun_it; if (!lun) continue; - device_remove_file(&lun->dev, &dev_attr_nofua); - device_remove_file(&lun->dev, - lun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); - device_remove_file(&lun->dev, - lun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); + if (common->sysfs) + fsg_common_remove_sysfs(lun); fsg_lun_close(lun); - device_unregister(&lun->dev); + if (common->sysfs) + device_unregister(&lun->dev); kfree(lun); } diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index b64761d836f6..1b88eae75283 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -102,6 +102,8 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg); +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h index 1fcda2bfef6c..d8cc090aca35 100644 --- a/drivers/usb/gadget/storage_common.h +++ b/drivers/usb/gadget/storage_common.h @@ -17,10 +17,20 @@ #define VLDBG(lun, fmt, args...) do { } while (0) #endif /* VERBOSE_DEBUG */ -#define LDBG(lun, fmt, args...) dev_dbg(&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err(&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) +#define _LMSG(func, lun, fmt, args...) \ + do { \ + if ((lun)->name_pfx && *(lun)->name_pfx) \ + func("%s/%s: " fmt, *(lun)->name_pfx, \ + (lun)->name, ## args); \ + else \ + func("%s: " fmt, (lun)->name, ## args); \ + } while (0) + +#define LDBG(lun, fmt, args...) _LMSG(pr_debug, lun, fmt, ## args) +#define LERROR(lun, fmt, args...) _LMSG(pr_err, lun, fmt, ## args) +#define LWARN(lun, fmt, args...) _LMSG(pr_warn, lun, fmt, ## args) +#define LINFO(lun, fmt, args...) _LMSG(pr_info, lun, fmt, ## args) + #ifdef DUMP_MSGS @@ -100,6 +110,8 @@ struct fsg_lun { of bound block device */ unsigned int blksize; /* logical block size of bound block device */ struct device dev; + const char *name; /* "lun.name" */ + const char **name_pfx; /* "function.name" */ }; static inline bool fsg_lun_is_open(struct fsg_lun *curlun) -- cgit v1.2.3 From b24650df9521f1845571568684621cefb0ba4e3b Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:54 +0200 Subject: usb: gadget: f_mass_storage: create fsg_common_setup for use in fsg_common_init fsg_common_init is a lengthy function. Factor a portion of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 40 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 7034d9c8363f..da87ffe34514 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2643,6 +2643,27 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } +static struct fsg_common *fsg_common_setup(struct fsg_common *common) +{ + if (!common) { + common = kzalloc(sizeof(*common), GFP_KERNEL); + if (!common) + return ERR_PTR(-ENOMEM); + common->free_storage_on_release = 1; + } else { + memset(common, 0, sizeof(*common)); + common->free_storage_on_release = 0; + } + init_rwsem(&common->filesem); + spin_lock_init(&common->lock); + kref_init(&common->ref); + init_completion(&common->thread_notifier); + init_waitqueue_head(&common->fsg_wait); + common->state = FSG_STATE_TERMINATED; + + return common; +} + void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) { common->sysfs = sysfs; @@ -2711,16 +2732,9 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, return ERR_PTR(-EINVAL); } - /* Allocate? */ - if (!common) { - common = kzalloc(sizeof *common, GFP_KERNEL); - if (!common) - return ERR_PTR(-ENOMEM); - common->free_storage_on_release = 1; - } else { - memset(common, 0, sizeof *common); - common->free_storage_on_release = 0; - } + common = fsg_common_setup(common); + if (IS_ERR(common)) + return common; fsg_common_set_sysfs(common, true); common->state = FSG_STATE_IDLE; @@ -2760,8 +2774,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, } common->luns = curlun_it; - init_rwsem(&common->filesem); - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { struct fsg_lun *curlun; @@ -2855,8 +2867,6 @@ buffhds_first_it: common->can_stall = cfg->can_stall && !(gadget_is_at91(common->gadget)); - spin_lock_init(&common->lock); - kref_init(&common->ref); /* Tell the thread to start working */ common->thread_task = @@ -2865,8 +2875,6 @@ buffhds_first_it: rc = PTR_ERR(common->thread_task); goto error_release; } - init_completion(&common->thread_notifier); - init_waitqueue_head(&common->fsg_wait); /* Information */ INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); -- cgit v1.2.3 From 6313caace5f5b4fd2c23b9bc40ea26f252a28bf9 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:55 +0200 Subject: usb: gadget: f_mass_storage: create fsg_common_set_num_buffers for use in fsg_common_init fsg_common_init is a lengthy function. Factor a portion of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 72 +++++++++++++++++++++++-------------- drivers/usb/gadget/f_mass_storage.h | 2 ++ 2 files changed, 48 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index da87ffe34514..79d989979360 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2681,6 +2681,49 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) } } +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) +{ + struct fsg_buffhd *bh, *buffhds; + int i, rc; + + rc = fsg_num_buffers_validate(n); + if (rc != 0) + return rc; + + buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL); + if (!buffhds) + return -ENOMEM; + + /* Data buffers cyclic list */ + bh = buffhds; + i = n; + goto buffhds_first_it; + do { + bh->next = bh + 1; + ++bh; +buffhds_first_it: + bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); + if (unlikely(!bh->buf)) + goto error_release; + } while (--i); + bh->next = buffhds; + + _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); + common->fsg_num_buffers = n; + common->buffhds = buffhds; + + return 0; + +error_release: + /* + * "buf"s pointed to by heads after n - i are NULL + * so releasing them won't hurt + */ + _fsg_common_free_buffers(buffhds, n); + + return -ENOMEM; +} + static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) { device_remove_file(&lun->dev, &dev_attr_nofua); @@ -2714,17 +2757,12 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, struct fsg_config *cfg) { struct usb_gadget *gadget = cdev->gadget; - struct fsg_buffhd *bh; struct fsg_lun **curlun_it; struct fsg_lun_config *lcfg; struct usb_string *us; int nluns, i, rc; char *pathbuf; - rc = fsg_num_buffers_validate(cfg->fsg_num_buffers); - if (rc != 0) - return ERR_PTR(rc); - /* Find out how many LUNs there should be */ nluns = cfg->nluns; if (nluns < 1 || nluns > FSG_MAX_LUNS) { @@ -2738,15 +2776,12 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, fsg_common_set_sysfs(common, true); common->state = FSG_STATE_IDLE; - common->fsg_num_buffers = cfg->fsg_num_buffers; - common->buffhds = kcalloc(common->fsg_num_buffers, - sizeof *(common->buffhds), GFP_KERNEL); - if (!common->buffhds) { + rc = fsg_common_set_num_buffers(common, cfg->fsg_num_buffers); + if (rc) { if (common->free_storage_on_release) kfree(common); - return ERR_PTR(-ENOMEM); + return ERR_PTR(rc); } - common->ops = cfg->ops; common->private_data = cfg->private_data; @@ -2833,21 +2868,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, } common->nluns = nluns; - /* Data buffers cyclic list */ - bh = common->buffhds; - i = common->fsg_num_buffers; - goto buffhds_first_it; - do { - bh->next = bh + 1; - ++bh; -buffhds_first_it: - bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); - if (unlikely(!bh->buf)) { - rc = -ENOMEM; - goto error_release; - } - } while (--i); - bh->next = common->buffhds; /* Prepare inquiryString */ i = get_default_bcdDevice(); diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 1b88eae75283..a00f51a1d94b 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -104,6 +104,8 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -- cgit v1.2.3 From 70634170999a15e338b4091e06bd36ffdd283899 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:56 +0200 Subject: usb: gadget: f_mass_storage: create lun handling helpers for use in fsg_common_init fsg_common_init is a lengthy function. Factor portions of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 80 +++++++++++++++++++++++++++++-------- drivers/usb/gadget/f_mass_storage.h | 8 ++++ 2 files changed, 71 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 79d989979360..cb789fa885fd 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2752,6 +2752,64 @@ static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) device_remove_file(&lun->dev, &dev_attr_file); } +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +{ + if (sysfs) { + fsg_common_remove_sysfs(lun); + device_unregister(&lun->dev); + } + fsg_lun_close(lun); + kfree(lun); +} + +static void _fsg_common_remove_luns(struct fsg_common *common, int n) +{ + int i; + + for (i = 0; i < n; ++i) + if (common->luns[i]) { + fsg_common_remove_lun(common->luns[i], common->sysfs); + common->luns[i] = NULL; + } +} + +void fsg_common_remove_luns(struct fsg_common *common) +{ + _fsg_common_remove_luns(common, common->nluns); +} + +void fsg_common_free_luns(struct fsg_common *common) +{ + fsg_common_remove_luns(common); + kfree(common->luns); + common->luns = NULL; +} + +int fsg_common_set_nluns(struct fsg_common *common, int nluns) +{ + struct fsg_lun **curlun; + + /* Find out how many LUNs there should be */ + if (nluns < 1 || nluns > FSG_MAX_LUNS) { + pr_err("invalid number of LUNs: %u\n", nluns); + return -EINVAL; + } + + curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); + if (unlikely(!curlun)) + return -ENOMEM; + + if (common->luns) + fsg_common_free_luns(common); + + common->luns = curlun; + common->nluns = nluns; + + pr_info("Number of LUNs=%d\n", common->nluns); + + return 0; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2763,12 +2821,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, int nluns, i, rc; char *pathbuf; - /* Find out how many LUNs there should be */ - nluns = cfg->nluns; - if (nluns < 1 || nluns > FSG_MAX_LUNS) { - dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); - return ERR_PTR(-EINVAL); - } common = fsg_common_setup(common); if (IS_ERR(common)) @@ -2798,17 +2850,12 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, } fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id; - /* - * Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. - */ - curlun_it = kcalloc(nluns, sizeof(*curlun_it), GFP_KERNEL); - if (unlikely(!curlun_it)) { - rc = -ENOMEM; - goto error_release; - } - common->luns = curlun_it; + rc = fsg_common_set_nluns(common, cfg->nluns); + if (rc) + goto error_release; + curlun_it = common->luns; + nluns = cfg->nluns; for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { struct fsg_lun *curlun; @@ -2866,7 +2913,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, goto error_luns; } } - common->nluns = nluns; /* Prepare inquiryString */ diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index a00f51a1d94b..f98c792f36b0 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -106,6 +106,14 @@ void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); + +void fsg_common_remove_luns(struct fsg_common *common); + +void fsg_common_free_luns(struct fsg_common *common); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -- cgit v1.2.3 From a891d7a32f47118ce2ccfc8cac994aded8393fcd Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:57 +0200 Subject: usb: gadget: f_mass_storage: create fsg_common_set_cdev for use in fsg_common_init fsg_common_init is a lengthy function. Factor a portion of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 50 +++++++++++++++++++++---------------- drivers/usb/gadget/f_mass_storage.h | 3 +++ 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index cb789fa885fd..e61c0667b53a 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2810,6 +2810,33 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) return 0; } +int fsg_common_set_cdev(struct fsg_common *common, + struct usb_composite_dev *cdev, bool can_stall) +{ + struct usb_string *us; + + common->gadget = cdev->gadget; + common->ep0 = cdev->gadget->ep0; + common->ep0req = cdev->req; + common->cdev = cdev; + + us = usb_gstrings_attach(cdev, fsg_strings_array, + ARRAY_SIZE(fsg_strings)); + if (IS_ERR(us)) + return PTR_ERR(us); + + fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id; + + /* + * Some peripheral controllers are known not to be able to + * halt bulk endpoints correctly. If one of them is present, + * disable stalls. + */ + common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); + + return 0; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -2817,7 +2844,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_gadget *gadget = cdev->gadget; struct fsg_lun **curlun_it; struct fsg_lun_config *lcfg; - struct usb_string *us; int nluns, i, rc; char *pathbuf; @@ -2837,19 +2863,9 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, common->ops = cfg->ops; common->private_data = cfg->private_data; - common->gadget = gadget; - common->ep0 = gadget->ep0; - common->ep0req = cdev->req; - common->cdev = cdev; - - us = usb_gstrings_attach(cdev, fsg_strings_array, - ARRAY_SIZE(fsg_strings)); - if (IS_ERR(us)) { - rc = PTR_ERR(us); + rc = fsg_common_set_cdev(common, cdev, cfg->can_stall); + if (rc) goto error_release; - } - fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id; - rc = fsg_common_set_nluns(common, cfg->nluns); if (rc) @@ -2925,14 +2941,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, : "File-Stor Gadget"), i); - /* - * Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - common->can_stall = cfg->can_stall && - !(gadget_is_at91(common->gadget)); - /* Tell the thread to start working */ common->thread_task = diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index f98c792f36b0..de7aa32565b4 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -106,6 +106,9 @@ void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); +int fsg_common_set_cdev(struct fsg_common *common, + struct usb_composite_dev *cdev, bool can_stall); + void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); void fsg_common_remove_luns(struct fsg_common *common); -- cgit v1.2.3 From b27c08c953e994f792a03d9b7cbc5cf3f9844135 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:58 +0200 Subject: usb: gadget: f_mass_storage: create lun creation helpers for use in fsg_common_init fsg_common_init is a lengthy function. Factor portions of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 238 ++++++++++++++++++++++-------------- drivers/usb/gadget/f_mass_storage.h | 6 + 2 files changed, 153 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index e61c0667b53a..6a67e2ed75d9 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2837,16 +2837,154 @@ int fsg_common_set_cdev(struct fsg_common *common, return 0; } +static inline int fsg_common_add_sysfs(struct fsg_common *common, + struct fsg_lun *lun) +{ + int rc; + + rc = device_register(&lun->dev); + if (rc) { + put_device(&lun->dev); + return rc; + } + + rc = device_create_file(&lun->dev, + lun->cdrom + ? &dev_attr_ro_cdrom + : &dev_attr_ro); + if (rc) + goto error; + rc = device_create_file(&lun->dev, + lun->removable + ? &dev_attr_file + : &dev_attr_file_nonremovable); + if (rc) + goto error; + rc = device_create_file(&lun->dev, &dev_attr_nofua); + if (rc) + goto error; + + return 0; + +error: + /* removing nonexistent files is a no-op */ + fsg_common_remove_sysfs(lun); + device_unregister(&lun->dev); + return rc; +} + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id, const char *name, + const char **name_pfx) +{ + struct fsg_lun *lun; + char *pathbuf, *p; + int rc = -ENOMEM; + + if (!common->nluns || !common->luns) + return -ENODEV; + + if (common->luns[id]) + return -EBUSY; + + if (!cfg->filename && !cfg->removable) { + pr_err("no file given for LUN%d\n", id); + return -EINVAL; + } + + lun = kzalloc(sizeof(*lun), GFP_KERNEL); + if (!lun) + return -ENOMEM; + + lun->name_pfx = name_pfx; + + lun->cdrom = !!cfg->cdrom; + lun->ro = cfg->cdrom || cfg->ro; + lun->initially_ro = lun->ro; + lun->removable = !!cfg->removable; + + if (!common->sysfs) { + /* we DON'T own the name!*/ + lun->name = name; + } else { + lun->dev.release = fsg_lun_release; + lun->dev.parent = &common->gadget->dev; + dev_set_drvdata(&lun->dev, &common->filesem); + dev_set_name(&lun->dev, name); + lun->name = dev_name(&lun->dev); + + rc = fsg_common_add_sysfs(common, lun); + if (rc) { + pr_info("failed to register LUN%d: %d\n", id, rc); + goto error_sysfs; + } + } + + common->luns[id] = lun; + + if (cfg->filename) { + rc = fsg_lun_open(lun, cfg->filename); + if (rc) + goto error_lun; + } + + pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); + p = "(no medium)"; + if (fsg_lun_is_open(lun)) { + p = "(error)"; + if (pathbuf) { + p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); + if (IS_ERR(p)) + p = "(error)"; + } + } + pr_info("LUN: %s%s%sfile: %s\n", + lun->removable ? "removable " : "", + lun->ro ? "read only " : "", + lun->cdrom ? "CD-ROM " : "", + p); + kfree(pathbuf); + + return 0; + +error_lun: + if (common->sysfs) { + fsg_common_remove_sysfs(lun); + device_unregister(&lun->dev); + } + fsg_lun_close(lun); + common->luns[id] = NULL; +error_sysfs: + kfree(lun); + return rc; +} + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) +{ + char buf[8]; /* enough for 100000000 different numbers, decimal */ + int i, rc; + + for (i = 0; i < common->nluns; ++i) { + snprintf(buf, sizeof(buf), "lun%d", i); + rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); + if (rc) + goto fail; + } + + pr_info("Number of LUNs=%d\n", common->nluns); + + return 0; + +fail: + _fsg_common_remove_luns(common, i); + return rc; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) { - struct usb_gadget *gadget = cdev->gadget; - struct fsg_lun **curlun_it; - struct fsg_lun_config *lcfg; - int nluns, i, rc; - char *pathbuf; - + int i, rc; common = fsg_common_setup(common); if (IS_ERR(common)) @@ -2870,66 +3008,10 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, rc = fsg_common_set_nluns(common, cfg->nluns); if (rc) goto error_release; - curlun_it = common->luns; - nluns = cfg->nluns; - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun_it, ++lcfg) { - struct fsg_lun *curlun; - - curlun = kzalloc(sizeof(*curlun), GFP_KERNEL); - if (!curlun) { - rc = -ENOMEM; - common->nluns = i; - goto error_release; - } - *curlun_it = curlun; - - curlun->cdrom = !!lcfg->cdrom; - curlun->ro = lcfg->cdrom || lcfg->ro; - curlun->initially_ro = curlun->ro; - curlun->removable = lcfg->removable; - curlun->dev.release = fsg_lun_release; - curlun->dev.parent = &gadget->dev; - /* curlun->dev.driver = &fsg_driver.driver; XXX */ - dev_set_drvdata(&curlun->dev, &common->filesem); - dev_set_name(&curlun->dev, "lun%d", i); - curlun->name = dev_name(&curlun->dev); - - rc = device_register(&curlun->dev); - if (rc) { - INFO(common, "failed to register LUN%d: %d\n", i, rc); - common->nluns = i; - put_device(&curlun->dev); - kfree(curlun); - goto error_release; - } - - rc = device_create_file(&curlun->dev, - curlun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, - curlun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto error_luns; - - if (lcfg->filename) { - rc = fsg_lun_open(curlun, lcfg->filename); - if (rc) - goto error_luns; - } else if (!curlun->removable) { - ERROR(common, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto error_luns; - } - } + rc = fsg_common_create_luns(common, cfg); + if (rc) + goto error_release; /* Prepare inquiryString */ i = get_default_bcdDevice(); @@ -2941,7 +3023,6 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, : "File-Stor Gadget"), i); - /* Tell the thread to start working */ common->thread_task = kthread_create(fsg_main_thread, common, "file-storage"); @@ -2954,37 +3035,12 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); INFO(common, "Number of LUNs=%d\n", common->nluns); - pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0, nluns = common->nluns, curlun_it = common->luns; - i < nluns; - ++curlun_it, ++i) { - struct fsg_lun *curlun = *curlun_it; - char *p = "(no medium)"; - if (fsg_lun_is_open(curlun)) { - p = "(error)"; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = "(error)"; - } - } - LINFO(curlun, "LUN: %s%s%sfile: %s\n", - curlun->removable ? "removable " : "", - curlun->ro ? "read only " : "", - curlun->cdrom ? "CD-ROM " : "", - p); - } - kfree(pathbuf); - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); wake_up_process(common->thread_task); return common; -error_luns: - common->nluns = i + 1; error_release: common->state = FSG_STATE_TERMINATED; /* The thread is dead */ /* Call fsg_common_release() directly, ref might be not initialised. */ diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index de7aa32565b4..2a51e7b1cc60 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -117,6 +117,12 @@ void fsg_common_free_luns(struct fsg_common *common); int fsg_common_set_nluns(struct fsg_common *common, int nluns); +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, + unsigned int id, const char *name, + const char **name_pfx); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -- cgit v1.2.3 From 23682e3c78c54620ccc6e3462220851e1ae8b02f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:05:59 +0200 Subject: usb: gadget: f_mass_storage: create fsg_common_set_inquiry_string for use in fsg_common_init fsg_common_init is a lengthy function. Factor a portion of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 29 +++++++++++++++++++---------- drivers/usb/gadget/f_mass_storage.h | 3 +++ 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6a67e2ed75d9..93a26b365e6a 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2980,11 +2980,27 @@ fail: return rc; } +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, + const char *pn) +{ + int i; + + /* Prepare inquiryString */ + i = get_default_bcdDevice(); + snprintf(common->inquiry_string, sizeof(common->inquiry_string), + "%-8s%-16s%04x", vn ?: "Linux", + /* Assume product name dependent on the first LUN */ + pn ?: ((*common->luns)->cdrom + ? "File-CD Gadget" + : "File-Stor Gadget"), + i); +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) { - int i, rc; + int rc; common = fsg_common_setup(common); if (IS_ERR(common)) @@ -3013,16 +3029,9 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, if (rc) goto error_release; - /* Prepare inquiryString */ - i = get_default_bcdDevice(); - snprintf(common->inquiry_string, sizeof common->inquiry_string, - "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", - /* Assume product name dependent on the first LUN */ - cfg->product_name ?: ((*common->luns)->cdrom - ? "File-CD Gadget" - : "File-Stor Gadget"), - i); + fsg_common_set_inquiry_string(common, cfg->vendor_name, + cfg->product_name); /* Tell the thread to start working */ common->thread_task = kthread_create(fsg_main_thread, common, "file-storage"); diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 2a51e7b1cc60..34a15d6bc3ca 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -123,6 +123,9 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, + const char *pn); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -- cgit v1.2.3 From 5de862d73b2c1b3fbb0ac8b45eb496d77347d1b8 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:00 +0200 Subject: usb: gadget: f_mass_storage: create fsg_common_run_thread for use in fsg_common_init fsg_common_init is a lengthy function. Factor a portion of it out. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 32 +++++++++++++++++++++----------- drivers/usb/gadget/f_mass_storage.h | 2 ++ 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 93a26b365e6a..5b99aa1846c3 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2996,6 +2996,24 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, i); } +int fsg_common_run_thread(struct fsg_common *common) +{ + common->state = FSG_STATE_IDLE; + /* Tell the thread to start working */ + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + common->state = FSG_STATE_TERMINATED; + return PTR_ERR(common->thread_task); + } + + DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); + + wake_up_process(common->thread_task); + + return 0; +} + struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, struct fsg_config *cfg) @@ -3032,21 +3050,13 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, fsg_common_set_inquiry_string(common, cfg->vendor_name, cfg->product_name); - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); - if (IS_ERR(common->thread_task)) { - rc = PTR_ERR(common->thread_task); - goto error_release; - } /* Information */ INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); - INFO(common, "Number of LUNs=%d\n", common->nluns); - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - wake_up_process(common->thread_task); + rc = fsg_common_run_thread(common); + if (rc) + goto error_release; return common; diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 34a15d6bc3ca..7d9e0bc1cbf1 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -126,6 +126,8 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn); +int fsg_common_run_thread(struct fsg_common *common); + void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -- cgit v1.2.3 From e5eaa0dc4866181aff655ef3f94cd990172b751f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:01 +0200 Subject: usb: gadget: f_mass_storage: convert to new function interface with backward compatibility Converting mass storage to the new function interface requires converting the USB mass storage's function code and its users. This patch converts the f_mass_storage.c to the new function interface. The file is now compiled into a separate usb_f_mass_storage.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/acm_ms.c | 1 + drivers/usb/gadget/f_mass_storage.c | 178 +++++++++++++++++++++++++++++++----- drivers/usb/gadget/f_mass_storage.h | 15 +++ drivers/usb/gadget/mass_storage.c | 1 + drivers/usb/gadget/multi.c | 1 + 7 files changed, 179 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 98220dcca315..40adaf08d3a5 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -528,6 +528,9 @@ config USB_F_RNDIS config USB_U_MS tristate +config USB_F_MASS_STORAGE + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index d90a0b079182..4a86b0c06676 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -62,6 +62,8 @@ usb_f_rndis-y := f_rndis.o obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o u_ms-y := storage_common.o obj-$(CONFIG_USB_U_MS) += u_ms.o +usb_f_mass_storage-y := f_mass_storage.o +obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o # # USB gadget drivers diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 992ffb00272f..31aae8fce426 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -40,6 +40,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USB_FMS_INCLUDED #include "f_mass_storage.c" /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 5b99aa1846c3..a063cd5e5533 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -213,6 +213,7 @@ #include #include #include +#include #include #include @@ -226,6 +227,13 @@ #define FSG_DRIVER_DESC "Mass Storage Function" #define FSG_DRIVER_VERSION "2009/09/11" +/* to avoid a lot of #ifndef-#endif in the temporary compatibility layer */ +#ifndef USB_FMS_INCLUDED +#define EXPORT_SYMBOL_GPL_IF_MODULE(m) EXPORT_SYMBOL_GPL(m); +#else +#define EXPORT_SYMBOL_GPL_IF_MODULE(m) +#endif + static const char fsg_string_interface[] = "Mass Storage"; #include "storage_common.h" @@ -2627,11 +2635,13 @@ void fsg_common_get(struct fsg_common *common) { kref_get(&common->ref); } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_get); void fsg_common_put(struct fsg_common *common) { kref_put(&common->ref, fsg_common_release); } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_put); /* check if fsg_num_buffers is within a valid range */ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) @@ -2643,7 +2653,7 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } -static struct fsg_common *fsg_common_setup(struct fsg_common *common) +static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool zero) { if (!common) { common = kzalloc(sizeof(*common), GFP_KERNEL); @@ -2651,7 +2661,8 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common) return ERR_PTR(-ENOMEM); common->free_storage_on_release = 1; } else { - memset(common, 0, sizeof(*common)); + if (zero) + memset(common, 0, sizeof(*common)); common->free_storage_on_release = 0; } init_rwsem(&common->filesem); @@ -2668,6 +2679,7 @@ void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) { common->sysfs = sysfs; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_sysfs); static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) { @@ -2723,6 +2735,7 @@ error_release: return -ENOMEM; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_num_buffers); static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) { @@ -2761,6 +2774,7 @@ void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) fsg_lun_close(lun); kfree(lun); } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_remove_lun); static void _fsg_common_remove_luns(struct fsg_common *common, int n) { @@ -2772,6 +2786,7 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) common->luns[i] = NULL; } } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_remove_luns); void fsg_common_remove_luns(struct fsg_common *common) { @@ -2784,6 +2799,7 @@ void fsg_common_free_luns(struct fsg_common *common) kfree(common->luns); common->luns = NULL; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_free_luns); int fsg_common_set_nluns(struct fsg_common *common, int nluns) { @@ -2809,6 +2825,14 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) return 0; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_nluns); + +void fsg_common_free_buffers(struct fsg_common *common) +{ + _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); + common->buffhds = NULL; +} +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_free_buffers); int fsg_common_set_cdev(struct fsg_common *common, struct usb_composite_dev *cdev, bool can_stall) @@ -2836,6 +2860,7 @@ int fsg_common_set_cdev(struct fsg_common *common, return 0; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_cdev); static inline int fsg_common_add_sysfs(struct fsg_common *common, struct fsg_lun *lun) @@ -2958,6 +2983,7 @@ error_sysfs: kfree(lun); return rc; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_create_lun); int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) { @@ -2979,6 +3005,7 @@ fail: _fsg_common_remove_luns(common, i); return rc; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_create_luns); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn) @@ -2995,6 +3022,7 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, : "File-Stor Gadget"), i); } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_inquiry_string); int fsg_common_run_thread(struct fsg_common *common) { @@ -3013,6 +3041,7 @@ int fsg_common_run_thread(struct fsg_common *common) return 0; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_run_thread); struct fsg_common *fsg_common_init(struct fsg_common *common, struct usb_composite_dev *cdev, @@ -3020,7 +3049,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common, { int rc; - common = fsg_common_setup(common); + common = fsg_common_setup(common, !!common); if (IS_ERR(common)) return common; fsg_common_set_sysfs(common, true); @@ -3066,6 +3095,7 @@ error_release: fsg_common_release(&common->ref); return ERR_PTR(rc); } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_init); static void fsg_common_release(struct kref *ref) { @@ -3105,24 +3135,6 @@ static void fsg_common_release(struct kref *ref) /*-------------------------------------------------------------------------*/ -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct fsg_common *common = fsg->common; - - DBG(fsg, "unbind\n"); - if (fsg->common->fsg == fsg) { - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - /* FIXME: make interruptible or killable somehow? */ - wait_event(common->fsg_wait, common->fsg != fsg); - } - - fsg_common_put(common); - usb_free_all_descriptors(&fsg->function); - kfree(fsg); -} - static int fsg_bind(struct usb_configuration *c, struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); @@ -3132,6 +3144,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) unsigned max_burst; int ret; +#ifndef USB_FMS_INCLUDED + struct fsg_opts *opts; + opts = fsg_opts_from_func_inst(f->fi); + if (!opts->no_configfs) { + ret = fsg_common_set_cdev(fsg->common, c->cdev, + fsg->common->can_stall); + if (ret) + return ret; + fsg_common_set_inquiry_string(fsg->common, 0, 0); + ret = fsg_common_run_thread(fsg->common); + if (ret) + return ret; + } +#endif + fsg->gadget = gadget; /* New interface */ @@ -3183,7 +3210,31 @@ autoconf_fail: return -ENOTSUPP; } -/****************************** ADD FUNCTION ******************************/ +/****************************** ALLOCATE FUNCTION *************************/ + +static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; + + DBG(fsg, "unbind\n"); + if (fsg->common->fsg == fsg) { + fsg->common->new_fsg = NULL; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); + /* FIXME: make interruptible or killable somehow? */ + wait_event(common->fsg_wait, common->fsg != fsg); + } + +#ifdef USB_FMS_INCLUDED + fsg_common_put(common); +#endif + usb_free_all_descriptors(&fsg->function); +#ifdef USB_FMS_INCLUDED + kfree(fsg); +#endif +} + +#ifdef USB_FMS_INCLUDED static int fsg_bind_config(struct usb_composite_dev *cdev, struct usb_configuration *c, @@ -3220,6 +3271,88 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, return rc; } +#else + +static void fsg_free_inst(struct usb_function_instance *fi) +{ + struct fsg_opts *opts; + + opts = fsg_opts_from_func_inst(fi); + fsg_common_put(opts->common); + kfree(opts); +} + +static struct usb_function_instance *fsg_alloc_inst(void) +{ + struct fsg_opts *opts; + int rc; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + opts->func_inst.free_func_inst = fsg_free_inst; + opts->common = fsg_common_setup(opts->common, false); + if (IS_ERR(opts->common)) { + rc = PTR_ERR(opts->common); + goto release_opts; + } + rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS); + if (rc) + goto release_opts; + + rc = fsg_common_set_num_buffers(opts->common, + CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); + if (rc) + goto release_luns; + + pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); + + return &opts->func_inst; + +release_luns: + kfree(opts->common->luns); +release_opts: + kfree(opts); + return ERR_PTR(rc); +} + +static void fsg_free(struct usb_function *f) +{ + struct fsg_dev *fsg; + + fsg = container_of(f, struct fsg_dev, function); + + kfree(fsg); +} + +static struct usb_function *fsg_alloc(struct usb_function_instance *fi) +{ + struct fsg_opts *opts = fsg_opts_from_func_inst(fi); + struct fsg_common *common = opts->common; + struct fsg_dev *fsg; + + fsg = kzalloc(sizeof(*fsg), GFP_KERNEL); + if (unlikely(!fsg)) + return ERR_PTR(-ENOMEM); + + fsg->function.name = FSG_DRIVER_DESC; + fsg->function.bind = fsg_bind; + fsg->function.unbind = fsg_unbind; + fsg->function.setup = fsg_setup; + fsg->function.set_alt = fsg_set_alt; + fsg->function.disable = fsg_disable; + fsg->function.free_func = fsg_free; + + fsg->common = common; + + return &fsg->function; +} + +DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz"); + +#endif /************************* Module parameters *************************/ @@ -3256,4 +3389,5 @@ void fsg_config_from_params(struct fsg_config *cfg, cfg->can_stall = params->stall; cfg->fsg_num_buffers = fsg_num_buffers; } +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_config_from_params); diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 7d9e0bc1cbf1..42f7db408478 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -1,6 +1,7 @@ #ifndef USB_F_MASS_STORAGE_H #define USB_F_MASS_STORAGE_H +#include #include "storage_common.h" struct fsg_module_parameters { @@ -70,6 +71,12 @@ struct fsg_operations { int (*thread_exits)(struct fsg_common *common); }; +struct fsg_opts { + struct fsg_common *common; + struct usb_function_instance func_inst; + bool no_configfs; /* for legacy gadgets */ +}; + struct fsg_lun_config { const char *filename; char ro; @@ -94,6 +101,12 @@ struct fsg_config { unsigned int fsg_num_buffers; }; +static inline struct fsg_opts * +fsg_opts_from_func_inst(const struct usb_function_instance *fi) +{ + return container_of(fi, struct fsg_opts, func_inst); +} + void fsg_common_get(struct fsg_common *common); void fsg_common_put(struct fsg_common *common); @@ -106,6 +119,8 @@ void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); +void fsg_common_free_buffers(struct fsg_common *common); + int fsg_common_set_cdev(struct fsg_common *common, struct usb_composite_dev *cdev, bool can_stall); diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 4723d1b04cff..f6702514f5d7 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -55,6 +55,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USB_FMS_INCLUDED #include "f_mass_storage.c" /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 6867d9dbbca4..42a5bed75388 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -41,6 +41,7 @@ MODULE_LICENSE("GPL"); * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USB_FMS_INCLUDED #include "f_mass_storage.c" #define USBF_ECM_INCLUDED -- cgit v1.2.3 From 2412fbf1ffac21da14308924ccb17fe1a5506b1a Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:02 +0200 Subject: usb: gadget: mass_storage: convert to new interface of f_mass_storage Convert old mass_storage gadget to use the new interface of f_mass_storage so that later the compatibility layer in f_mass_storage can be removed. struct fsg_common is not known to mass_storage.c, so a setter method is added to f_mass_storage. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/f_mass_storage.c | 7 +++ drivers/usb/gadget/f_mass_storage.h | 3 + drivers/usb/gadget/mass_storage.c | 107 +++++++++++++++++++++++++++--------- 4 files changed, 91 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 40adaf08d3a5..7d64e474c48b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -885,6 +885,7 @@ config USB_MASS_STORAGE depends on BLOCK select USB_LIBCOMPOSITE select USB_U_MS + select USB_F_MASS_STORAGE help The Mass Storage Gadget acts as a USB Mass Storage disk drive. As its storage repository it can use a regular file or a block diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index a063cd5e5533..d6c2da0fb759 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2827,6 +2827,13 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) } EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_nluns); +void fsg_common_set_ops(struct fsg_common *common, + const struct fsg_operations *ops) +{ + common->ops = ops; +} +EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_ops); + void fsg_common_free_buffers(struct fsg_common *common) { _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 42f7db408478..b53cf8c9189e 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -132,6 +132,9 @@ void fsg_common_free_luns(struct fsg_common *common); int fsg_common_set_nluns(struct fsg_common *common, int nluns); +void fsg_common_set_ops(struct fsg_common *common, + const struct fsg_operations *ops); + int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, unsigned int id, const char *name, const char **name_pfx); diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index f6702514f5d7..8e27a8c96444 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -46,17 +46,7 @@ #define FSG_VENDOR_ID 0x0525 /* NetChip */ #define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ -/*-------------------------------------------------------------------------*/ - -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#define USB_FMS_INCLUDED -#include "f_mass_storage.c" +#include "f_mass_storage.h" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -107,6 +97,9 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; + /****************************** Configurations ******************************/ static struct fsg_module_parameters mod_data = { @@ -139,13 +132,7 @@ static int msg_thread_exits(struct fsg_common *common) static int __init msg_do_config(struct usb_configuration *c) { - static const struct fsg_operations ops = { - .thread_exits = msg_thread_exits, - }; - static struct fsg_common common; - - struct fsg_common *retp; - struct fsg_config config; + struct fsg_opts *opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -153,15 +140,24 @@ static int __init msg_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - fsg_config_from_params(&config, &mod_data, fsg_num_buffers); - config.ops = &ops; + opts = fsg_opts_from_func_inst(fi_msg); + + f_msg = usb_get_function(fi_msg); + if (IS_ERR(f_msg)) + return PTR_ERR(f_msg); - retp = fsg_common_init(&common, c->cdev, &config); - if (IS_ERR(retp)) - return PTR_ERR(retp); + ret = fsg_common_run_thread(opts->common); + if (ret) + goto put_func; - ret = fsg_bind_config(c->cdev, c, &common); - fsg_common_put(&common); + ret = usb_add_function(c, f_msg); + if (ret) + goto put_func; + + return 0; + +put_func: + usb_put_function(f_msg); return ret; } @@ -176,23 +172,79 @@ static struct usb_configuration msg_config_driver = { static int __init msg_bind(struct usb_composite_dev *cdev) { + static const struct fsg_operations ops = { + .thread_exits = msg_thread_exits, + }; + struct fsg_opts *opts; + struct fsg_config config; int status; + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) + return PTR_ERR(fi_msg); + + fsg_config_from_params(&config, &mod_data, fsg_num_buffers); + opts = fsg_opts_from_func_inst(fi_msg); + + opts->no_configfs = true; + status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); + if (status) + goto fail; + + status = fsg_common_set_nluns(opts->common, config.nluns); + if (status) + goto fail_set_nluns; + + fsg_common_set_ops(opts->common, &ops); + + status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); + if (status) + goto fail_set_cdev; + + fsg_common_set_sysfs(opts->common, true); + status = fsg_common_create_luns(opts->common, &config); + if (status) + goto fail_set_cdev; + + fsg_common_set_inquiry_string(opts->common, config.vendor_name, + config.product_name); + status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) - return status; + goto fail_string_ids; msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; status = usb_add_config(cdev, &msg_config_driver, msg_do_config); if (status < 0) - return status; + goto fail_string_ids; + usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&cdev->gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); set_bit(0, &msg_registered); return 0; + +fail_string_ids: + fsg_common_remove_luns(opts->common); +fail_set_cdev: + fsg_common_free_luns(opts->common); +fail_set_nluns: + fsg_common_free_buffers(opts->common); +fail: + usb_put_function_instance(fi_msg); + return status; } +static int msg_unbind(struct usb_composite_dev *cdev) +{ + if (!IS_ERR(f_msg)) + usb_put_function(f_msg); + + if (!IS_ERR(fi_msg)) + usb_put_function_instance(fi_msg); + + return 0; +} /****************************** Some noise ******************************/ @@ -203,6 +255,7 @@ static __refdata struct usb_composite_driver msg_driver = { .needs_serial = 1, .strings = dev_strings, .bind = msg_bind, + .unbind = msg_unbind, }; MODULE_DESCRIPTION(DRIVER_DESC); -- cgit v1.2.3 From 77850ae28607f33c1388928b9a4146ee2e0e57cf Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:03 +0200 Subject: usb: gadget: storage_common: make attribute operations more generic Show/store methods for sysfs attributes contain code which can be used also by configfs. Make them abstract the source the lun and rw_semaphore are taken from. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 27 +++++++++++++++++++++------ drivers/usb/gadget/storage_common.c | 31 ++++++------------------------- drivers/usb/gadget/storage_common.h | 21 +++++++++++---------- 3 files changed, 38 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index d6c2da0fb759..d80be5f0e6d2 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2581,37 +2581,52 @@ static int fsg_main_thread(void *common_) static ssize_t ro_show(struct device *dev, struct device_attribute *attr, char *buf) { - return fsg_show_ro(dev, attr, buf); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return fsg_show_ro(curlun, buf); } static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, char *buf) { - return fsg_show_nofua(dev, attr, buf); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return fsg_show_nofua(curlun, buf); } static ssize_t file_show(struct device *dev, struct device_attribute *attr, char *buf) { - return fsg_show_file(dev, attr, buf); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + + return fsg_show_file(curlun, filesem, buf); } static ssize_t ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return fsg_store_ro(dev, attr, buf, count); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + + return fsg_store_ro(curlun, filesem, buf, count); } static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return fsg_store_nofua(dev, attr, buf, count); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + + return fsg_store_nofua(curlun, buf, count); } static ssize_t file_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return fsg_store_file(dev, attr, buf, count); + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + + return fsg_store_file(curlun, filesem, buf, count); } static DEVICE_ATTR_RW(ro); diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3e2500f19140..969948dc2596 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -31,11 +31,6 @@ #include "storage_common.h" -static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ - return container_of(dev, struct fsg_lun, dev); -} - /* There is only one interface. */ struct usb_interface_descriptor fsg_intf_desc = { @@ -324,31 +319,23 @@ EXPORT_SYMBOL(store_cdrom_address); /*-------------------------------------------------------------------------*/ -ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf) { - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) ? curlun->ro : curlun->initially_ro); } EXPORT_SYMBOL(fsg_show_ro); -ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf) { - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - return sprintf(buf, "%u\n", curlun->nofua); } EXPORT_SYMBOL(fsg_show_nofua); -ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf) { - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); char *p; ssize_t rc; @@ -373,12 +360,10 @@ ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, EXPORT_SYMBOL(fsg_show_file); -ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) { ssize_t rc; - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); unsigned ro; rc = kstrtouint(buf, 2, &ro); @@ -404,10 +389,8 @@ ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL(fsg_store_ro); -ssize_t fsg_store_nofua(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) { - struct fsg_lun *curlun = fsg_lun_from_dev(dev); unsigned nofua; int ret; @@ -425,11 +408,9 @@ ssize_t fsg_store_nofua(struct device *dev, struct device_attribute *attr, } EXPORT_SYMBOL(fsg_store_nofua); -ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) { - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); int rc = 0; if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h index d8cc090aca35..16cf07bb9e75 100644 --- a/drivers/usb/gadget/storage_common.h +++ b/drivers/usb/gadget/storage_common.h @@ -181,6 +181,11 @@ static inline u32 get_unaligned_be24(u8 *buf) return 0xffffff & (u32) get_unaligned_be32(buf - 1); } +static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) +{ + return container_of(dev, struct fsg_lun, dev); +} + enum { FSG_STRING_INTERFACE }; @@ -205,18 +210,14 @@ void fsg_lun_close(struct fsg_lun *curlun); int fsg_lun_open(struct fsg_lun *curlun, const char *filename); int fsg_lun_fsync_sub(struct fsg_lun *curlun); void store_cdrom_address(u8 *dest, int msf, u32 addr); -ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf); -ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); -ssize_t fsg_store_nofua(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count); -ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); #endif /* USB_STORAGE_COMMON_H */ -- cgit v1.2.3 From 864328ef8e735403f85b768284001a4187d6868f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:04 +0200 Subject: usb: gadget: storage_common: add methods to show/store 'cdrom' and 'removable' This will be required by configfs integration. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/storage_common.c | 42 +++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/storage_common.h | 5 +++++ 2 files changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 969948dc2596..c7b78a1f6086 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -359,6 +359,17 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, } EXPORT_SYMBOL(fsg_show_file); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) +{ + return sprintf(buf, "%u\n", curlun->cdrom); +} +EXPORT_SYMBOL(fsg_show_cdrom); + +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) +{ + return sprintf(buf, "%u\n", curlun->removable); +} +EXPORT_SYMBOL(fsg_show_removable); ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) @@ -439,4 +450,35 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, } EXPORT_SYMBOL(fsg_store_file); +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count) +{ + unsigned cdrom; + int ret; + + ret = kstrtouint(buf, 2, &cdrom); + if (ret) + return ret; + + curlun->cdrom = cdrom; + + return count; +} +EXPORT_SYMBOL(fsg_store_cdrom); + +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, + size_t count) +{ + unsigned removable; + int ret; + + ret = kstrtouint(buf, 2, &removable); + if (ret) + return ret; + + curlun->removable = removable; + + return count; +} +EXPORT_SYMBOL(fsg_store_removable); + MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h index 16cf07bb9e75..e0f7aa69c7ed 100644 --- a/drivers/usb/gadget/storage_common.h +++ b/drivers/usb/gadget/storage_common.h @@ -214,10 +214,15 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, + size_t count); #endif /* USB_STORAGE_COMMON_H */ -- cgit v1.2.3 From ef0aa4b92cf10a7684135c61dc406398308b328f Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:06:05 +0200 Subject: usb: gadget: f_mass_storage: add configfs support From this commit on f_mass_storage is available through configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 11 ++ drivers/usb/gadget/f_mass_storage.c | 360 ++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/f_mass_storage.h | 17 ++ 3 files changed, 388 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 7d64e474c48b..bc5dea2f26e2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -668,6 +668,17 @@ config USB_CONFIGFS_PHONET help The Phonet protocol implementation for USB device. +config USB_CONFIGFS_MASS_STORAGE + boolean "Mass storage" + depends on USB_CONFIGFS + select USB_U_MS + select USB_F_MASS_STORAGE + help + The Mass Storage Gadget acts as a USB Mass Storage disk drive. + As its storage repository it can use a regular file or a block + device (in much the same way as the "loop" device driver), + specified as a module parameter or sysfs option. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index d80be5f0e6d2..00d3687594bb 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -220,6 +220,7 @@ #include #include "gadget_chips.h" +#include "configfs.h" /*------------------------------------------------------------------------*/ @@ -3295,6 +3296,342 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, #else +static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct fsg_lun_opts, group); +} + +static inline struct fsg_opts *to_fsg_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct fsg_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(fsg_lun_opts); +CONFIGFS_ATTR_OPS(fsg_lun_opts); + +static void fsg_lun_attr_release(struct config_item *item) +{ + struct fsg_lun_opts *lun_opts; + + lun_opts = to_fsg_lun_opts(item); + kfree(lun_opts); +} + +static struct configfs_item_operations fsg_lun_item_ops = { + .release = fsg_lun_attr_release, + .show_attribute = fsg_lun_opts_attr_show, + .store_attribute = fsg_lun_opts_attr_store, +}; + +static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page) +{ + struct fsg_opts *fsg_opts; + + fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + + return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page); +} + +static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts, + const char *page, size_t len) +{ + struct fsg_opts *fsg_opts; + + fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + + return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_file = + __CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show, + fsg_lun_opts_file_store); + +static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page) +{ + return fsg_show_ro(opts->lun, page); +} + +static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts, + const char *page, size_t len) +{ + struct fsg_opts *fsg_opts; + + fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + + return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_ro = + __CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show, + fsg_lun_opts_ro_store); + +static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts, + char *page) +{ + return fsg_show_removable(opts->lun, page); +} + +static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts, + const char *page, size_t len) +{ + return fsg_store_removable(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_removable = + __CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR, + fsg_lun_opts_removable_show, + fsg_lun_opts_removable_store); + +static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page) +{ + return fsg_show_cdrom(opts->lun, page); +} + +static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts, + const char *page, size_t len) +{ + return fsg_store_cdrom(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom = + __CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show, + fsg_lun_opts_cdrom_store); + +static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page) +{ + return fsg_show_nofua(opts->lun, page); +} + +static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts, + const char *page, size_t len) +{ + return fsg_store_nofua(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_nofua = + __CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show, + fsg_lun_opts_nofua_store); + +static struct configfs_attribute *fsg_lun_attrs[] = { + &fsg_lun_opts_file.attr, + &fsg_lun_opts_ro.attr, + &fsg_lun_opts_removable.attr, + &fsg_lun_opts_cdrom.attr, + &fsg_lun_opts_nofua.attr, + NULL, +}; + +static struct config_item_type fsg_lun_type = { + .ct_item_ops = &fsg_lun_item_ops, + .ct_attrs = fsg_lun_attrs, + .ct_owner = THIS_MODULE, +}; + +#define MAX_NAME_LEN 40 + +static struct config_group *fsg_lun_make(struct config_group *group, + const char *name) +{ + struct fsg_lun_opts *opts; + struct fsg_opts *fsg_opts; + struct fsg_lun_config config; + char *num_str; + u8 num; + int ret; + + num_str = strchr(name, '.'); + if (!num_str) { + pr_err("Unable to locate . in LUN.NUMBER\n"); + return ERR_PTR(-EINVAL); + } + num_str++; + + ret = kstrtou8(num_str, 0, &num); + if (ret) + return ERR_PTR(ret); + + fsg_opts = to_fsg_opts(&group->cg_item); + if (num >= FSG_MAX_LUNS) + return ERR_PTR(-ENODEV); + mutex_lock(&fsg_opts->lock); + if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { + ret = -EBUSY; + goto out; + } + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) { + ret = -ENOMEM; + goto out; + } + + memset(&config, 0, sizeof(config)); + config.removable = true; + + + ret = fsg_common_create_lun(fsg_opts->common, &config, num, name, + (const char **)&group->cg_item.ci_name); + if (ret) { + kfree(opts); + goto out; + } + opts->lun = fsg_opts->common->luns[num]; + opts->lun_id = num; + mutex_unlock(&fsg_opts->lock); + + config_group_init_type_name(&opts->group, name, &fsg_lun_type); + + return &opts->group; +out: + mutex_unlock(&fsg_opts->lock); + return ERR_PTR(ret); +} + +static void fsg_lun_drop(struct config_group *group, struct config_item *item) +{ + struct fsg_lun_opts *lun_opts; + struct fsg_opts *fsg_opts; + + lun_opts = to_fsg_lun_opts(item); + fsg_opts = to_fsg_opts(&group->cg_item); + + mutex_lock(&fsg_opts->lock); + if (fsg_opts->refcnt) { + struct config_item *gadget; + + gadget = group->cg_item.ci_parent->ci_parent; + unregister_gadget_item(gadget); + } + + fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs); + fsg_opts->common->luns[lun_opts->lun_id] = NULL; + lun_opts->lun_id = 0; + mutex_unlock(&fsg_opts->lock); + + config_item_put(item); +} + +CONFIGFS_ATTR_STRUCT(fsg_opts); +CONFIGFS_ATTR_OPS(fsg_opts); + +static void fsg_attr_release(struct config_item *item) +{ + struct fsg_opts *opts = to_fsg_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations fsg_item_ops = { + .release = fsg_attr_release, + .show_attribute = fsg_opts_attr_show, + .store_attribute = fsg_opts_attr_store, +}; + +static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->common->can_stall); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, + size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + opts->common->can_stall = num != 0; + ret = len; + +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct fsg_opts_attribute fsg_opts_stall = + __CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show, + fsg_opts_stall_store); + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->common->fsg_num_buffers); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts, + const char *page, size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + ret = fsg_num_buffers_validate(num); + if (ret) + goto end; + + fsg_common_set_num_buffers(opts->common, num); + ret = len; + +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct fsg_opts_attribute fsg_opts_num_buffers = + __CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR, + fsg_opts_num_buffers_show, + fsg_opts_num_buffers_store); + +#endif + +static struct configfs_attribute *fsg_attrs[] = { + &fsg_opts_stall.attr, +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + &fsg_opts_num_buffers.attr, +#endif + NULL, +}; + +static struct configfs_group_operations fsg_group_ops = { + .make_group = fsg_lun_make, + .drop_item = fsg_lun_drop, +}; + +static struct config_item_type fsg_func_type = { + .ct_item_ops = &fsg_item_ops, + .ct_group_ops = &fsg_group_ops, + .ct_attrs = fsg_attrs, + .ct_owner = THIS_MODULE, +}; + static void fsg_free_inst(struct usb_function_instance *fi) { struct fsg_opts *opts; @@ -3307,11 +3644,13 @@ static void fsg_free_inst(struct usb_function_instance *fi) static struct usb_function_instance *fsg_alloc_inst(void) { struct fsg_opts *opts; + struct fsg_lun_config config; int rc; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + mutex_init(&opts->lock); opts->func_inst.free_func_inst = fsg_free_inst; opts->common = fsg_common_setup(opts->common, false); if (IS_ERR(opts->common)) { @@ -3329,6 +3668,18 @@ static struct usb_function_instance *fsg_alloc_inst(void) pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); + memset(&config, 0, sizeof(config)); + config.removable = true; + rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", + (const char **)&opts->func_inst.group.cg_item.ci_name); + opts->lun0.lun = opts->common->luns[0]; + opts->lun0.lun_id = 0; + config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); + opts->default_groups[0] = &opts->lun0.group; + opts->func_inst.group.default_groups = opts->default_groups; + + config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type); + return &opts->func_inst; release_luns: @@ -3341,8 +3692,14 @@ release_opts: static void fsg_free(struct usb_function *f) { struct fsg_dev *fsg; + struct fsg_opts *opts; fsg = container_of(f, struct fsg_dev, function); + opts = container_of(f->fi, struct fsg_opts, func_inst); + + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); kfree(fsg); } @@ -3357,6 +3714,9 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) if (unlikely(!fsg)) return ERR_PTR(-ENOMEM); + mutex_lock(&opts->lock); + opts->refcnt++; + mutex_unlock(&opts->lock); fsg->function.name = FSG_DRIVER_DESC; fsg->function.bind = fsg_bind; fsg->function.unbind = fsg_unbind; diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index b53cf8c9189e..7d421d2ac3c9 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -71,10 +71,27 @@ struct fsg_operations { int (*thread_exits)(struct fsg_common *common); }; +struct fsg_lun_opts { + struct config_group group; + struct fsg_lun *lun; + int lun_id; +}; + struct fsg_opts { struct fsg_common *common; struct usb_function_instance func_inst; + struct fsg_lun_opts lun0; + struct config_group *default_groups[2]; bool no_configfs; /* for legacy gadgets */ + + /* + * Read/write access to configfs attributes is handled by configfs. + * + * This is to protect the data from concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; struct fsg_lun_config { -- cgit v1.2.3 From e6c661ef18177f2f1ce32210140f8497851d9388 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:07:29 +0200 Subject: usb: gadget: acm_ms: convert to new interface of f_mass_storage Convert the legacy acm_ms gadget to use the new function interface of f_mass_storage, so that later the compatibility layer in f_mass_storage can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/acm_ms.c | 113 +++++++++++++++++++++++++++++--------------- 2 files changed, 75 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bc5dea2f26e2..886db6a7d4d9 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1021,6 +1021,7 @@ config USB_G_ACM_MS select USB_U_SERIAL select USB_F_ACM select USB_U_MS + select USB_F_MASS_STORAGE help This driver provides two functions in one configuration: a mass storage, and a CDC ACM (serial port) link. diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 31aae8fce426..7bfa134fe0e3 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -31,17 +31,7 @@ #define ACM_MS_VENDOR_NUM 0x1d6b /* Linux Foundation */ #define ACM_MS_PRODUCT_NUM 0x0106 /* Composite Gadget: ACM + MS*/ -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#define USB_FMS_INCLUDED -#include "f_mass_storage.c" +#include "f_mass_storage.h" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -121,16 +111,19 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); -static struct fsg_common fsg_common; - /*-------------------------------------------------------------------------*/ static struct usb_function *f_acm; static struct usb_function_instance *f_acm_inst; + +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; + /* * We _always_ have both ACM and mass storage functions. */ static int __init acm_ms_do_config(struct usb_configuration *c) { + struct fsg_opts *opts; int status; if (gadget_is_otg(c->cdev->gadget)) { @@ -138,31 +131,37 @@ static int __init acm_ms_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - f_acm_inst = usb_get_function_instance("acm"); - if (IS_ERR(f_acm_inst)) - return PTR_ERR(f_acm_inst); + opts = fsg_opts_from_func_inst(fi_msg); f_acm = usb_get_function(f_acm_inst); - if (IS_ERR(f_acm)) { - status = PTR_ERR(f_acm); - goto err_func; + if (IS_ERR(f_acm)) + return PTR_ERR(f_acm); + + f_msg = usb_get_function(fi_msg); + if (IS_ERR(f_msg)) { + status = PTR_ERR(f_msg); + goto put_acm; } status = usb_add_function(c, f_acm); if (status < 0) - goto err_conf; + goto put_msg; - status = fsg_bind_config(c->cdev, c, &fsg_common); - if (status < 0) - goto err_fsg; + status = fsg_common_run_thread(opts->common); + if (status) + goto remove_acm; + + status = usb_add_function(c, f_msg); + if (status) + goto remove_acm; return 0; -err_fsg: +remove_acm: usb_remove_function(c, f_acm); -err_conf: +put_msg: + usb_put_function(f_msg); +put_acm: usb_put_function(f_acm); -err_func: - usb_put_function_instance(f_acm_inst); return status; } @@ -178,46 +177,82 @@ static struct usb_configuration acm_ms_config_driver = { static int __init acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct fsg_opts *opts; + struct fsg_config config; int status; - void *retp; - /* set up mass storage function */ - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data, - fsg_num_buffers); - if (IS_ERR(retp)) { - status = PTR_ERR(retp); - return PTR_ERR(retp); + f_acm_inst = usb_get_function_instance("acm"); + if (IS_ERR(f_acm_inst)) + return PTR_ERR(f_acm_inst); + + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) { + status = PTR_ERR(fi_msg); + goto fail_get_msg; } + /* set up mass storage function */ + fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); + opts = fsg_opts_from_func_inst(fi_msg); + + opts->no_configfs = true; + status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); + if (status) + goto fail; + + status = fsg_common_set_nluns(opts->common, config.nluns); + if (status) + goto fail_set_nluns; + + status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); + if (status) + goto fail_set_cdev; + + fsg_common_set_sysfs(opts->common, true); + status = fsg_common_create_luns(opts->common, &config); + if (status) + goto fail_set_cdev; + + fsg_common_set_inquiry_string(opts->common, config.vendor_name, + config.product_name); /* * Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) - goto fail1; + goto fail_string_ids; device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register our configuration */ status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); if (status < 0) - goto fail1; + goto fail_string_ids; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", DRIVER_DESC); - fsg_common_put(&fsg_common); return 0; /* error recovery */ -fail1: - fsg_common_put(&fsg_common); +fail_string_ids: + fsg_common_remove_luns(opts->common); +fail_set_cdev: + fsg_common_free_luns(opts->common); +fail_set_nluns: + fsg_common_free_buffers(opts->common); +fail: + usb_put_function_instance(fi_msg); +fail_get_msg: + usb_put_function_instance(f_acm_inst); return status; } static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) { + usb_put_function(f_msg); + usb_put_function_instance(fi_msg); usb_put_function(f_acm); usb_put_function_instance(f_acm_inst); return 0; -- cgit v1.2.3 From 7388901528411cbda3f5e0d121ae3797f4397ded Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:08:25 +0200 Subject: usb: gadget: multi: convert to new interface of f_ecm Convert the legacy multi gadget to the new interface of f_ecm, so that later the compatibility layer in f_ecm can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/multi.c | 68 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 886db6a7d4d9..92a896653cd6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1070,6 +1070,7 @@ config USB_G_MULTI_CDC bool "CDC Ethernet + CDC Serial + Storage configuration" depends on USB_G_MULTI default n + select USB_F_ECM help This option enables a configuration with CDC Ethernet (ECM), CDC Serial and Mass Storage functions available in the Multifunction diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 42a5bed75388..7dd554481dd4 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -15,6 +15,7 @@ #include #include +#include #include "u_serial.h" #if defined USB_ETH_RNDIS @@ -44,8 +45,7 @@ MODULE_LICENSE("GPL"); #define USB_FMS_INCLUDED #include "f_mass_storage.c" -#define USBF_ECM_INCLUDED -#include "f_ecm.c" +#include "u_ecm.h" #ifdef USB_ETH_RNDIS # define USB_FRNDIS_INCLUDED # include "f_rndis.c" @@ -151,14 +151,14 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; -static u8 host_mac[ETH_ALEN]; - static struct usb_function_instance *fi_acm; static struct eth_dev *the_dev; /********** RNDIS **********/ #ifdef USB_ETH_RNDIS +static u8 host_mac[ETH_ALEN]; + static struct usb_function *f_acm_rndis; static __init int rndis_do_config(struct usb_configuration *c) @@ -220,7 +220,9 @@ static __ref int rndis_config_register(struct usb_composite_dev *cdev) /********** CDC ECM **********/ #ifdef CONFIG_USB_G_MULTI_CDC +static struct usb_function_instance *fi_ecm; static struct usb_function *f_acm_multi; +static struct usb_function *f_ecm; static __init int cdc_do_config(struct usb_configuration *c) { @@ -231,14 +233,20 @@ static __init int cdc_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - ret = ecm_bind_config(c, host_mac, the_dev); + f_ecm = usb_get_function(fi_ecm); + if (IS_ERR(f_ecm)) + return PTR_ERR(f_ecm); + + ret = usb_add_function(c, f_ecm); if (ret < 0) - return ret; + goto err_func_ecm; /* implicit port_num is zero */ f_acm_multi = usb_get_function(fi_acm); - if (IS_ERR(f_acm_multi)) - return PTR_ERR(f_acm_multi); + if (IS_ERR(f_acm_multi)) { + ret = PTR_ERR(f_acm_multi); + goto err_func_acm; + } ret = usb_add_function(c, f_acm_multi); if (ret) @@ -253,6 +261,10 @@ err_fsg: usb_remove_function(c, f_acm_multi); err_conf: usb_put_function(f_acm_multi); +err_func_acm: + usb_remove_function(c, f_ecm); +err_func_ecm: + usb_put_function(f_ecm); return ret; } @@ -285,6 +297,9 @@ static __ref int cdc_config_register(struct usb_composite_dev *cdev) static int __ref multi_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; +#ifdef CONFIG_USB_G_MULTI_CDC + struct f_ecm_opts *ecm_opts; +#endif int status; if (!can_support_ecm(cdev->gadget)) { @@ -293,11 +308,39 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) return -EINVAL; } +#ifdef CONFIG_USB_G_MULTI_CDC + fi_ecm = usb_get_function_instance("ecm"); + if (IS_ERR(fi_ecm)) + return PTR_ERR(fi_ecm); + + ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); + + gether_set_qmult(ecm_opts->net, qmult); + if (!gether_set_host_addr(ecm_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); + + the_dev = netdev_priv(ecm_opts->net); + +#elif defined USB_ETH_RNDIS + /* set up network link layer */ the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, qmult); if (IS_ERR(the_dev)) return PTR_ERR(the_dev); +#endif + +#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) + gether_set_gadget(ecm_opts->net, cdev->gadget); + status = gether_register_netdev(ecm_opts->net); + if (status) + goto fail0; + ecm_opts->bound = true; + + gether_get_host_addr_u8(ecm_opts->net, host_mac); +#endif /* set up serial link layer */ fi_acm = usb_get_function_instance("acm"); @@ -345,7 +388,11 @@ fail2: fail1: usb_put_function_instance(fi_acm); fail0: +#ifdef CONFIG_USB_G_MULTI_CDC + usb_put_function_instance(fi_ecm); +#else gether_cleanup(the_dev); +#endif return status; } @@ -358,7 +405,12 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev) usb_put_function(f_acm_rndis); #endif usb_put_function_instance(fi_acm); +#ifdef CONFIG_USB_G_MULTI_CDC + usb_put_function(f_ecm); + usb_put_function_instance(fi_ecm); +#else gether_cleanup(the_dev); +#endif return 0; } -- cgit v1.2.3 From 4d1a8f68b42d2a726e36bfe2f891496b4c6bdbbb Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:08:26 +0200 Subject: usb: gadget: multi: convert to new interface of f_rndis Convert the legacy multi gadget to the new interface of f_rndis, so that later the compatibility layer in f_rndis can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 +- drivers/usb/gadget/multi.c | 73 +++++++++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 92a896653cd6..bbcc313f0317 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1036,7 +1036,6 @@ config USB_G_MULTI select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_U_ETHER - select USB_U_RNDIS select USB_F_ACM select USB_U_MS help @@ -1057,6 +1056,8 @@ config USB_G_MULTI config USB_G_MULTI_RNDIS bool "RNDIS + CDC Serial + Storage configuration" depends on USB_G_MULTI + select USB_U_RNDIS + select USB_F_RNDIS default y help This option enables a configuration with RNDIS, CDC Serial and diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 7dd554481dd4..fceef0fc0860 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -47,8 +47,7 @@ MODULE_LICENSE("GPL"); #include "u_ecm.h" #ifdef USB_ETH_RNDIS -# define USB_FRNDIS_INCLUDED -# include "f_rndis.c" +# include "u_rndis.h" # include "rndis.h" #endif #include "u_ether.h" @@ -152,14 +151,13 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; static struct usb_function_instance *fi_acm; -static struct eth_dev *the_dev; /********** RNDIS **********/ #ifdef USB_ETH_RNDIS -static u8 host_mac[ETH_ALEN]; - +static struct usb_function_instance *fi_rndis; static struct usb_function *f_acm_rndis; +static struct usb_function *f_rndis; static __init int rndis_do_config(struct usb_configuration *c) { @@ -170,13 +168,19 @@ static __init int rndis_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - ret = rndis_bind_config(c, host_mac, the_dev); + f_rndis = usb_get_function(fi_rndis); + if (IS_ERR(f_rndis)) + return PTR_ERR(f_rndis); + + ret = usb_add_function(c, f_rndis); if (ret < 0) - return ret; + goto err_func_rndis; f_acm_rndis = usb_get_function(fi_acm); - if (IS_ERR(f_acm_rndis)) - return PTR_ERR(f_acm_rndis); + if (IS_ERR(f_acm_rndis)) { + ret = PTR_ERR(f_acm_rndis); + goto err_func_acm; + } ret = usb_add_function(c, f_acm_rndis); if (ret) @@ -191,6 +195,10 @@ err_fsg: usb_remove_function(c, f_acm_rndis); err_conf: usb_put_function(f_acm_rndis); +err_func_acm: + usb_remove_function(c, f_rndis); +err_func_rndis: + usb_put_function(f_rndis); return ret; } @@ -299,12 +307,15 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) struct usb_gadget *gadget = cdev->gadget; #ifdef CONFIG_USB_G_MULTI_CDC struct f_ecm_opts *ecm_opts; +#endif +#ifdef USB_ETH_RNDIS + struct f_rndis_opts *rndis_opts; #endif int status; if (!can_support_ecm(cdev->gadget)) { dev_err(&gadget->dev, "controller '%s' not usable\n", - gadget->name); + gadget->name); return -EINVAL; } @@ -320,26 +331,38 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) pr_info("using host ethernet address: %s", host_addr); if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) pr_info("using self ethernet address: %s", dev_addr); +#endif - the_dev = netdev_priv(ecm_opts->net); +#ifdef USB_ETH_RNDIS + fi_rndis = usb_get_function_instance("rndis"); + if (IS_ERR(fi_rndis)) { + status = PTR_ERR(fi_rndis); + goto fail; + } -#elif defined USB_ETH_RNDIS + rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst); - /* set up network link layer */ - the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, - qmult); - if (IS_ERR(the_dev)) - return PTR_ERR(the_dev); + gether_set_qmult(rndis_opts->net, qmult); + if (!gether_set_host_addr(rndis_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(rndis_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); #endif #if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) + /* + * If both ecm and rndis are selected then: + * 1) rndis borrows the net interface from ecm + * 2) since the interface is shared it must not be bound + * twice - in ecm's _and_ rndis' binds, so do it here. + */ gether_set_gadget(ecm_opts->net, cdev->gadget); status = gether_register_netdev(ecm_opts->net); if (status) goto fail0; - ecm_opts->bound = true; - gether_get_host_addr_u8(ecm_opts->net, host_mac); + rndis_borrow_net(fi_rndis, ecm_opts->net); + ecm_opts->bound = true; #endif /* set up serial link layer */ @@ -388,10 +411,12 @@ fail2: fail1: usb_put_function_instance(fi_acm); fail0: +#ifdef USB_ETH_RNDIS + usb_put_function_instance(fi_rndis); +fail: +#endif #ifdef CONFIG_USB_G_MULTI_CDC usb_put_function_instance(fi_ecm); -#else - gether_cleanup(the_dev); #endif return status; } @@ -405,11 +430,13 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev) usb_put_function(f_acm_rndis); #endif usb_put_function_instance(fi_acm); +#ifdef USB_ETH_RNDIS + usb_put_function(f_rndis); + usb_put_function_instance(fi_rndis); +#endif #ifdef CONFIG_USB_G_MULTI_CDC usb_put_function(f_ecm); usb_put_function_instance(fi_ecm); -#else - gether_cleanup(the_dev); #endif return 0; } -- cgit v1.2.3 From 1bcce939478f894b46a592aed28ccc9caaf1a52a Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:08:27 +0200 Subject: usb: gadget: multi: convert to new interface of f_mass_storage Convert the legacy multi gadget to the new interface of f_mass_storage, so that later the compatibility layer in f_mass_storage can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/multi.c | 112 +++++++++++++++++++++++++++++++++------------ 2 files changed, 83 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bbcc313f0317..4b0c456f9d63 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -1038,6 +1038,7 @@ config USB_G_MULTI select USB_U_ETHER select USB_F_ACM select USB_U_MS + select USB_F_MASS_STORAGE help The Multifunction Composite Gadget provides Ethernet (RNDIS and/or CDC Ethernet), mass storage and ACM serial link diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index fceef0fc0860..4fdaa54a2a2a 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -33,17 +33,7 @@ MODULE_AUTHOR("Michal Nazarewicz"); MODULE_LICENSE("GPL"); -/***************************** All the files... *****************************/ - -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#define USB_FMS_INCLUDED -#include "f_mass_storage.c" +#include "f_mass_storage.h" #include "u_ecm.h" #ifdef USB_ETH_RNDIS @@ -148,9 +138,8 @@ static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); -static struct fsg_common fsg_common; - static struct usb_function_instance *fi_acm; +static struct usb_function_instance *fi_msg; /********** RNDIS **********/ @@ -158,9 +147,11 @@ static struct usb_function_instance *fi_acm; static struct usb_function_instance *fi_rndis; static struct usb_function *f_acm_rndis; static struct usb_function *f_rndis; +static struct usb_function *f_msg_rndis; static __init int rndis_do_config(struct usb_configuration *c) { + struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -186,11 +177,24 @@ static __init int rndis_do_config(struct usb_configuration *c) if (ret) goto err_conf; - ret = fsg_bind_config(c->cdev, c, &fsg_common); - if (ret < 0) + f_msg_rndis = usb_get_function(fi_msg); + if (IS_ERR(f_msg_rndis)) { + ret = PTR_ERR(f_msg_rndis); goto err_fsg; + } + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + ret = fsg_common_run_thread(fsg_opts->common); + if (ret) + goto err_run; + + ret = usb_add_function(c, f_msg_rndis); + if (ret) + goto err_run; return 0; +err_run: + usb_put_function(f_msg_rndis); err_fsg: usb_remove_function(c, f_acm_rndis); err_conf: @@ -231,9 +235,11 @@ static __ref int rndis_config_register(struct usb_composite_dev *cdev) static struct usb_function_instance *fi_ecm; static struct usb_function *f_acm_multi; static struct usb_function *f_ecm; +static struct usb_function *f_msg_multi; static __init int cdc_do_config(struct usb_configuration *c) { + struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -260,11 +266,24 @@ static __init int cdc_do_config(struct usb_configuration *c) if (ret) goto err_conf; - ret = fsg_bind_config(c->cdev, c, &fsg_common); - if (ret < 0) + f_msg_multi = usb_get_function(fi_msg); + if (IS_ERR(f_msg_multi)) { + ret = PTR_ERR(f_msg_multi); goto err_fsg; + } + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + ret = fsg_common_run_thread(fsg_opts->common); + if (ret) + goto err_run; + + ret = usb_add_function(c, f_msg_multi); + if (ret) + goto err_run; return 0; +err_run: + usb_put_function(f_msg_multi); err_fsg: usb_remove_function(c, f_acm_multi); err_conf: @@ -311,6 +330,8 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) #ifdef USB_ETH_RNDIS struct f_rndis_opts *rndis_opts; #endif + struct fsg_opts *fsg_opts; + struct fsg_config config; int status; if (!can_support_ecm(cdev->gadget)) { @@ -373,41 +394,65 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) } /* set up mass storage function */ - { - void *retp; - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data, - fsg_num_buffers); - if (IS_ERR(retp)) { - status = PTR_ERR(retp); - goto fail1; - } + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) { + status = PTR_ERR(fi_msg); + goto fail1; } + fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); + fsg_opts = fsg_opts_from_func_inst(fi_msg); + + fsg_opts->no_configfs = true; + status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); + if (status) + goto fail2; + + status = fsg_common_set_nluns(fsg_opts->common, config.nluns); + if (status) + goto fail_set_nluns; + + status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); + if (status) + goto fail_set_cdev; + + fsg_common_set_sysfs(fsg_opts->common, true); + status = fsg_common_create_luns(fsg_opts->common, &config); + if (status) + goto fail_set_cdev; + + fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name, + config.product_name); /* allocate string IDs */ status = usb_string_ids_tab(cdev, strings_dev); if (unlikely(status < 0)) - goto fail2; + goto fail_string_ids; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; /* register configurations */ status = rndis_config_register(cdev); if (unlikely(status < 0)) - goto fail2; + goto fail_string_ids; status = cdc_config_register(cdev); if (unlikely(status < 0)) - goto fail2; + goto fail_string_ids; usb_composite_overwrite_options(cdev, &coverwrite); /* we're done */ dev_info(&gadget->dev, DRIVER_DESC "\n"); - fsg_common_put(&fsg_common); return 0; /* error recovery */ +fail_string_ids: + fsg_common_remove_luns(fsg_opts->common); +fail_set_cdev: + fsg_common_free_luns(fsg_opts->common); +fail_set_nluns: + fsg_common_free_buffers(fsg_opts->common); fail2: - fsg_common_put(&fsg_common); + usb_put_function_instance(fi_msg); fail1: usb_put_function_instance(fi_acm); fail0: @@ -423,6 +468,13 @@ fail: static int __exit multi_unbind(struct usb_composite_dev *cdev) { +#ifdef CONFIG_USB_G_MULTI_CDC + usb_put_function(f_msg_multi); +#endif +#ifdef USB_ETH_RNDIS + usb_put_function(f_msg_rndis); +#endif + usb_put_function_instance(fi_msg); #ifdef CONFIG_USB_G_MULTI_CDC usb_put_function(f_acm_multi); #endif -- cgit v1.2.3 From 7a93d040e01ec9053ec6ea4486f21829d48f903a Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:08:28 +0200 Subject: usb: gadget: f_mass_storage: remove compatibility layer There are no more old interface users left. Remove it. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 150 +++++------------------------------- drivers/usb/gadget/f_mass_storage.h | 21 ----- 2 files changed, 19 insertions(+), 152 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 00d3687594bb..6e5a6daf1a12 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -228,13 +228,6 @@ #define FSG_DRIVER_DESC "Mass Storage Function" #define FSG_DRIVER_VERSION "2009/09/11" -/* to avoid a lot of #ifndef-#endif in the temporary compatibility layer */ -#ifndef USB_FMS_INCLUDED -#define EXPORT_SYMBOL_GPL_IF_MODULE(m) EXPORT_SYMBOL_GPL(m); -#else -#define EXPORT_SYMBOL_GPL_IF_MODULE(m) -#endif - static const char fsg_string_interface[] = "Mass Storage"; #include "storage_common.h" @@ -2651,13 +2644,13 @@ void fsg_common_get(struct fsg_common *common) { kref_get(&common->ref); } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_get); +EXPORT_SYMBOL_GPL(fsg_common_get); void fsg_common_put(struct fsg_common *common) { kref_put(&common->ref, fsg_common_release); } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_put); +EXPORT_SYMBOL_GPL(fsg_common_put); /* check if fsg_num_buffers is within a valid range */ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) @@ -2669,7 +2662,7 @@ static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) return -EINVAL; } -static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool zero) +static struct fsg_common *fsg_common_setup(struct fsg_common *common) { if (!common) { common = kzalloc(sizeof(*common), GFP_KERNEL); @@ -2677,8 +2670,6 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common, bool zero) return ERR_PTR(-ENOMEM); common->free_storage_on_release = 1; } else { - if (zero) - memset(common, 0, sizeof(*common)); common->free_storage_on_release = 0; } init_rwsem(&common->filesem); @@ -2695,7 +2686,7 @@ void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) { common->sysfs = sysfs; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_sysfs); +EXPORT_SYMBOL_GPL(fsg_common_set_sysfs); static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) { @@ -2751,7 +2742,7 @@ error_release: return -ENOMEM; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_num_buffers); +EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) { @@ -2790,7 +2781,7 @@ void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) fsg_lun_close(lun); kfree(lun); } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_remove_lun); +EXPORT_SYMBOL_GPL(fsg_common_remove_lun); static void _fsg_common_remove_luns(struct fsg_common *common, int n) { @@ -2802,7 +2793,7 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) common->luns[i] = NULL; } } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_remove_luns); +EXPORT_SYMBOL_GPL(fsg_common_remove_luns); void fsg_common_remove_luns(struct fsg_common *common) { @@ -2815,7 +2806,7 @@ void fsg_common_free_luns(struct fsg_common *common) kfree(common->luns); common->luns = NULL; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_free_luns); +EXPORT_SYMBOL_GPL(fsg_common_free_luns); int fsg_common_set_nluns(struct fsg_common *common, int nluns) { @@ -2841,21 +2832,21 @@ int fsg_common_set_nluns(struct fsg_common *common, int nluns) return 0; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_nluns); +EXPORT_SYMBOL_GPL(fsg_common_set_nluns); void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops) { common->ops = ops; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_ops); +EXPORT_SYMBOL_GPL(fsg_common_set_ops); void fsg_common_free_buffers(struct fsg_common *common) { _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); common->buffhds = NULL; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_free_buffers); +EXPORT_SYMBOL_GPL(fsg_common_free_buffers); int fsg_common_set_cdev(struct fsg_common *common, struct usb_composite_dev *cdev, bool can_stall) @@ -2883,7 +2874,7 @@ int fsg_common_set_cdev(struct fsg_common *common, return 0; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_cdev); +EXPORT_SYMBOL_GPL(fsg_common_set_cdev); static inline int fsg_common_add_sysfs(struct fsg_common *common, struct fsg_lun *lun) @@ -3006,7 +2997,7 @@ error_sysfs: kfree(lun); return rc; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_create_lun); +EXPORT_SYMBOL_GPL(fsg_common_create_lun); int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) { @@ -3028,7 +3019,7 @@ fail: _fsg_common_remove_luns(common, i); return rc; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_create_luns); +EXPORT_SYMBOL_GPL(fsg_common_create_luns); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn) @@ -3045,7 +3036,7 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, : "File-Stor Gadget"), i); } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_set_inquiry_string); +EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); int fsg_common_run_thread(struct fsg_common *common) { @@ -3064,61 +3055,7 @@ int fsg_common_run_thread(struct fsg_common *common) return 0; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_run_thread); - -struct fsg_common *fsg_common_init(struct fsg_common *common, - struct usb_composite_dev *cdev, - struct fsg_config *cfg) -{ - int rc; - - common = fsg_common_setup(common, !!common); - if (IS_ERR(common)) - return common; - fsg_common_set_sysfs(common, true); - common->state = FSG_STATE_IDLE; - - rc = fsg_common_set_num_buffers(common, cfg->fsg_num_buffers); - if (rc) { - if (common->free_storage_on_release) - kfree(common); - return ERR_PTR(rc); - } - common->ops = cfg->ops; - common->private_data = cfg->private_data; - - rc = fsg_common_set_cdev(common, cdev, cfg->can_stall); - if (rc) - goto error_release; - - rc = fsg_common_set_nluns(common, cfg->nluns); - if (rc) - goto error_release; - - rc = fsg_common_create_luns(common, cfg); - if (rc) - goto error_release; - - - fsg_common_set_inquiry_string(common, cfg->vendor_name, - cfg->product_name); - - /* Information */ - INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); - - rc = fsg_common_run_thread(common); - if (rc) - goto error_release; - - return common; - -error_release: - common->state = FSG_STATE_TERMINATED; /* The thread is dead */ - /* Call fsg_common_release() directly, ref might be not initialised. */ - fsg_common_release(&common->ref); - return ERR_PTR(rc); -} -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_common_init); +EXPORT_SYMBOL_GPL(fsg_common_run_thread); static void fsg_common_release(struct kref *ref) { @@ -3166,9 +3103,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; unsigned max_burst; int ret; - -#ifndef USB_FMS_INCLUDED struct fsg_opts *opts; + opts = fsg_opts_from_func_inst(f->fi); if (!opts->no_configfs) { ret = fsg_common_set_cdev(fsg->common, c->cdev, @@ -3180,7 +3116,6 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (ret) return ret; } -#endif fsg->gadget = gadget; @@ -3248,54 +3183,9 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) wait_event(common->fsg_wait, common->fsg != fsg); } -#ifdef USB_FMS_INCLUDED - fsg_common_put(common); -#endif usb_free_all_descriptors(&fsg->function); -#ifdef USB_FMS_INCLUDED - kfree(fsg); -#endif -} - -#ifdef USB_FMS_INCLUDED - -static int fsg_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct fsg_common *common) -{ - struct fsg_dev *fsg; - int rc; - - fsg = kzalloc(sizeof *fsg, GFP_KERNEL); - if (unlikely(!fsg)) - return -ENOMEM; - - fsg->function.name = FSG_DRIVER_DESC; - fsg->function.bind = fsg_bind; - fsg->function.unbind = fsg_unbind; - fsg->function.setup = fsg_setup; - fsg->function.set_alt = fsg_set_alt; - fsg->function.disable = fsg_disable; - - fsg->common = common; - /* - * Our caller holds a reference to common structure so we - * don't have to be worry about it being freed until we return - * from this function. So instead of incrementing counter now - * and decrement in error recovery we increment it only when - * call to usb_add_function() was successful. - */ - - rc = usb_add_function(c, &fsg->function); - if (unlikely(rc)) - kfree(fsg); - else - fsg_common_get(fsg->common); - return rc; } -#else - static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item) { return container_of(to_config_group(item), struct fsg_lun_opts, group); @@ -3652,7 +3542,7 @@ static struct usb_function_instance *fsg_alloc_inst(void) return ERR_PTR(-ENOMEM); mutex_init(&opts->lock); opts->func_inst.free_func_inst = fsg_free_inst; - opts->common = fsg_common_setup(opts->common, false); + opts->common = fsg_common_setup(opts->common); if (IS_ERR(opts->common)) { rc = PTR_ERR(opts->common); goto release_opts; @@ -3734,8 +3624,6 @@ DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Nazarewicz"); -#endif - /************************* Module parameters *************************/ @@ -3771,5 +3659,5 @@ void fsg_config_from_params(struct fsg_config *cfg, cfg->can_stall = params->stall; cfg->fsg_num_buffers = fsg_num_buffers; } -EXPORT_SYMBOL_GPL_IF_MODULE(fsg_config_from_params); +EXPORT_SYMBOL_GPL(fsg_config_from_params); diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h index 7d421d2ac3c9..b4866fcef30b 100644 --- a/drivers/usb/gadget/f_mass_storage.h +++ b/drivers/usb/gadget/f_mass_storage.h @@ -128,10 +128,6 @@ void fsg_common_get(struct fsg_common *common); void fsg_common_put(struct fsg_common *common); -struct fsg_common *fsg_common_init(struct fsg_common *common, - struct usb_composite_dev *cdev, - struct fsg_config *cfg); - void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); @@ -167,21 +163,4 @@ void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params, - unsigned int fsg_num_buffers) - __attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params, - unsigned int fsg_num_buffers) -{ - struct fsg_config cfg; - fsg_config_from_params(&cfg, params, fsg_num_buffers); - return fsg_common_init(common, cdev, &cfg); -} - #endif /* USB_F_MASS_STORAGE_H */ -- cgit v1.2.3 From 8254baccdd2635782826936b72608449b6b4bbde Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 9 Oct 2013 10:08:29 +0200 Subject: usb: gadget: mass_storage: merge usb_f_mass_storage module with u_ms module u_ms.ko is needed only together with usb_f_mass_storage.ko. Merge them. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 7 ------- drivers/usb/gadget/Makefile | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 4b0c456f9d63..604f885345f1 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -525,9 +525,6 @@ config USB_F_SUBSET config USB_F_RNDIS tristate -config USB_U_MS - tristate - config USB_F_MASS_STORAGE tristate @@ -671,7 +668,6 @@ config USB_CONFIGFS_PHONET config USB_CONFIGFS_MASS_STORAGE boolean "Mass storage" depends on USB_CONFIGFS - select USB_U_MS select USB_F_MASS_STORAGE help The Mass Storage Gadget acts as a USB Mass Storage disk drive. @@ -895,7 +891,6 @@ config USB_MASS_STORAGE tristate "Mass Storage Gadget" depends on BLOCK select USB_LIBCOMPOSITE - select USB_U_MS select USB_F_MASS_STORAGE help The Mass Storage Gadget acts as a USB Mass Storage disk drive. @@ -1020,7 +1015,6 @@ config USB_G_ACM_MS select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_F_ACM - select USB_U_MS select USB_F_MASS_STORAGE help This driver provides two functions in one configuration: @@ -1037,7 +1031,6 @@ config USB_G_MULTI select USB_U_SERIAL select USB_U_ETHER select USB_F_ACM - select USB_U_MS select USB_F_MASS_STORAGE help The Multifunction Composite Gadget provides Ethernet (RNDIS diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 4a86b0c06676..f1bd42a2cbba 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -60,9 +60,7 @@ usb_f_ecm_subset-y := f_subset.o obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o usb_f_rndis-y := f_rndis.o obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o -u_ms-y := storage_common.o -obj-$(CONFIG_USB_U_MS) += u_ms.o -usb_f_mass_storage-y := f_mass_storage.o +usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o # -- cgit v1.2.3 From c5340bd14336b902604ab95212a8877de109d9ae Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 10 Oct 2013 18:26:59 +0200 Subject: usb: musb: cancel work on removal So I captured this: |WARNING: CPU: 0 PID: 2078 at /home/bigeasy/work/new/TI/linux/lib/debugobjects.c:260 debug_print_object+0x94/0xc4() |ODEBUG: free active (active state 0) object type: work_struct hint: musb_irq_work+0x0/0x38 [musb_hdrc] |CPU: 0 PID: 2078 Comm: rmmod Not tainted 3.12.0-rc4+ #338 |[] (unwind_backtrace+0x0/0xf4) from [] (show_stack+0x14/0x1c) |[] (show_stack+0x14/0x1c) from [] (warn_slowpath_common+0x64/0x84) |[] (warn_slowpath_common+0x64/0x84) from [] (warn_slowpath_fmt+0x30/0x40) |[] (warn_slowpath_fmt+0x30/0x40) from [] (debug_print_object+0x94/0xc4) |[] (debug_print_object+0x94/0xc4) from [] (debug_check_no_obj_freed+0x1c0/0x228) |[] (debug_check_no_obj_freed+0x1c0/0x228) from [] (kfree+0xf8/0x228) |[] (kfree+0xf8/0x228) from [] (release_nodes+0x1a8/0x248) |[] (release_nodes+0x1a8/0x248) from [] (__device_release_driver+0x98/0xf0) |[] (__device_release_driver+0x98/0xf0) from [] (device_release_driver+0x24/0x34) |[] (device_release_driver+0x24/0x34) from [] (bus_remove_device+0x148/0x15c) |[] (bus_remove_device+0x148/0x15c) from [] (device_del+0x104/0x1c0) |[] (device_del+0x104/0x1c0) from [] (platform_device_del+0x18/0xac) |[] (platform_device_del+0x18/0xac) from [] (platform_device_unregister+0xc/0x18) |[] (platform_device_unregister+0xc/0x18) from [] (dsps_remove+0x20/0x4c [musb_dsps]) |[] (dsps_remove+0x20/0x4c [musb_dsps]) from [] (platform_drv_remove+0x1c/0x24) |[] (platform_drv_remove+0x1c/0x24) from [] (__device_release_driver+0x90/0xf0) |[] (__device_release_driver+0x90/0xf0) from [] (driver_detach+0xb4/0xb8) |[] (driver_detach+0xb4/0xb8) from [] (bus_remove_driver+0x98/0xec) |[] (bus_remove_driver+0x98/0xec) from [] (SyS_delete_module+0x1e0/0x24c) |[] (SyS_delete_module+0x1e0/0x24c) from [] (ret_fast_syscall+0x0/0x48) |---[ end trace d79045419a3e51ec ]--- The workqueue is only scheduled from the ep0 and never canceled in case the musb is removed before the work has a chance to run. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 18e877ffe7b7..5b4fa79a277b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1763,6 +1763,7 @@ static void musb_free(struct musb *musb) disable_irq_wake(musb->nIrq); free_irq(musb->nIrq, musb); } + cancel_work_sync(&musb->irq_work); if (musb->dma_controller) dma_controller_destroy(musb->dma_controller); -- cgit v1.2.3 From 5578b266e9ae05391d53b446acf23818256ff13f Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Thu, 10 Oct 2013 20:35:17 +0400 Subject: usb: phy: Add RCAR Gen2 USB phy This adds RCAR Gen2 USB phy support. The driver configures USB channels 0/2 which are shared between PCI USB hosts and USBHS/USBSS devices. It also controls internal USBHS phy. Signed-off-by: Valentine Barshak Signed-off-by: Felipe Balbi --- drivers/usb/phy/Kconfig | 13 ++ drivers/usb/phy/Makefile | 1 + drivers/usb/phy/phy-rcar-gen2-usb.c | 248 ++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 drivers/usb/phy/phy-rcar-gen2-usb.c (limited to 'drivers') diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index d5589f9c60a9..c0c8cd37648e 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -214,6 +214,19 @@ config USB_RCAR_PHY To compile this driver as a module, choose M here: the module will be called phy-rcar-usb. +config USB_RCAR_GEN2_PHY + tristate "Renesas R-Car Gen2 USB PHY support" + depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST + select USB_PHY + help + Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver. + It is typically used to control internal USB PHY for USBHS, + and to configure shared USB channels 0 and 2. + This driver supports R8A7790 and R8A7791. + + To compile this driver as a module, choose M here: the + module will be called phy-rcar-gen2-usb. + config USB_ULPI bool "Generic ULPI Transceiver Driver" depends on ARM diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 2135e85f46ed..8c5b14764b72 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -29,5 +29,6 @@ obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o +obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c new file mode 100644 index 000000000000..a99a6953f11c --- /dev/null +++ b/drivers/usb/phy/phy-rcar-gen2-usb.c @@ -0,0 +1,248 @@ +/* + * Renesas R-Car Gen2 USB phy driver + * + * Copyright (C) 2013 Renesas Solutions Corp. + * Copyright (C) 2013 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct rcar_gen2_usb_phy_priv { + struct usb_phy phy; + void __iomem *base; + struct clk *clk; + spinlock_t lock; + int usecount; + u32 ugctrl2; +}; + +#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy) + +/* Low Power Status register */ +#define USBHS_LPSTS_REG 0x02 +#define USBHS_LPSTS_SUSPM (1 << 14) + +/* USB General control register */ +#define USBHS_UGCTRL_REG 0x80 +#define USBHS_UGCTRL_CONNECT (1 << 2) +#define USBHS_UGCTRL_PLLRESET (1 << 0) + +/* USB General control register 2 */ +#define USBHS_UGCTRL2_REG 0x84 +#define USBHS_UGCTRL2_USB0_PCI (1 << 4) +#define USBHS_UGCTRL2_USB0_HS (3 << 4) +#define USBHS_UGCTRL2_USB2_PCI (0 << 31) +#define USBHS_UGCTRL2_USB2_SS (1 << 31) + +/* USB General status register */ +#define USBHS_UGSTS_REG 0x88 +#define USBHS_UGSTS_LOCK (3 << 8) + +/* Enable USBHS internal phy */ +static int __rcar_gen2_usbhs_phy_enable(void __iomem *base) +{ + u32 val; + int i; + + /* USBHS PHY power on */ + val = ioread32(base + USBHS_UGCTRL_REG); + val &= ~USBHS_UGCTRL_PLLRESET; + iowrite32(val, base + USBHS_UGCTRL_REG); + + val = ioread16(base + USBHS_LPSTS_REG); + val |= USBHS_LPSTS_SUSPM; + iowrite16(val, base + USBHS_LPSTS_REG); + + for (i = 0; i < 20; i++) { + val = ioread32(base + USBHS_UGSTS_REG); + if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { + val = ioread32(base + USBHS_UGCTRL_REG); + val |= USBHS_UGCTRL_CONNECT; + iowrite32(val, base + USBHS_UGCTRL_REG); + return 0; + } + udelay(1); + } + + /* Timed out waiting for the PLL lock */ + return -ETIMEDOUT; +} + +/* Disable USBHS internal phy */ +static int __rcar_gen2_usbhs_phy_disable(void __iomem *base) +{ + u32 val; + + /* USBHS PHY power off */ + val = ioread32(base + USBHS_UGCTRL_REG); + val &= ~USBHS_UGCTRL_CONNECT; + iowrite32(val, base + USBHS_UGCTRL_REG); + + val = ioread16(base + USBHS_LPSTS_REG); + val &= ~USBHS_LPSTS_SUSPM; + iowrite16(val, base + USBHS_LPSTS_REG); + + val = ioread32(base + USBHS_UGCTRL_REG); + val |= USBHS_UGCTRL_PLLRESET; + iowrite32(val, base + USBHS_UGCTRL_REG); + return 0; +} + +/* Setup USB channels */ +static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) +{ + u32 val; + + clk_prepare_enable(priv->clk); + + /* Set USB channels in the USBHS UGCTRL2 register */ + val = ioread32(priv->base); + val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); + val |= priv->ugctrl2; + iowrite32(val, priv->base); +} + +/* Shutdown USB channels */ +static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv) +{ + __rcar_gen2_usbhs_phy_disable(priv->base); + clk_disable_unprepare(priv->clk); +} + +static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend) +{ + struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); + unsigned long flags; + int retval; + + spin_lock_irqsave(&priv->lock, flags); + retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) : + __rcar_gen2_usbhs_phy_enable(priv->base); + spin_unlock_irqrestore(&priv->lock, flags); + return retval; +} + +static int rcar_gen2_usb_phy_init(struct usb_phy *phy) +{ + struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + /* + * Enable the clock and setup USB channels + * if it's the first user + */ + if (!priv->usecount++) + __rcar_gen2_usb_phy_init(priv); + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy) +{ + struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (!priv->usecount) { + dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n"); + goto out; + } + + /* Disable everything if it's the last user */ + if (!--priv->usecount) + __rcar_gen2_usb_phy_shutdown(priv); +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rcar_gen2_phy_platform_data *pdata; + struct rcar_gen2_usb_phy_priv *priv; + struct resource *res; + void __iomem *base; + struct clk *clk; + int retval; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(dev, "No platform data\n"); + return -EINVAL; + } + + clk = devm_clk_get(&pdev->dev, "usbhs"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Can't get the clock\n"); + return PTR_ERR(clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(dev, "Memory allocation failed\n"); + return -ENOMEM; + } + + spin_lock_init(&priv->lock); + priv->clk = clk; + priv->base = base; + priv->ugctrl2 = pdata->chan0_pci ? + USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS; + priv->ugctrl2 |= pdata->chan2_pci ? + USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS; + priv->phy.dev = dev; + priv->phy.label = dev_name(dev); + priv->phy.init = rcar_gen2_usb_phy_init; + priv->phy.shutdown = rcar_gen2_usb_phy_shutdown; + priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend; + + retval = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); + if (retval < 0) { + dev_err(dev, "Failed to add USB phy\n"); + return retval; + } + + platform_set_drvdata(pdev, priv); + + return retval; +} + +static int rcar_gen2_usb_phy_remove(struct platform_device *pdev) +{ + struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev); + + usb_remove_phy(&priv->phy); + + return 0; +} + +static struct platform_driver rcar_gen2_usb_phy_driver = { + .driver = { + .name = "usb_phy_rcar_gen2", + }, + .probe = rcar_gen2_usb_phy_probe, + .remove = rcar_gen2_usb_phy_remove, +}; + +module_platform_driver(rcar_gen2_usb_phy_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy"); +MODULE_AUTHOR("Valentine Barshak "); -- cgit v1.2.3 From 16b972a592ea2c9a3c2a3c12238de650fd4043a9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 11 Oct 2013 08:34:28 -0500 Subject: usb: dwc3: core: use pm_runtime_put_sync() on remove We are going to disable runtime_pm and we're removing the driver, we must disable the device now. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e88ffae80cac..74f9cf02da07 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -584,7 +584,7 @@ static int dwc3_remove(struct platform_device *pdev) usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); - pm_runtime_put(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); dwc3_debugfs_exit(dwc); -- cgit v1.2.3 From 1479e8411831c2112fa83b44664075e3ceea2533 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 9 Oct 2013 08:41:57 +0200 Subject: usb: gadget: s3c-hsotg: add isochronous transfers support This patch adds isochronous transfer support. It adds few modifications: - Modify s3c_hsotg_epint() function. Some interrupts are ignored for isochronous endpoints, (e.g. INTknTXFEmpMsk) becouse isochronous request is always transfered in single transaction, which ends with XferCompl interrupt. - Add Odd/Even microframe toggle to allow data transfering in each microframe in s3c_hsotg_epint() function. - Fix s3c_hsotg_ep_enable() function by supporting isochronous endpoint type. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 424b2ad00ec7..961abcd71314 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -83,9 +83,11 @@ struct s3c_hsotg_req; * @dir_in: Set to true if this endpoint is of the IN direction, which * means that it is sending data to the Host. * @index: The index for the endpoint registers. + * @interval - Interval for periodic endpoints * @name: The name array passed to the USB core. * @halted: Set if the endpoint has been halted. * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep * @sent_zlp: Set if we've sent a zero-length packet. * @total_data: The total number of data bytes done. * @fifo_size: The size of the FIFO (for periodic IN endpoints) @@ -121,9 +123,11 @@ struct s3c_hsotg_ep { unsigned char dir_in; unsigned char index; + unsigned char interval; unsigned int halted:1; unsigned int periodic:1; + unsigned int isochronous:1; unsigned int sent_zlp:1; char name[10]; @@ -1886,8 +1890,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); u32 ints; + u32 ctrl; ints = readl(hsotg->regs + epint_reg); + ctrl = readl(hsotg->regs + epctl_reg); /* Clear endpoint interrupts */ writel(ints, hsotg->regs + epint_reg); @@ -1896,6 +1902,14 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, __func__, idx, dir_in ? "in" : "out", ints); if (ints & DxEPINT_XferCompl) { + if (hs_ep->isochronous && hs_ep->interval == 1) { + if (ctrl & DxEPCTL_EOFrNum) + ctrl |= DxEPCTL_SetEvenFr; + else + ctrl |= DxEPCTL_SetOddFr; + writel(ctrl, hsotg->regs + epctl_reg); + } + dev_dbg(hsotg->dev, "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", __func__, readl(hsotg->regs + epctl_reg), @@ -1962,7 +1976,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, if (ints & DxEPINT_Back2BackSetup) dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); - if (dir_in) { + if (dir_in && !hs_ep->isochronous) { /* not sure if this is important, but we'll clear it anyway */ if (ints & DIEPMSK_INTknTXFEmpMsk) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", @@ -2581,13 +2595,18 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); /* default, set to non-periodic */ + hs_ep->isochronous = 0; hs_ep->periodic = 0; + hs_ep->interval = desc->bInterval; switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: - dev_err(hsotg->dev, "no current ISOC support\n"); - ret = -EINVAL; - goto out; + epctrl |= DxEPCTL_EPType_Iso; + epctrl |= DxEPCTL_SetEvenFr; + hs_ep->isochronous = 1; + if (dir_in) + hs_ep->periodic = 1; + break; case USB_ENDPOINT_XFER_BULK: epctrl |= DxEPCTL_EPType_Bulk; -- cgit v1.2.3 From 4fca54aa5829328a356aea31895b817dacba2861 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 9 Oct 2013 09:00:02 +0200 Subject: usb: gadget: s3c-hsotg: add multi count support This patch adds Multi Count support. It adds few modifications: - Fix s3c_hsotg_set_ep_maxpacket() function. Field wMaxPacketSize of endpoint descriptor is now splitted into maximum packet size value and number of additional transaction per microframe. - Modify s3c_hsotg_write_fifo() function. It actually calculates transfer size, taking into account Multi Count value, which indicates number of transactions per microframe. - Fix s3c_hsotg_start_req() function by setting number of packets to Multi Count field in DIEPTSIZ register for isochronous endpoints. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 961abcd71314..920e3c9af7d5 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -83,6 +83,7 @@ struct s3c_hsotg_req; * @dir_in: Set to true if this endpoint is of the IN direction, which * means that it is sending data to the Host. * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe * @interval - Interval for periodic endpoints * @name: The name array passed to the USB core. * @halted: Set if the endpoint has been halted. @@ -123,6 +124,7 @@ struct s3c_hsotg_ep { unsigned char dir_in; unsigned char index; + unsigned char mc; unsigned char interval; unsigned int halted:1; @@ -472,6 +474,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, void *data; int can_write; int pkt_round; + int max_transfer; to_write -= (buf_pos - hs_ep->last_load); @@ -539,8 +542,10 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, can_write *= 4; /* fifo size is in 32bit quantities. */ } - dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", - __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); + max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; + + dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", + __func__, gnptxsts, can_write, to_write, max_transfer); /* * limit to 512 bytes of data, it seems at least on the non-periodic @@ -555,8 +560,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, * the transfer to return that it did not run out of fifo space * doing it. */ - if (to_write > hs_ep->ep.maxpacket) { - to_write = hs_ep->ep.maxpacket; + if (to_write > max_transfer) { + to_write = max_transfer; s3c_hsotg_en_gsint(hsotg, periodic ? GINTSTS_PTxFEmp : @@ -567,7 +572,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, if (to_write > can_write) { to_write = can_write; - pkt_round = to_write % hs_ep->ep.maxpacket; + pkt_round = to_write % max_transfer; /* * Round the write down to an @@ -731,8 +736,16 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, else packets = 1; /* send one packet if length is zero. */ + if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { + dev_err(hsotg->dev, "req length > maxpacket*mc\n"); + return; + } + if (dir_in && index != 0) - epsize = DxEPTSIZ_MC(1); + if (hs_ep->isochronous) + epsize = DxEPTSIZ_MC(packets); + else + epsize = DxEPTSIZ_MC(1); else epsize = 0; @@ -1702,6 +1715,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; void __iomem *regs = hsotg->regs; u32 mpsval; + u32 mcval; u32 reg; if (ep == 0) { @@ -1710,10 +1724,15 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, if (mpsval > 3) goto bad_mps; hs_ep->ep.maxpacket = mps; + hs_ep->mc = 1; } else { mpsval = mps & DxEPCTL_MPS_MASK; if (mpsval > 1024) goto bad_mps; + mcval = ((mps >> 11) & 0x3) + 1; + hs_ep->mc = mcval; + if (mcval > 3) + goto bad_mps; hs_ep->ep.maxpacket = mpsval; } @@ -2599,6 +2618,9 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, hs_ep->periodic = 0; hs_ep->interval = desc->bInterval; + if (hs_ep->interval > 1 && hs_ep->mc > 1) + dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: epctrl |= DxEPCTL_EPType_Iso; -- cgit v1.2.3 From 7eb581d5a91519c1e851b07945492049c12c99df Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 11 Oct 2013 12:48:51 +0200 Subject: usb: gadget: s3c-hsotg: remove unused label This patch removes unused label. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 920e3c9af7d5..93f786669dd5 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2676,7 +2676,6 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, /* enable the endpoint interrupt */ s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); -out: spin_unlock_irqrestore(&hsotg->lock, flags); return ret; } -- cgit v1.2.3 From cd1086913ffef6d9656efdf35168b2b28675c245 Mon Sep 17 00:00:00 2001 From: Andreas Larsson Date: Fri, 11 Oct 2013 08:07:00 +0200 Subject: usb: gadget: Make VERBOSE_DEBUG enableable via Kconfig Create a way for VERBOSE_DEBUG to be enabled during drivers/usb/gadget/ build. Signed-off-by: Andreas Larsson Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 14 ++++++++++++++ drivers/usb/gadget/Makefile | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 604f885345f1..a91e6422f930 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -58,6 +58,20 @@ config USB_GADGET_DEBUG trying to track down. Never enable these messages for a production build. +config USB_GADGET_VERBOSE + bool "Verbose debugging Messages (DEVELOPMENT)" + depends on USB_GADGET_DEBUG + help + Many controller and gadget drivers will print verbose debugging + messages if you use this option to ask for those messages. + + Avoid enabling these messages, even if you're actively + debugging such a driver. Many drivers will emit so many + messages that the driver timings are affected, which will + either create new failure modes or remove the one you're + trying to track down. Never enable these messages for a + production build. + config USB_GADGET_DEBUG_FILES boolean "Debugging information files (DEVELOPMENT)" depends on PROC_FS diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index f1bd42a2cbba..f1af39603d4d 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,7 +1,8 @@ # # USB peripheral controller drivers # -ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o -- cgit v1.2.3 From 7f4d1e7bdd9f293a522e5559f1b64a95c066c15e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 11 Oct 2013 09:01:03 +0200 Subject: usb: phy: don't return with NULL from devm_usb_get_phy() The callers are expecting an ERR_PTR value in case of an error. Change he code to return with an encoded -ENOMEM value in the case of a failed devres_alloc call. Signed-off-by: Gabor Juhos Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index a9984c700d2c..1b74523e1fee 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -98,7 +98,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type) ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) - return NULL; + return ERR_PTR(-ENOMEM); phy = usb_get_phy(type); if (!IS_ERR(phy)) { -- cgit v1.2.3 From 81a1d5ea6670acecf1366cd6a4d328c123bdf9fa Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 15 Oct 2013 08:33:12 +0200 Subject: usb: gadget: storage_common: use strtobool instead of kstrtouint strtobool is more flexible for the user and is more appropriate in the context. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/storage_common.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index c7b78a1f6086..8bd5f2d838db 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -375,9 +375,9 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) { ssize_t rc; - unsigned ro; + bool ro; - rc = kstrtouint(buf, 2, &ro); + rc = strtobool(buf, &ro); if (rc) return rc; @@ -402,10 +402,10 @@ EXPORT_SYMBOL(fsg_store_ro); ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count) { - unsigned nofua; + bool nofua; int ret; - ret = kstrtouint(buf, 2, &nofua); + ret = strtobool(buf, &nofua); if (ret) return ret; @@ -452,10 +452,10 @@ EXPORT_SYMBOL(fsg_store_file); ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count) { - unsigned cdrom; + bool cdrom; int ret; - ret = kstrtouint(buf, 2, &cdrom); + ret = strtobool(buf, &cdrom); if (ret) return ret; @@ -468,10 +468,10 @@ EXPORT_SYMBOL(fsg_store_cdrom); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count) { - unsigned removable; + bool removable; int ret; - ret = kstrtouint(buf, 2, &removable); + ret = strtobool(buf, &removable); if (ret) return ret; -- cgit v1.2.3 From b8798636798ee04feb0f1bb87eec0027e3f68d98 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 15 Oct 2013 08:33:13 +0200 Subject: usb: gadget: storage_common: pass filesem to fsg_store_cdrom If cdrom flag is set ro flag is implied. Try setting the ro first, and only if it succeeds set the cdrom flag. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 7 ++++++- drivers/usb/gadget/storage_common.c | 42 +++++++++++++++++++++++++++---------- drivers/usb/gadget/storage_common.h | 3 ++- 3 files changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6e5a6daf1a12..6b5f45144cdf 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3281,7 +3281,12 @@ static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page) static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts, const char *page, size_t len) { - return fsg_store_cdrom(opts->lun, page, len); + struct fsg_opts *fsg_opts; + + fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + + return fsg_store_cdrom(opts->lun, &fsg_opts->common->filesem, page, + len); } static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom = diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 8bd5f2d838db..ec20a1f50c2d 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -371,6 +371,23 @@ ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) } EXPORT_SYMBOL(fsg_show_removable); +/* + * The caller must hold fsg->filesem for reading when calling this function. + */ +static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro) +{ + if (fsg_lun_is_open(curlun)) { + LDBG(curlun, "read-only status change prevented\n"); + return -EBUSY; + } + + curlun->ro = ro; + curlun->initially_ro = ro; + LDBG(curlun, "read-only status set to %d\n", curlun->ro); + + return 0; +} + ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count) { @@ -386,16 +403,11 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, * backing file is closed. */ down_read(filesem); - if (fsg_lun_is_open(curlun)) { - LDBG(curlun, "read-only status change prevented\n"); - rc = -EBUSY; - } else { - curlun->ro = ro; - curlun->initially_ro = ro; - LDBG(curlun, "read-only status set to %d\n", curlun->ro); + rc = _fsg_store_ro(curlun, ro); + if (!rc) rc = count; - } up_read(filesem); + return rc; } EXPORT_SYMBOL(fsg_store_ro); @@ -450,7 +462,8 @@ ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, } EXPORT_SYMBOL(fsg_store_file); -ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count) +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count) { bool cdrom; int ret; @@ -459,9 +472,16 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count) if (ret) return ret; - curlun->cdrom = cdrom; + down_read(filesem); + ret = cdrom ? _fsg_store_ro(curlun, true) : 0; - return count; + if (!ret) { + curlun->cdrom = cdrom; + ret = count; + } + up_read(filesem); + + return ret; } EXPORT_SYMBOL(fsg_store_cdrom); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h index e0f7aa69c7ed..c74c2fdbd56e 100644 --- a/drivers/usb/gadget/storage_common.h +++ b/drivers/usb/gadget/storage_common.h @@ -221,7 +221,8 @@ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); -ssize_t fsg_store_cdrom(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count); -- cgit v1.2.3 From ab93e014f35374a8169b0f465fccee69e04ea34c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:17 +0200 Subject: usb: gadget: s3c-hsotg: fix "protocol stall" handling After normal handling of SetupDone interrupt, XferCompl interrupt occurs, and then we enqueue new setup request. But when ep0 is stalled, there is no XferCompl, so we have to enqueue setup request immediately after stalling ep. Otherwise incoming control requests won't be processed correctly. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 93f786669dd5..4faf5e70e093 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1164,6 +1164,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, return 1; } +static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); + /** * s3c_hsotg_process_control - process a control request * @hsotg: The device state @@ -1263,11 +1265,15 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, * don't believe we need to anything more to get the EP * to reply with a STALL packet */ + + /* + * complete won't be called, so we enqueue + * setup request here + */ + s3c_hsotg_enqueue_setup(hsotg); } } -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); - /** * s3c_hsotg_complete_setup - completion of a setup transfer * @ep: The endpoint the request was on. -- cgit v1.2.3 From 5cb2ff0cdd60aef07c592a9d09349b5993fdf9b4 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:18 +0200 Subject: usb: gadget: s3c-hsotg: fix s3c_hsotg_write_fifo function for dedicated fifo mode In s3c_hsotg_write_fifo function PTxFEmp/NPTxFEmp interrupts are enabled only in shared-fifo mode. In dedicated-fifo mode they should not be used (when enabled then cause interrupt storm). Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 4faf5e70e093..bb173852ae4c 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -563,9 +563,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, if (to_write > max_transfer) { to_write = max_transfer; - s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + s3c_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } /* see if we can write data */ @@ -590,9 +592,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, * is more room left. */ - s3c_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTxFEmp : - GINTSTS_NPTxFEmp); + /* it's needed only when we do not use dedicated fifos */ + if (!hsotg->dedicated_fifos) + s3c_hsotg_en_gsint(hsotg, + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", -- cgit v1.2.3 From afcf4169a41ef02d3f833f4eccac11038bd2b39c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:19 +0200 Subject: usb: gadget: s3c-hsotg: fix endpoint interrupts handling When s3c_hsotg_trytx is called for ep without enqueued request, interrupts for this ep are disabled, to prevent interrupt flooding. Interrupts are enabled when new request for this ep is starting. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index bb173852ae4c..30cead183d50 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -841,6 +841,9 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, readl(hsotg->regs + epctrl_reg)); + + /* enable ep interrupts */ + s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); } /** @@ -1814,8 +1817,16 @@ static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, { struct s3c_hsotg_req *hs_req = hs_ep->req; - if (!hs_ep->dir_in || !hs_req) + if (!hs_ep->dir_in || !hs_req) { + /** + * if request is not enqueued, we disable interrupts + * for endpoints, excepting ep0 + */ + if (hs_ep->index != 0) + s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, + hs_ep->dir_in, 0); return 0; + } if (hs_req->req.actual < hs_req->req.length) { dev_dbg(hsotg->dev, "trying to write more for ep%d\n", -- cgit v1.2.3 From 7e8046505c9fda30c3c2a64f1cc84390e2458c54 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:20 +0200 Subject: usb: gadget: s3c-hsotg: add DAINT masking In OEPInt/IEPInt interrupts handling added bitwise and of DAINT and DAINTMSK, because we should handle masked interrupts only. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 30cead183d50..8d71a9b09005 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2433,10 +2433,14 @@ irq_retry: if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { u32 daint = readl(hsotg->regs + DAINT); - u32 daint_out = daint >> DAINT_OutEP_SHIFT; - u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); + u32 daintmsk = readl(hsotg->regs + DAINTMSK); + u32 daint_out, daint_in; int ep; + daint &= daintmsk; + daint_out = daint >> DAINT_OutEP_SHIFT; + daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); + dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { -- cgit v1.2.3 From a18ed7b036454794dc2d18b92e531c76953d556f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:21 +0200 Subject: usb: gadget: s3c-hsotg: fix "halted" property updating Property "halted" of s3c_hsotg_ep structure is actually initialised when ep enabled, and changed when halt is set/cleared. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 8d71a9b09005..a854cb3c965f 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2641,6 +2641,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, /* default, set to non-periodic */ hs_ep->isochronous = 0; hs_ep->periodic = 0; + hs_ep->halted = 0; hs_ep->interval = desc->bInterval; if (hs_ep->interval > 1 && hs_ep->mc > 1) @@ -2842,6 +2843,8 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) writel(epctl, hs->regs + epreg); + hs_ep->halted = value; + return 0; } -- cgit v1.2.3 From bd9ef7bf0c8e129f24b28366e6c7e9ea92a7aed6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:22 +0200 Subject: usb: gadget: s3c-hsotg: fix clear feature ENDPOINT_HALT All requests for endpoint are completed when it was halted and the halt was cleared by CLEAR_FEATURE, but not when new state is same as previous. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a854cb3c965f..70615585b48d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1115,6 +1115,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); struct s3c_hsotg_ep *ep; int ret; + bool halted; dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", __func__, set ? "SET" : "CLEAR"); @@ -1129,6 +1130,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, switch (le16_to_cpu(ctrl->wValue)) { case USB_ENDPOINT_HALT: + halted = ep->halted; + s3c_hsotg_ep_sethalt(&ep->ep, set); ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); @@ -1138,7 +1141,12 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, return ret; } - if (!set) { + /* + * we have to complete all requests for ep if it was + * halted, and the halt was cleared by CLEAR_FEATURE + */ + + if (!set && halted) { /* * If we have request in progress, * then complete it -- cgit v1.2.3 From 8acc8296f94349e7a933dd97e8f5d0ec16d4b4db Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 19 Sep 2013 11:50:23 +0200 Subject: usb: gadget: s3c-hsotg: fix interrupt configuration in dedicated-fifo mode In dedicated-fifo mode TxFIFOEmpty interrupt should be asserted when TxFIFO for this endpoint is completly empty, so NPTxFEmpLvl and PTxFEmpLvl bits are set in GAHBCFG register. In DIEPMSK register INTknTXFEmpMsk is set, becouse it's needed to indicate FIFO Empty state. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 70615585b48d..a9cae1ff0449 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2304,15 +2304,19 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) GAHBCFG_HBstLen_Incr4, hsotg->regs + GAHBCFG); else - writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG); + writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NPTxFEmpLvl | + GAHBCFG_PTxFEmpLvl) : 0) | + GAHBCFG_GlblIntrEn, + hsotg->regs + GAHBCFG); /* - * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end - * up being flooded with interrupts if the host is polling the - * endpoint to try and read data. + * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts + * when we have no data to transfer. Otherwise we get being flooded by + * interrupts. */ - writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) | + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty | + DIEPMSK_INTknTXFEmpMsk : 0) | DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | DIEPMSK_INTknEPMisMsk, -- cgit v1.2.3 From 811f33033f9e6a00756e38990d82214c8c619f4c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 24 Sep 2013 11:24:28 +0200 Subject: usb: gadget: s3c-hsotg: fix can_write limit for non-periodic endpoints Value of can_write variable in s3c_hsotg_write_fifo function should be limited to 512 only for non-periodic endpoints. There was some discrepancy between comment and code, becouse comment suggests correct behavior, but in the code limit was applied to periodic endpoints too. So there is additional check causing the limitation concerns only non-periodic endpoints. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/s3c-hsotg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a9cae1ff0449..9875d9c0823f 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -552,7 +552,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, * FIFO, requests of >512 cause the endpoint to get stuck with a * fragment of the end of the transfer in it. */ - if (can_write > 512) + if (can_write > 512 && !periodic) can_write = 512; /* -- cgit v1.2.3 From ae44df2e21b50f9fff28ac75c57e399c04df812c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 15 Oct 2013 18:29:22 +0200 Subject: usb: musb: call musb_start() only once in OTG mode In commit 001dd84 ("usb: musb: start musb on the udc side, too") it was ensured that the state engine is started also in OTG mode after a removal / insertion of the gadget. Unfortunately this change also introduced a bug: If the device is configured as OTG and it connected with a remote host _without_ loading a gadget then we bug() later (because musb->otg->gadget is not initialized). Initially I assumed it might be nice to have the host part of musb in OTG mode working without having a gadget loaded. This bug and fact that it wasn't working like this before the host/gadget split made me realize that this was a silly idea. This patch now introduces back the old behavior where in OTG mode the host mode is only working after the gadget has been loaded. Cc: stable@vger.kernel.org # v3.11 Cc: Daniel Mack Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_virthub.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a523950c2b32..d8bbdb366beb 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -266,6 +266,23 @@ int musb_hub_status_data(struct usb_hcd *hcd, char *buf) return retval; } +static int musb_has_gadget(struct musb *musb) +{ + /* + * In host-only mode we start a connection right away. In OTG mode + * we have to wait until we loaded a gadget. We don't really need a + * gadget if we operate as a host but we should not start a session + * as a device without a gadget or else we explode. + */ +#ifdef CONFIG_USB_MUSB_HOST + return 1; +#else + if (musb->port_mode == MUSB_PORT_MODE_HOST) + return 1; + return musb->g.dev.driver != NULL; +#endif +} + int musb_hub_control( struct usb_hcd *hcd, u16 typeReq, @@ -408,7 +425,7 @@ int musb_hub_control( * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up. */ - if (!hcd->self.is_b_host) + if (!hcd->self.is_b_host && musb_has_gadget(musb)) musb_start(musb); break; case USB_PORT_FEAT_RESET: -- cgit v1.2.3 From 8b9fcce2d88586b9a120ff3e039d8f42413f0bb0 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 15 Oct 2013 18:29:23 +0200 Subject: usb: musb: dsps: move try_idle to start hook The timer is initialized right after musb is probed. There is actually no need to have this timer running because _nothing_ will happen until we have the gadget loaded. Also we need this timer only if we run in OTG mode _and_ we need it also after the gadget has been replaced with another one. I've been looking at am35x.c, da8xx.c, omap2430.c, tusb6010.c. da8xx seem to have the same problem as dsps and doing mostly the same thing. tusb6010 seem to do something different and do some actual "idle / power saving" work so I am not too comfortable to remove musb_platform_try_idle() from musb_gadget_setup(). Therefore this patch does not start the timer if there is no gadget active (which is at musb_gadget_setup() at time). In order to have the timer active after the gadget is loaded it will be triggered from dsps_musb_enable(). Cc: stable@vger.kernel.org # v3.11 Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index c7fe16db6bb6..e0d81b8318ab 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -121,6 +121,7 @@ struct dsps_glue { unsigned long last_timer; /* last timer data for each instance */ }; +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout); /** * dsps_musb_enable - enable interrupts */ @@ -143,6 +144,7 @@ static void dsps_musb_enable(struct musb *musb) /* Force the DRVVBUS IRQ so we can start polling for ID change. */ dsps_writel(reg_base, wrp->coreintr_set, (1 << wrp->drvvbus) << wrp->usb_shift); + dsps_musb_try_idle(musb, 0); } /** @@ -234,6 +236,9 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->port_mode == MUSB_PORT_MODE_HOST) return; + if (!musb->g.dev.driver) + return; + if (time_after(glue->last_timer, timeout) && timer_pending(&glue->timer)) { dev_dbg(musb->controller, -- cgit v1.2.3 From 807d0d2b35f94a8074d195bfdabe407f0089a694 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 15 Oct 2013 18:29:24 +0200 Subject: usb: musb: dsps: remove declartion for dsps_musb_try_idle() This patch moves dsps_musb_try_idle() before dsps_musb_enable() so the declaration (of dsps_musb_try_idle() can be removed. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 75 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e0d81b8318ab..9efba94c35f2 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -121,7 +121,43 @@ struct dsps_glue { unsigned long last_timer; /* last timer data for each instance */ }; -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout); +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ + struct device *dev = musb->controller; + struct dsps_glue *glue = dev_get_drvdata(dev->parent); + + if (timeout == 0) + timeout = jiffies + msecs_to_jiffies(3); + + /* Never idle if active, or when VBUS timeout is not set as host */ + if (musb->is_active || (musb->a_wait_bcon == 0 && + musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + dev_dbg(musb->controller, "%s active, deleting timer\n", + usb_otg_state_string(musb->xceiv->state)); + del_timer(&glue->timer); + glue->last_timer = jiffies; + return; + } + if (musb->port_mode == MUSB_PORT_MODE_HOST) + return; + + if (!musb->g.dev.driver) + return; + + if (time_after(glue->last_timer, timeout) && + timer_pending(&glue->timer)) { + dev_dbg(musb->controller, + "Longer idle timer already pending, ignoring...\n"); + return; + } + glue->last_timer = timeout; + + dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", + usb_otg_state_string(musb->xceiv->state), + jiffies_to_msecs(timeout - jiffies)); + mod_timer(&glue->timer, timeout); +} + /** * dsps_musb_enable - enable interrupts */ @@ -216,43 +252,6 @@ static void otg_timer(unsigned long _musb) spin_unlock_irqrestore(&musb->lock, flags); } -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - - if (timeout == 0) - timeout = jiffies + msecs_to_jiffies(3); - - /* Never idle if active, or when VBUS timeout is not set as host */ - if (musb->is_active || (musb->a_wait_bcon == 0 && - musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer); - glue->last_timer = jiffies; - return; - } - if (musb->port_mode == MUSB_PORT_MODE_HOST) - return; - - if (!musb->g.dev.driver) - return; - - if (time_after(glue->last_timer, timeout) && - timer_pending(&glue->timer)) { - dev_dbg(musb->controller, - "Longer idle timer already pending, ignoring...\n"); - return; - } - glue->last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->state), - jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer, timeout); -} - static irqreturn_t dsps_interrupt(int irq, void *hci) { struct musb *musb = hci; -- cgit v1.2.3 From 0f901c980110cd69b63670096465b35377e73b1c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 15 Oct 2013 18:29:25 +0200 Subject: usb: musb: dsps: redo the otg timer According to the comments, we rely on the OTG timer because the core does not expose some important OTG details. So far this is all I know. After playing with OTG I stumbled over a problem: musb is recognized as a B-device without a problem. Whenever a cable is plugged, the VBUS rises, musb recognizes this as a starting session, sets the MUSB_DEVCTL_SESSION bit by itself and a RESET interrupt occurs, the session starts. Good. After a disconnect, the timer is started and re-starts itself because it remains in B_IDLE with the BDEVICE set. I didn't figure the the reason or the need for it. Nothing changes here except for OTG state from B to A device if the BDEVICE bit disappears. This doesn't make much sense to me because nothing happens after this. _IF_ we receive an interrupt before the state change then we may act on wrong condition. Plugging a B-device (and letting MUSB act as host) doesn't work here. The reason seems to be that the MUSB tries to start a session, it fails and then it removes the bit. So we never start as a host. This patch sets the MUSB_DEVCTL_SESSION bit in the IDLE state so musb can try to establish a session as host. After the bit is set, musb tries to start a session and if it fails it clears the bit. Therefore it will try over and over again until a session either as host or as device is established. The readout of the MUSB_DEVCTL register after the removal the MUSB_DEVCTL_SESSION (in A_WAIT_BCON) has been removed because it did not contain the BDEVICE bit set (in the second read) leading to A_IDLE. After plugging a host musb assumed that it is also a host and complained about a missing reset. However a third read of the register has has the BDEVICE bit set so it seems that it is not stable. This mostly what da8xx.c is doing except that we set the timer also after A_WAIT_BCON so the session bit can be triggered. Whit this change I was able to keep am335x-evm in OTG mode and plug in either a HOST or a DEVICE and in a random order and the device was recognized. Cc: stable@vger.kernel.org # v3.11 Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 9efba94c35f2..e1da6702078a 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -209,6 +209,7 @@ static void otg_timer(unsigned long _musb) const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; unsigned long flags; + int skip_session = 0; /* * We poll because DSPS IP's won't expose several OTG-critical @@ -221,10 +222,12 @@ static void otg_timer(unsigned long _musb) spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: - devctl &= ~MUSB_DEVCTL_SESSION; - dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl); + dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); + skip_session = 1; + /* fall */ - devctl = dsps_readb(musb->mregs, MUSB_DEVCTL); + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: if (devctl & MUSB_DEVCTL_BDEVICE) { musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); @@ -232,20 +235,15 @@ static void otg_timer(unsigned long _musb) musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } + if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) + dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; dsps_writel(musb->ctrl_base, wrp->coreintr_set, MUSB_INTR_VBUSERROR << wrp->usb_shift); break; - case OTG_STATE_B_IDLE: - devctl = dsps_readb(mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&glue->timer, - jiffies + wrp->poll_seconds * HZ); - else - musb->xceiv->state = OTG_STATE_A_IDLE; - break; default: break; } -- cgit v1.2.3 From 24616eb66a996d30bf6449feb313a29cd1083cf9 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 15 Oct 2013 18:29:26 +0200 Subject: usb: musb: dsps: run the timer only on OTG systems I introduced this check here because it looked wrong in HOST only configurions. The timer would remove that session bit and will never come back and so there would not be another session. Now that I played with OTG for a while I belive this workaround is only required for the OTG mode because we have to end the session and then we have to try to start manually. Therefore, this patch limits this timer to the OTG only port mode so we don't need to poll around in device only mode. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e1da6702078a..82e1da08a67b 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -138,7 +138,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) glue->last_timer = jiffies; return; } - if (musb->port_mode == MUSB_PORT_MODE_HOST) + if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) return; if (!musb->g.dev.driver) -- cgit v1.2.3 From 5bb7289d7f9d5c7418892c342824196602d20729 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 16 Oct 2013 08:34:51 +0200 Subject: usb: gadget: f_mass_storage: style corrections, cleanup & simplification Fix spacing, improve error code returned, remove unused #define, use strtobool() instead of kstrtou8(). Acked-by: Michal Nazarewicz Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_mass_storage.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 6b5f45144cdf..8fa8b1f771fb 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3209,9 +3209,9 @@ static void fsg_lun_attr_release(struct config_item *item) } static struct configfs_item_operations fsg_lun_item_ops = { - .release = fsg_lun_attr_release, - .show_attribute = fsg_lun_opts_attr_show, - .store_attribute = fsg_lun_opts_attr_store, + .release = fsg_lun_attr_release, + .show_attribute = fsg_lun_opts_attr_show, + .store_attribute = fsg_lun_opts_attr_store, }; static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page) @@ -3323,8 +3323,6 @@ static struct config_item_type fsg_lun_type = { .ct_owner = THIS_MODULE, }; -#define MAX_NAME_LEN 40 - static struct config_group *fsg_lun_make(struct config_group *group, const char *name) { @@ -3348,7 +3346,8 @@ static struct config_group *fsg_lun_make(struct config_group *group, fsg_opts = to_fsg_opts(&group->cg_item); if (num >= FSG_MAX_LUNS) - return ERR_PTR(-ENODEV); + return ERR_PTR(-ERANGE); + mutex_lock(&fsg_opts->lock); if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { ret = -EBUSY; @@ -3364,7 +3363,6 @@ static struct config_group *fsg_lun_make(struct config_group *group, memset(&config, 0, sizeof(config)); config.removable = true; - ret = fsg_common_create_lun(fsg_opts->common, &config, num, name, (const char **)&group->cg_item.ci_name); if (ret) { @@ -3418,9 +3416,9 @@ static void fsg_attr_release(struct config_item *item) } static struct configfs_item_operations fsg_item_ops = { - .release = fsg_attr_release, - .show_attribute = fsg_opts_attr_show, - .store_attribute = fsg_opts_attr_store, + .release = fsg_attr_release, + .show_attribute = fsg_opts_attr_show, + .store_attribute = fsg_opts_attr_store, }; static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) @@ -3438,22 +3436,23 @@ static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, size_t len) { int ret; - u8 num; + bool stall; mutex_lock(&opts->lock); + if (opts->refcnt) { - ret = -EBUSY; - goto end; + mutex_unlock(&opts->lock); + return -EBUSY; } - ret = kstrtou8(page, 0, &num); - if (ret) - goto end; - opts->common->can_stall = num != 0; - ret = len; + ret = strtobool(page, &stall); + if (!ret) { + opts->common->can_stall = stall; + ret = len; + } -end: mutex_unlock(&opts->lock); + return ret; } -- cgit v1.2.3 From 0d2dd7eaed1dac07b266ca2c662ff4a184a3060f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 16 Oct 2013 12:50:06 +0200 Subject: usb: musb: core: properly free host / device structs in err path The patch fixes two issues in the error path cleanup: - in MUSB_PORT_MODE_DUAL_ROLE mode, if musb_gadget_setup() fails we never cleanup the host struct earlier allocated. - if musb_init_debugfs() or sysfs_create_group() fails, then we never free the host part initialization, only device part. Cc: stable@vger.kernel.org # v3.11 Cc: Daniel Mack Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 5b4fa79a277b..6203ad38e913 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1901,6 +1901,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (status < 0) goto fail3; status = musb_gadget_setup(musb); + if (status) + musb_host_cleanup(musb); break; default: dev_err(dev, "unsupported port mode %d\n", musb->port_mode); @@ -1927,6 +1929,7 @@ fail5: fail4: musb_gadget_cleanup(musb); + musb_host_cleanup(musb); fail3: if (musb->dma_controller) -- cgit v1.2.3 From 8d1aad7485e653c2c5fd985b326096f680f7d918 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 16 Oct 2013 12:50:07 +0200 Subject: usb: musb: core: Call dma_controller_destroy() in error path only once. In commit f3ce4d5 ("usb: musb: core: call dma_controller_destroy() in the err path") I erroneously assumed that the dma controller is not removed in the error patch. This was wrong because it happens later via musb_free(). That means the original commit can be reverted because it is wrong or we do this, so it is more obvious. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 6203ad38e913..7fd213785d52 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1764,8 +1764,6 @@ static void musb_free(struct musb *musb) free_irq(musb->nIrq, musb); } cancel_work_sync(&musb->irq_work); - if (musb->dma_controller) - dma_controller_destroy(musb->dma_controller); musb_host_free(musb); } @@ -1990,6 +1988,9 @@ static int musb_remove(struct platform_device *pdev) musb_exit_debugfs(musb); musb_shutdown(pdev); + if (musb->dma_controller) + dma_controller_destroy(musb->dma_controller); + musb_free(musb); device_init_wakeup(dev, 0); return 0; -- cgit v1.2.3 From 4805414705df77d946b41df4f8b315e2b089eec4 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 16 Oct 2013 12:50:08 +0200 Subject: usb: musb: cppi41: allow to defer probing if DMA isn't yet available If everything (musb, cppi41, phy) is built-in then musb will start without the dma engine printing only |musb-hdrc musb-hdrc.0.auto: Falied to request rx1. The reason for this is that the musb device structs are created & probed before those of the cppi41 device. So the cppi41 device is probed too late. As a workaround for this allow the musb_cppi41 part to defer the probe if everything is fine except for the missing DMA controller. In case of another error we continue. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 8 +++++++- drivers/usb/musb/musb_cppi41.c | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 7fd213785d52..4db987f07f67 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1838,8 +1838,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) pm_runtime_get_sync(musb->controller); - if (use_dma && dev->dma_mask) + if (use_dma && dev->dma_mask) { musb->dma_controller = dma_controller_create(musb, musb->mregs); + if (IS_ERR(musb->dma_controller)) { + status = PTR_ERR(musb->dma_controller); + goto fail2_5; + } + } /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); @@ -1932,6 +1937,7 @@ fail4: fail3: if (musb->dma_controller) dma_controller_destroy(musb->dma_controller); +fail2_5: pm_runtime_put_sync(musb->controller); fail2: diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index ae959746f77f..ff9d6de2b746 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -484,6 +484,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) if (ret) goto err; + ret = -EINVAL; if (port > MUSB_DMA_NUM_CHANNELS || !port) goto err; if (is_tx) @@ -503,6 +504,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) dc = dma_request_slave_channel(dev, str); if (!dc) { dev_err(dev, "Falied to request %s.\n", str); + ret = -EPROBE_DEFER; goto err; } cppi41_channel->dc = dc; @@ -510,7 +512,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) return 0; err: cppi41_release_all_dma_chans(controller); - return -EINVAL; + return ret; } void dma_controller_destroy(struct dma_controller *c) @@ -526,7 +528,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base) { struct cppi41_dma_controller *controller; - int ret; + int ret = 0; if (!musb->controller->of_node) { dev_err(musb->controller, "Need DT for the DMA engine.\n"); @@ -553,5 +555,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, plat_get_fail: kfree(controller); kzalloc_fail: + if (ret == -EPROBE_DEFER) + return ERR_PTR(ret); return NULL; } -- cgit v1.2.3 From 80d7d8a768cda6e8a08ab805a977d08741011da1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 17 Oct 2013 13:55:06 +0530 Subject: usb: phy: twl6030-usb: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly to avoid build breakage in the future. Signed-off-by: Sachin Kamat Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-twl6030-usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 16dbc9382678..30e8a61552d4 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -33,6 +33,7 @@ #include #include #include +#include /* usb register definitions */ #define USB_VENDOR_ID_LSB 0x00 -- cgit v1.2.3