mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Linux 3.9-rc3
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQEcBAABAgAGBQJRRkrbAAoJEHm+PkMAQRiGy3oH/jrbHinYs0auurANgx4TdtWT /WNajstKBqLOJJ6cnTR7sOqwOVlptt65EbbTs+qGyZ2Z2W/Lg0BMenHvNHo4ER8C e7UbMdBCSLKBjAMKh1XCoZscGv4Exm8WRH3Vc5yP0Hafj3EzSAVLY1dta9WKKoQi bh7D1ErUlbU1zczA1w5YbPF0LqFKRvyZOwebMCCAKAxv5wWAxmbcPNxVR4sufkjg k6TkQ2ysgWivZAfy3tJYOcxiEu7ahpZVEuYdlZEJQXHRQUfoNljQlOp4BqKsYUai 5A0kaf2VpKay/7pkhvTfBBcF/jFJ68pYP6gQ2ThNdr0b5kOiAfMWj030Xyngnhg= =iO9t -----END PGP SIGNATURE----- Merge tag 'v3.9-rc3' into next Merge with mainline to bring in module_platform_driver_probe() and devm_ioremap_resource().
This commit is contained in:
commit
688d794c4c
17348 changed files with 1080737 additions and 591285 deletions
|
|
@ -37,6 +37,7 @@ config USB_ARCH_HAS_EHCI
|
|||
default y if ARCH_W90X900
|
||||
default y if ARCH_AT91
|
||||
default y if ARCH_MXC
|
||||
default y if ARCH_MXS
|
||||
default y if ARCH_OMAP3
|
||||
default y if ARCH_CNS3XXX
|
||||
default y if ARCH_VT8500
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
|
|||
obj-$(CONFIG_USB_SERIAL) += serial/
|
||||
|
||||
obj-$(CONFIG_USB) += misc/
|
||||
obj-$(CONFIG_USB_COMMON) += phy/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += phy/
|
||||
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
|
||||
|
||||
obj-$(CONFIG_USB_ATM) += atm/
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static irqreturn_t c67x00_irq(int irq, void *__dev)
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static int __devinit c67x00_drv_probe(struct platform_device *pdev)
|
||||
static int c67x00_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct c67x00_device *c67x00;
|
||||
struct c67x00_platform_data *pdata;
|
||||
|
|
@ -191,7 +191,7 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit c67x00_drv_remove(struct platform_device *pdev)
|
||||
static int c67x00_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
|
@ -219,7 +219,7 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver c67x00_driver = {
|
||||
.probe = c67x00_drv_probe,
|
||||
.remove = __devexit_p(c67x00_drv_remove),
|
||||
.remove = c67x00_drv_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "c67x00",
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
|
|||
/* -------------------------------------------------------------------------- */
|
||||
/* Transactions */
|
||||
|
||||
static inline u16 ll_recv_msg(struct c67x00_device *dev)
|
||||
static inline int ll_recv_msg(struct c67x00_device *dev)
|
||||
{
|
||||
u16 res;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ struct c67x00_urb_priv {
|
|||
#define TD_PIDEP_OFFSET 0x04
|
||||
#define TD_PIDEPMASK_PID 0xF0
|
||||
#define TD_PIDEPMASK_EP 0x0F
|
||||
#define TD_PORTLENMASK_DL 0x02FF
|
||||
#define TD_PORTLENMASK_DL 0x03FF
|
||||
#define TD_PORTLENMASK_PN 0xC000
|
||||
|
||||
#define TD_STATUS_OFFSET 0x07
|
||||
|
|
@ -590,7 +590,7 @@ static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
|
|||
{
|
||||
struct c67x00_td *td;
|
||||
struct c67x00_urb_priv *urbp = urb->hcpriv;
|
||||
const __u8 active_flag = 1, retry_cnt = 1;
|
||||
const __u8 active_flag = 1, retry_cnt = 3;
|
||||
__u8 cmd = 0;
|
||||
int tt = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ config USB_CHIPIDEA_UDC
|
|||
config USB_CHIPIDEA_HOST
|
||||
bool "ChipIdea host controller"
|
||||
depends on USB=y || USB=USB_CHIPIDEA
|
||||
depends on USB_EHCI_HCD
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
help
|
||||
Say Y here to enable host controller functionality of the
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
|
|||
|
||||
/* End of common functions shared by usbmisc drivers*/
|
||||
|
||||
static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = {
|
||||
static struct ci13xxx_platform_data ci13xxx_imx_platdata = {
|
||||
.name = "ci13xxx_imx",
|
||||
.flags = CI13XXX_REQUIRE_TRANSCEIVER |
|
||||
CI13XXX_PULLUP_ON_VBUS |
|
||||
|
|
@ -93,7 +93,7 @@ static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = {
|
|||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
static int ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data;
|
||||
struct platform_device *plat_ci, *phy_pdev;
|
||||
|
|
@ -220,7 +220,7 @@ put_np:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ci13xxx_imx_remove(struct platform_device *pdev)
|
||||
static int ci13xxx_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
|
|||
|
||||
static struct platform_driver ci13xxx_imx_driver = {
|
||||
.probe = ci13xxx_imx_probe,
|
||||
.remove = __devexit_p(ci13xxx_imx_remove),
|
||||
.remove = ci13xxx_imx_remove,
|
||||
.driver = {
|
||||
.name = "imx_usb",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ struct usbmisc_usb_device {
|
|||
struct device *dev; /* usb controller device */
|
||||
int index;
|
||||
|
||||
int disable_oc:1; /* over current detect disabled */
|
||||
unsigned int disable_oc:1; /* over current detect disabled */
|
||||
};
|
||||
|
||||
int usbmisc_set_ops(const struct usbmisc_ops *ops);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
|
|||
.notify_event = ci13xxx_msm_notify_event,
|
||||
};
|
||||
|
||||
static int __devinit ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
static int ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci;
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ static int __devinit ci13xxx_msm_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit ci13xxx_msm_remove(struct platform_device *pdev)
|
||||
static int ci13xxx_msm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ static int __devexit ci13xxx_msm_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver ci13xxx_msm_driver = {
|
||||
.probe = ci13xxx_msm_probe,
|
||||
.remove = __devexit_p(ci13xxx_msm_remove),
|
||||
.remove = ci13xxx_msm_remove,
|
||||
.driver = { .name = "msm_hsusb", },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ struct ci13xxx_platform_data penwell_pci_platdata = {
|
|||
* Allocates basic PCI resources for this USB device controller, and then
|
||||
* invokes the udc_probe() method to start the UDC associated with it
|
||||
*/
|
||||
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
|
||||
static int ci13xxx_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ci13xxx_platform_data *platdata = (void *)id->driver_data;
|
||||
|
|
@ -107,7 +107,7 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
|
|||
* first invoking the udc_remove() and then releases
|
||||
* all PCI resources allocated for this USB device controller
|
||||
*/
|
||||
static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
|
||||
static void ci13xxx_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci = pci_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ static struct pci_driver ci13xxx_pci_driver = {
|
|||
.name = UDC_DRIVER_NAME,
|
||||
.id_table = ci13xxx_pci_id_table,
|
||||
.probe = ci13xxx_pci_probe,
|
||||
.remove = __devexit_p(ci13xxx_pci_remove),
|
||||
.remove = ci13xxx_pci_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(ci13xxx_pci_driver);
|
||||
|
|
|
|||
|
|
@ -385,12 +385,13 @@ EXPORT_SYMBOL_GPL(ci13xxx_add_device);
|
|||
|
||||
void ci13xxx_remove_device(struct platform_device *pdev)
|
||||
{
|
||||
int id = pdev->id;
|
||||
platform_device_unregister(pdev);
|
||||
ida_simple_remove(&ci_ida, pdev->id);
|
||||
ida_simple_remove(&ci_ida, id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
|
||||
|
||||
static int __devinit ci_hdrc_probe(struct platform_device *pdev)
|
||||
static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ci13xxx *ci;
|
||||
|
|
@ -410,7 +411,7 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
base = devm_request_and_ioremap(dev, res);
|
||||
if (!res) {
|
||||
if (!base) {
|
||||
dev_err(dev, "can't request and ioremap resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -508,7 +509,7 @@ rm_wq:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ci_hdrc_remove(struct platform_device *pdev)
|
||||
static int ci_hdrc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx *ci = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -523,7 +524,7 @@ static int __devexit ci_hdrc_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver ci_hdrc_driver = {
|
||||
.probe = ci_hdrc_probe,
|
||||
.remove = __devexit_p(ci_hdrc_remove),
|
||||
.remove = ci_hdrc_remove,
|
||||
.driver = {
|
||||
.name = "ci_hdrc",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -160,9 +160,6 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr,
|
|||
gadget->speed);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
|
||||
gadget->max_speed);
|
||||
/* TODO: Scheduled for removal in 3.8. */
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
|
||||
gadget_is_dualspeed(gadget));
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
|
||||
gadget->is_otg);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
|
||||
|
|
@ -225,7 +222,7 @@ static struct {
|
|||
} dbg_data = {
|
||||
.idx = 0,
|
||||
.tty = 0,
|
||||
.lck = __RW_LOCK_UNLOCKED(lck)
|
||||
.lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,77 +20,18 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
|
||||
#define CHIPIDEA_EHCI
|
||||
#include "../host/ehci-hcd.c"
|
||||
#include "../host/ehci.h"
|
||||
|
||||
#include "ci.h"
|
||||
#include "bits.h"
|
||||
#include "host.h"
|
||||
|
||||
static int ci_ehci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int ret;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ret = ehci_setup(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hc_driver ci_ehci_hc_driver = {
|
||||
.description = "ehci_hcd",
|
||||
.product_desc = "ChipIdea HDRC EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ci_ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
static struct hc_driver __read_mostly ci_ehci_hc_driver;
|
||||
|
||||
static irqreturn_t host_irq(struct ci13xxx *ci)
|
||||
{
|
||||
|
|
@ -129,6 +70,9 @@ static int host_start(struct ci13xxx *ci)
|
|||
else
|
||||
ci->hcd = hcd;
|
||||
|
||||
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -157,5 +101,7 @@ int ci_hdrc_host_init(struct ci13xxx *ci)
|
|||
rdrv->name = "host";
|
||||
ci->roles[CI_ROLE_HOST] = rdrv;
|
||||
|
||||
ehci_init_driver(&ci_ehci_hc_driver, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1767,7 +1767,7 @@ static int udc_start(struct ci13xxx *ci)
|
|||
goto put_transceiver;
|
||||
}
|
||||
|
||||
retval = dbg_create_files(&ci->gadget.dev);
|
||||
retval = dbg_create_files(ci->dev);
|
||||
if (retval)
|
||||
goto unreg_device;
|
||||
|
||||
|
|
@ -1796,7 +1796,7 @@ remove_trans:
|
|||
|
||||
dev_err(dev, "error = %i\n", retval);
|
||||
remove_dbg:
|
||||
dbg_remove_files(&ci->gadget.dev);
|
||||
dbg_remove_files(ci->dev);
|
||||
unreg_device:
|
||||
device_unregister(&ci->gadget.dev);
|
||||
put_transceiver:
|
||||
|
|
@ -1836,7 +1836,7 @@ static void udc_stop(struct ci13xxx *ci)
|
|||
if (ci->global_phy)
|
||||
usb_put_phy(ci->transceiver);
|
||||
}
|
||||
dbg_remove_files(&ci->gadget.dev);
|
||||
dbg_remove_files(ci->dev);
|
||||
device_unregister(&ci->gadget.dev);
|
||||
/* my kobject is dynamic, I swear! */
|
||||
memset(&ci->gadget, 0, sizeof(ci->gadget));
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int __devinit usbmisc_imx6q_probe(struct platform_device *pdev)
|
||||
static int usbmisc_imx6q_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct imx6q_usbmisc *data;
|
||||
|
|
@ -98,9 +98,9 @@ static int __devinit usbmisc_imx6q_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&data->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->base = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!data->base)
|
||||
return -EADDRNOTAVAIL;
|
||||
data->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->base))
|
||||
return PTR_ERR(data->base);
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->clk)) {
|
||||
|
|
@ -127,7 +127,7 @@ static int __devinit usbmisc_imx6q_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit usbmisc_imx6q_remove(struct platform_device *pdev)
|
||||
static int usbmisc_imx6q_remove(struct platform_device *pdev)
|
||||
{
|
||||
usbmisc_unset_ops(&imx6q_usbmisc_ops);
|
||||
clk_disable_unprepare(usbmisc->clk);
|
||||
|
|
@ -136,7 +136,7 @@ static int __devexit usbmisc_imx6q_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver usbmisc_imx6q_driver = {
|
||||
.probe = usbmisc_imx6q_probe,
|
||||
.remove = __devexit_p(usbmisc_imx6q_remove),
|
||||
.remove = usbmisc_imx6q_remove,
|
||||
.driver = {
|
||||
.name = "usbmisc_imx6q",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ comment "USB Device Class drivers"
|
|||
|
||||
config USB_ACM
|
||||
tristate "USB Modem (CDC ACM) support"
|
||||
depends on USB
|
||||
depends on USB && TTY
|
||||
---help---
|
||||
This driver supports USB modems and ISDN adapters which support the
|
||||
Communication Device Class Abstract Control Model interface.
|
||||
|
|
|
|||
|
|
@ -410,19 +410,12 @@ static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags)
|
|||
|
||||
static void acm_process_read_urb(struct acm *acm, struct urb *urb)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!urb->actual_length)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&acm->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_string(&acm->port, urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
tty_flip_buffer_push(&acm->port);
|
||||
}
|
||||
|
||||
static void acm_read_bulk_callback(struct urb *urb)
|
||||
|
|
@ -787,6 +780,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
|
|||
tmp.flags = ASYNC_LOW_LATENCY;
|
||||
tmp.xmit_fifo_size = acm->writesize;
|
||||
tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
|
||||
tmp.close_delay = acm->port.close_delay / 10;
|
||||
tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
|
||||
ASYNC_CLOSING_WAIT_NONE :
|
||||
acm->port.closing_wait / 10;
|
||||
|
||||
if (copy_to_user(info, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
|
@ -794,6 +791,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_serial_info(struct acm *acm,
|
||||
struct serial_struct __user *newinfo)
|
||||
{
|
||||
struct serial_struct new_serial;
|
||||
unsigned int closing_wait, close_delay;
|
||||
int retval = 0;
|
||||
|
||||
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
|
||||
return -EFAULT;
|
||||
|
||||
close_delay = new_serial.close_delay * 10;
|
||||
closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
|
||||
ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
|
||||
|
||||
mutex_lock(&acm->port.mutex);
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((close_delay != acm->port.close_delay) ||
|
||||
(closing_wait != acm->port.closing_wait))
|
||||
retval = -EPERM;
|
||||
else
|
||||
retval = -EOPNOTSUPP;
|
||||
} else {
|
||||
acm->port.close_delay = close_delay;
|
||||
acm->port.closing_wait = closing_wait;
|
||||
}
|
||||
|
||||
mutex_unlock(&acm->port.mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int acm_tty_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
|
@ -804,6 +832,9 @@ static int acm_tty_ioctl(struct tty_struct *tty,
|
|||
case TIOCGSERIAL: /* gets serial port data */
|
||||
rv = get_serial_info(acm, (struct serial_struct __user *) arg);
|
||||
break;
|
||||
case TIOCSSERIAL:
|
||||
rv = set_serial_info(acm, (struct serial_struct __user *) arg);
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
@ -1568,6 +1599,9 @@ static const struct usb_device_id acm_ids[] = {
|
|||
{ USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
|
||||
.driver_info = NO_UNION_NORMAL,
|
||||
},
|
||||
{ USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
|
||||
.driver_info = NO_UNION_NORMAL,
|
||||
},
|
||||
{ USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
|
||||
.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
|
|||
#define WDM_RESPONDING 7
|
||||
#define WDM_SUSPENDING 8
|
||||
#define WDM_RESETTING 9
|
||||
#define WDM_OVERFLOW 10
|
||||
|
||||
#define WDM_MAX 16
|
||||
|
||||
|
|
@ -155,6 +156,7 @@ static void wdm_in_callback(struct urb *urb)
|
|||
{
|
||||
struct wdm_device *desc = urb->context;
|
||||
int status = urb->status;
|
||||
int length = urb->actual_length;
|
||||
|
||||
spin_lock(&desc->iuspin);
|
||||
clear_bit(WDM_RESPONDING, &desc->flags);
|
||||
|
|
@ -185,9 +187,17 @@ static void wdm_in_callback(struct urb *urb)
|
|||
}
|
||||
|
||||
desc->rerr = status;
|
||||
desc->reslength = urb->actual_length;
|
||||
memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
|
||||
desc->length += desc->reslength;
|
||||
if (length + desc->length > desc->wMaxCommand) {
|
||||
/* The buffer would overflow */
|
||||
set_bit(WDM_OVERFLOW, &desc->flags);
|
||||
} else {
|
||||
/* we may already be in overflow */
|
||||
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
|
||||
memmove(desc->ubuf + desc->length, desc->inbuf, length);
|
||||
desc->length += length;
|
||||
desc->reslength = length;
|
||||
}
|
||||
}
|
||||
skip_error:
|
||||
wake_up(&desc->wait);
|
||||
|
||||
|
|
@ -435,6 +445,11 @@ retry:
|
|||
rv = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
if (test_bit(WDM_OVERFLOW, &desc->flags)) {
|
||||
clear_bit(WDM_OVERFLOW, &desc->flags);
|
||||
rv = -ENOBUFS;
|
||||
goto err;
|
||||
}
|
||||
i++;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (!test_bit(WDM_READ, &desc->flags)) {
|
||||
|
|
@ -478,6 +493,7 @@ retry:
|
|||
spin_unlock_irq(&desc->iuspin);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!desc->reslength) { /* zero length read */
|
||||
dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
|
||||
clear_bit(WDM_READ, &desc->flags);
|
||||
|
|
@ -1004,6 +1020,7 @@ static int wdm_post_reset(struct usb_interface *intf)
|
|||
struct wdm_device *desc = wdm_find_device(intf);
|
||||
int rv;
|
||||
|
||||
clear_bit(WDM_OVERFLOW, &desc->flags);
|
||||
clear_bit(WDM_RESETTING, &desc->flags);
|
||||
rv = recover_from_urb_loss(desc);
|
||||
mutex_unlock(&desc->wlock);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
|||
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
|
||||
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
|
||||
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
||||
usbcore-y += port.o
|
||||
|
||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||
|
|
|
|||
|
|
@ -316,17 +316,23 @@ static char *usb_dump_iad_descriptor(char *start, char *end,
|
|||
*/
|
||||
static char *usb_dump_config_descriptor(char *start, char *end,
|
||||
const struct usb_config_descriptor *desc,
|
||||
int active)
|
||||
int active, int speed)
|
||||
{
|
||||
int mul;
|
||||
|
||||
if (start > end)
|
||||
return start;
|
||||
if (speed == USB_SPEED_SUPER)
|
||||
mul = 8;
|
||||
else
|
||||
mul = 2;
|
||||
start += sprintf(start, format_config,
|
||||
/* mark active/actual/current cfg. */
|
||||
active ? '*' : ' ',
|
||||
desc->bNumInterfaces,
|
||||
desc->bConfigurationValue,
|
||||
desc->bmAttributes,
|
||||
desc->bMaxPower * 2);
|
||||
desc->bMaxPower * mul);
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
@ -342,7 +348,8 @@ static char *usb_dump_config(int speed, char *start, char *end,
|
|||
if (!config)
|
||||
/* getting these some in 2.3.7; none in 2.3.6 */
|
||||
return start + sprintf(start, "(null Cfg. desc.)\n");
|
||||
start = usb_dump_config_descriptor(start, end, &config->desc, active);
|
||||
start = usb_dump_config_descriptor(start, end, &config->desc, active,
|
||||
speed);
|
||||
for (i = 0; i < USB_MAXIADS; i++) {
|
||||
if (config->intf_assoc[i] == NULL)
|
||||
break;
|
||||
|
|
@ -591,16 +598,14 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
|
|||
|
||||
/* Now look at all of this device's children. */
|
||||
usb_hub_for_each_child(usbdev, chix, childdev) {
|
||||
if (childdev) {
|
||||
usb_lock_device(childdev);
|
||||
ret = usb_device_dump(buffer, nbytes, skip_bytes,
|
||||
file_offset, childdev, bus,
|
||||
level + 1, chix - 1, ++cnt);
|
||||
usb_unlock_device(childdev);
|
||||
if (ret == -EFAULT)
|
||||
return total_written;
|
||||
total_written += ret;
|
||||
}
|
||||
usb_lock_device(childdev);
|
||||
ret = usb_device_dump(buffer, nbytes, skip_bytes,
|
||||
file_offset, childdev, bus,
|
||||
level + 1, chix - 1, ++cnt);
|
||||
usb_unlock_device(childdev);
|
||||
if (ret == -EFAULT)
|
||||
return total_written;
|
||||
total_written += ret;
|
||||
}
|
||||
return total_written;
|
||||
}
|
||||
|
|
@ -660,7 +665,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
|
|||
{
|
||||
loff_t ret;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_lock(&file_inode(file)->i_mutex);
|
||||
|
||||
switch (orig) {
|
||||
case 0:
|
||||
|
|
@ -676,7 +681,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&file_inode(file)->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usbdevice_fs.h>
|
||||
#include <linux/usb/hcd.h> /* for usbcore internals */
|
||||
|
|
@ -160,7 +161,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
|
|||
{
|
||||
loff_t ret;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_lock(&file_inode(file)->i_mutex);
|
||||
|
||||
switch (orig) {
|
||||
case 0:
|
||||
|
|
@ -176,7 +177,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&file_inode(file)->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1077,7 +1078,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
|
|||
if (!intf || !intf->dev.driver)
|
||||
ret = -ENODATA;
|
||||
else {
|
||||
strncpy(gd.driver, intf->dev.driver->name,
|
||||
strlcpy(gd.driver, intf->dev.driver->name,
|
||||
sizeof(gd.driver));
|
||||
ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
|
||||
}
|
||||
|
|
@ -1970,7 +1971,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
void __user *p)
|
||||
{
|
||||
struct dev_state *ps = file->private_data;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct usb_device *dev = ps->dev;
|
||||
int ret = -ENOTTY;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@
|
|||
#include "usb.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
|
||||
/*
|
||||
* Adds a new dynamic USBdevice ID to this driver,
|
||||
* and cause the driver to probe for all devices again.
|
||||
|
|
@ -194,20 +192,6 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
|
|||
}
|
||||
spin_unlock(&usb_drv->dynids.lock);
|
||||
}
|
||||
#else
|
||||
static inline int usb_create_newid_files(struct usb_driver *usb_drv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_remove_newid_files(struct usb_driver *usb_drv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void usb_free_dynids(struct usb_driver *usb_drv)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
|
||||
struct usb_driver *drv)
|
||||
|
|
@ -238,7 +222,7 @@ static int usb_probe_device(struct device *dev)
|
|||
/* TODO: Add real matching code */
|
||||
|
||||
/* The device should always appear to be in use
|
||||
* unless the driver suports autosuspend.
|
||||
* unless the driver supports autosuspend.
|
||||
*/
|
||||
if (!udriver->supports_autosuspend)
|
||||
error = usb_autoresume_device(udev);
|
||||
|
|
@ -790,7 +774,6 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_device *usb_dev;
|
||||
|
|
@ -832,14 +815,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG */
|
||||
|
||||
/**
|
||||
* usb_register_device_driver - register a USB device (not interface) driver
|
||||
* @new_udriver: USB operations for the device driver
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ int usb_choose_configuration(struct usb_device *udev)
|
|||
int insufficient_power = 0;
|
||||
struct usb_host_config *c, *best;
|
||||
|
||||
if (usb_device_is_owned(udev))
|
||||
return 0;
|
||||
|
||||
best = NULL;
|
||||
c = udev->config;
|
||||
num_configs = udev->descriptor.bNumConfigurations;
|
||||
|
|
@ -97,7 +100,7 @@ int usb_choose_configuration(struct usb_device *udev)
|
|||
*/
|
||||
|
||||
/* Rule out configs that draw too much bus current */
|
||||
if (c->desc.bMaxPower * 2 > udev->bus_mA) {
|
||||
if (usb_get_max_power(udev, c) > udev->bus_mA) {
|
||||
insufficient_power++;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -160,9 +163,7 @@ static int generic_probe(struct usb_device *udev)
|
|||
/* Choose and set the configuration. This registers the interfaces
|
||||
* with the driver core and lets interface drivers bind to them.
|
||||
*/
|
||||
if (usb_device_is_owned(udev))
|
||||
; /* Don't configure if the device is owned */
|
||||
else if (udev->authorized == 0)
|
||||
if (udev->authorized == 0)
|
||||
dev_err(&udev->dev, "Device is not authorized for usage\n");
|
||||
else {
|
||||
c = usb_choose_configuration(udev);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <asm/unaligned.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
|
@ -619,6 +620,10 @@ nongeneric:
|
|||
status = hcd->driver->hub_control (hcd,
|
||||
typeReq, wValue, wIndex,
|
||||
tbuf, wLength);
|
||||
|
||||
if (typeReq == GetHubDescriptor)
|
||||
usb_hub_adjust_deviceremovable(hcd->self.root_hub,
|
||||
(struct usb_hub_descriptor *)tbuf);
|
||||
break;
|
||||
error:
|
||||
/* "protocol stall" on error */
|
||||
|
|
@ -1025,6 +1030,49 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* usb_hcd_start_port_resume - a root-hub port is sending a resume signal
|
||||
* @bus: the bus which the root hub belongs to
|
||||
* @portnum: the port which is being resumed
|
||||
*
|
||||
* HCDs should call this function when they know that a resume signal is
|
||||
* being sent to a root-hub port. The root hub will be prevented from
|
||||
* going into autosuspend until usb_hcd_end_port_resume() is called.
|
||||
*
|
||||
* The bus's private lock must be held by the caller.
|
||||
*/
|
||||
void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
|
||||
{
|
||||
unsigned bit = 1 << portnum;
|
||||
|
||||
if (!(bus->resuming_ports & bit)) {
|
||||
bus->resuming_ports |= bit;
|
||||
pm_runtime_get_noresume(&bus->root_hub->dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
|
||||
|
||||
/*
|
||||
* usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal
|
||||
* @bus: the bus which the root hub belongs to
|
||||
* @portnum: the port which is being resumed
|
||||
*
|
||||
* HCDs should call this function when they know that a resume signal has
|
||||
* stopped being sent to a root-hub port. The root hub will be allowed to
|
||||
* autosuspend again.
|
||||
*
|
||||
* The bus's private lock must be held by the caller.
|
||||
*/
|
||||
void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
|
||||
{
|
||||
unsigned bit = 1 << portnum;
|
||||
|
||||
if (bus->resuming_ports & bit) {
|
||||
bus->resuming_ports &= ~bit;
|
||||
pm_runtime_put_noidle(&bus->root_hub->dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -2039,8 +2087,9 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
|
|||
status = hcd->driver->bus_resume(hcd);
|
||||
clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
|
||||
if (status == 0) {
|
||||
/* TRSMRCY = 10 msec */
|
||||
msleep(10);
|
||||
struct usb_device *udev;
|
||||
int port1;
|
||||
|
||||
spin_lock_irq(&hcd_root_hub_lock);
|
||||
if (!HCD_DEAD(hcd)) {
|
||||
usb_set_device_state(rhdev, rhdev->actconfig
|
||||
|
|
@ -2050,6 +2099,20 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
|
|||
hcd->state = HC_STATE_RUNNING;
|
||||
}
|
||||
spin_unlock_irq(&hcd_root_hub_lock);
|
||||
|
||||
/*
|
||||
* Check whether any of the enabled ports on the root hub are
|
||||
* unsuspended. If they are then a TRSMRCY delay is needed
|
||||
* (this is what the USB-2 spec calls a "global resume").
|
||||
* Otherwise we can skip the delay.
|
||||
*/
|
||||
usb_hub_for_each_child(rhdev, port1, udev) {
|
||||
if (udev->state != USB_STATE_NOTATTACHED &&
|
||||
!udev->port_is_suspended) {
|
||||
usleep_range(10000, 11000); /* TRSMRCY */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hcd->state = old_state;
|
||||
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
|
||||
|
|
@ -2151,8 +2214,15 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
|
|||
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
|
||||
{
|
||||
struct usb_hcd *hcd = __hcd;
|
||||
unsigned long flags;
|
||||
irqreturn_t rc;
|
||||
|
||||
/* IRQF_DISABLED doesn't work correctly with shared IRQs
|
||||
* when the first handler doesn't use it. So let's just
|
||||
* assume it's never used.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
|
||||
rc = IRQ_NONE;
|
||||
else if (hcd->driver->irq(hcd) == IRQ_NONE)
|
||||
|
|
@ -2160,6 +2230,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
|
|||
else
|
||||
rc = IRQ_HANDLED;
|
||||
|
||||
local_irq_restore(flags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_irq);
|
||||
|
|
@ -2347,6 +2418,14 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
|
|||
int retval;
|
||||
|
||||
if (hcd->driver->irq) {
|
||||
|
||||
/* IRQF_DISABLED doesn't work as advertised when used together
|
||||
* with IRQF_SHARED. As usb_hcd_irq() will always disable
|
||||
* interrupts we can remove it here.
|
||||
*/
|
||||
if (irqflags & IRQF_SHARED)
|
||||
irqflags &= ~IRQF_DISABLED;
|
||||
|
||||
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
|
||||
hcd->driver->description, hcd->self.busnum);
|
||||
retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
|
||||
|
|
@ -2475,7 +2554,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
}
|
||||
|
||||
/* starting here, usbcore will pay attention to this root hub */
|
||||
rhdev->bus_mA = min(500u, hcd->power_budget);
|
||||
if ((retval = register_root_hub(hcd)) != 0)
|
||||
goto err_register_root_hub;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
122
drivers/usb/core/hub.h
Normal file
122
drivers/usb/core/hub.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* usb hub driver head file
|
||||
*
|
||||
* Copyright (C) 1999 Linus Torvalds
|
||||
* Copyright (C) 1999 Johannes Erdfelt
|
||||
* Copyright (C) 1999 Gregory P. Smith
|
||||
* Copyright (C) 2001 Brad Hards (bhards@bigpond.net.au)
|
||||
* Copyright (C) 2012 Intel Corp (tianyu.lan@intel.com)
|
||||
*
|
||||
* move struct usb_hub to this file.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch11.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include "usb.h"
|
||||
|
||||
struct usb_hub {
|
||||
struct device *intfdev; /* the "interface" device */
|
||||
struct usb_device *hdev;
|
||||
struct kref kref;
|
||||
struct urb *urb; /* for interrupt polling pipe */
|
||||
|
||||
/* buffer for urb ... with extra space in case of babble */
|
||||
u8 (*buffer)[8];
|
||||
union {
|
||||
struct usb_hub_status hub;
|
||||
struct usb_port_status port;
|
||||
} *status; /* buffer for status reports */
|
||||
struct mutex status_mutex; /* for the status buffer */
|
||||
|
||||
int error; /* last reported error */
|
||||
int nerrors; /* track consecutive errors */
|
||||
|
||||
struct list_head event_list; /* hubs w/data or errs ready */
|
||||
unsigned long event_bits[1]; /* status change bitmask */
|
||||
unsigned long change_bits[1]; /* ports with logical connect
|
||||
status change */
|
||||
unsigned long busy_bits[1]; /* ports being reset or
|
||||
resumed */
|
||||
unsigned long removed_bits[1]; /* ports with a "removed"
|
||||
device present */
|
||||
unsigned long wakeup_bits[1]; /* ports that have signaled
|
||||
remote wakeup */
|
||||
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
|
||||
#error event_bits[] is too short!
|
||||
#endif
|
||||
|
||||
struct usb_hub_descriptor *descriptor; /* class descriptor */
|
||||
struct usb_tt tt; /* Transaction Translator */
|
||||
|
||||
unsigned mA_per_port; /* current for each child */
|
||||
|
||||
unsigned limited_power:1;
|
||||
unsigned quiescing:1;
|
||||
unsigned disconnected:1;
|
||||
|
||||
unsigned quirk_check_port_auto_suspend:1;
|
||||
|
||||
unsigned has_indicators:1;
|
||||
u8 indicator[USB_MAXCHILDREN];
|
||||
struct delayed_work leds;
|
||||
struct delayed_work init_work;
|
||||
struct usb_port **ports;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb port - kernel's representation of a usb port
|
||||
* @child: usb device attatched to the port
|
||||
* @dev: generic device interface
|
||||
* @port_owner: port's owner
|
||||
* @connect_type: port's connect type
|
||||
* @portnum: port index num based one
|
||||
* @power_is_on: port's power state
|
||||
* @did_runtime_put: port has done pm_runtime_put().
|
||||
*/
|
||||
struct usb_port {
|
||||
struct usb_device *child;
|
||||
struct device dev;
|
||||
struct dev_state *port_owner;
|
||||
enum usb_port_connect_type connect_type;
|
||||
u8 portnum;
|
||||
unsigned power_is_on:1;
|
||||
unsigned did_runtime_put:1;
|
||||
};
|
||||
|
||||
#define to_usb_port(_dev) \
|
||||
container_of(_dev, struct usb_port, dev)
|
||||
|
||||
extern int usb_hub_create_port_device(struct usb_hub *hub,
|
||||
int port1);
|
||||
extern void usb_hub_remove_port_device(struct usb_hub *hub,
|
||||
int port1);
|
||||
extern int usb_hub_set_port_power(struct usb_device *hdev,
|
||||
int port1, bool set);
|
||||
extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev);
|
||||
extern int hub_port_debounce(struct usb_hub *hub, int port1,
|
||||
bool must_be_connected);
|
||||
extern int usb_clear_port_feature(struct usb_device *hdev,
|
||||
int port1, int feature);
|
||||
|
||||
static inline int hub_port_debounce_be_connected(struct usb_hub *hub,
|
||||
int port1)
|
||||
{
|
||||
return hub_port_debounce(hub, port1, true);
|
||||
}
|
||||
|
||||
static inline int hub_port_debounce_be_stable(struct usb_hub *hub,
|
||||
int port1)
|
||||
{
|
||||
return hub_port_debounce(hub, port1, false);
|
||||
}
|
||||
|
||||
|
|
@ -1540,7 +1540,6 @@ static void usb_release_interface(struct device *dev)
|
|||
kfree(intf);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_device *usb_dev;
|
||||
|
|
@ -1575,14 +1574,6 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG */
|
||||
|
||||
struct device_type usb_if_device_type = {
|
||||
.name = "usb_interface",
|
||||
.release = usb_release_interface,
|
||||
|
|
@ -1760,7 +1751,7 @@ free_interfaces:
|
|||
}
|
||||
}
|
||||
|
||||
i = dev->bus_mA - cp->desc.bMaxPower * 2;
|
||||
i = dev->bus_mA - usb_get_max_power(dev, cp);
|
||||
if (i < 0)
|
||||
dev_warn(&dev->dev, "new config #%d exceeds power "
|
||||
"limit by %dmA\n",
|
||||
|
|
@ -1795,7 +1786,8 @@ free_interfaces:
|
|||
if (dev->actconfig && usb_disable_lpm(dev)) {
|
||||
dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto free_interfaces;
|
||||
}
|
||||
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
|
|
@ -1806,29 +1798,8 @@ free_interfaces:
|
|||
goto free_interfaces;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
/* All the old state is gone, so what else can we do?
|
||||
* The device is probably useless now anyway.
|
||||
*/
|
||||
cp = NULL;
|
||||
}
|
||||
|
||||
dev->actconfig = cp;
|
||||
if (!cp) {
|
||||
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
||||
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
||||
/* Leave LPM disabled while the device is unconfigured. */
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
usb_autosuspend_device(dev);
|
||||
goto free_interfaces;
|
||||
}
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
usb_set_device_state(dev, USB_STATE_CONFIGURED);
|
||||
|
||||
/* Initialize the new interface structures and the
|
||||
/*
|
||||
* Initialize the new interface structures and the
|
||||
* hc/hcd/usbcore interface/endpoint state.
|
||||
*/
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
|
|
@ -1872,6 +1843,35 @@ free_interfaces:
|
|||
}
|
||||
kfree(new_interfaces);
|
||||
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0 && cp) {
|
||||
/*
|
||||
* All the old state is gone, so what else can we do?
|
||||
* The device is probably useless now anyway.
|
||||
*/
|
||||
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
usb_disable_interface(dev, cp->interface[i], true);
|
||||
put_device(&cp->interface[i]->dev);
|
||||
cp->interface[i] = NULL;
|
||||
}
|
||||
cp = NULL;
|
||||
}
|
||||
|
||||
dev->actconfig = cp;
|
||||
mutex_unlock(hcd->bandwidth_mutex);
|
||||
|
||||
if (!cp) {
|
||||
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
||||
|
||||
/* Leave LPM disabled while the device is unconfigured. */
|
||||
usb_autosuspend_device(dev);
|
||||
return ret;
|
||||
}
|
||||
usb_set_device_state(dev, USB_STATE_CONFIGURED);
|
||||
|
||||
if (cp->string == NULL &&
|
||||
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
|
||||
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
|
||||
|
|
|
|||
202
drivers/usb/core/port.c
Normal file
202
drivers/usb/core/port.c
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* usb port device code
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corp
|
||||
*
|
||||
* Author: Lan Tianyu <tianyu.lan@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
#include "hub.h"
|
||||
|
||||
static const struct attribute_group *port_dev_group[];
|
||||
|
||||
static ssize_t show_port_connect_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
char *result;
|
||||
|
||||
switch (port_dev->connect_type) {
|
||||
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
|
||||
result = "hotplug";
|
||||
break;
|
||||
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
|
||||
result = "hardwired";
|
||||
break;
|
||||
case USB_PORT_NOT_USED:
|
||||
result = "not used";
|
||||
break;
|
||||
default:
|
||||
result = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", result);
|
||||
}
|
||||
static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type,
|
||||
NULL);
|
||||
|
||||
static struct attribute *port_dev_attrs[] = {
|
||||
&dev_attr_connect_type.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group port_dev_attr_grp = {
|
||||
.attrs = port_dev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *port_dev_group[] = {
|
||||
&port_dev_attr_grp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void usb_port_device_release(struct device *dev)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
|
||||
dev_pm_qos_hide_flags(dev);
|
||||
kfree(port_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
static int usb_port_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_interface *intf = to_usb_interface(dev->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
int port1 = port_dev->portnum;
|
||||
int retval;
|
||||
|
||||
if (!hub)
|
||||
return -EINVAL;
|
||||
|
||||
usb_autopm_get_interface(intf);
|
||||
set_bit(port1, hub->busy_bits);
|
||||
|
||||
retval = usb_hub_set_port_power(hdev, port1, true);
|
||||
if (port_dev->child && !retval) {
|
||||
/*
|
||||
* Wait for usb hub port to be reconnected in order to make
|
||||
* the resume procedure successful.
|
||||
*/
|
||||
retval = hub_port_debounce_be_connected(hub, port1);
|
||||
if (retval < 0) {
|
||||
dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n",
|
||||
retval);
|
||||
goto out;
|
||||
}
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
|
||||
|
||||
/* Set return value to 0 if debounce successful */
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
clear_bit(port1, hub->busy_bits);
|
||||
usb_autopm_put_interface(intf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int usb_port_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
struct usb_device *hdev = to_usb_device(dev->parent->parent);
|
||||
struct usb_interface *intf = to_usb_interface(dev->parent);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
int port1 = port_dev->portnum;
|
||||
int retval;
|
||||
|
||||
if (!hub)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)
|
||||
== PM_QOS_FLAGS_ALL)
|
||||
return -EAGAIN;
|
||||
|
||||
usb_autopm_get_interface(intf);
|
||||
set_bit(port1, hub->busy_bits);
|
||||
retval = usb_hub_set_port_power(hdev, port1, false);
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
|
||||
usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
|
||||
clear_bit(port1, hub->busy_bits);
|
||||
usb_autopm_put_interface(intf);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops usb_port_pm_ops = {
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
.runtime_suspend = usb_port_runtime_suspend,
|
||||
.runtime_resume = usb_port_runtime_resume,
|
||||
.runtime_idle = pm_generic_runtime_idle,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct device_type usb_port_device_type = {
|
||||
.name = "usb_port",
|
||||
.release = usb_port_device_release,
|
||||
.pm = &usb_port_pm_ops,
|
||||
};
|
||||
|
||||
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
|
||||
{
|
||||
struct usb_port *port_dev = NULL;
|
||||
int retval;
|
||||
|
||||
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
|
||||
if (!port_dev) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hub->ports[port1 - 1] = port_dev;
|
||||
port_dev->portnum = port1;
|
||||
port_dev->power_is_on = true;
|
||||
port_dev->dev.parent = hub->intfdev;
|
||||
port_dev->dev.groups = port_dev_group;
|
||||
port_dev->dev.type = &usb_port_device_type;
|
||||
dev_set_name(&port_dev->dev, "port%d", port1);
|
||||
|
||||
retval = device_register(&port_dev->dev);
|
||||
if (retval)
|
||||
goto error_register;
|
||||
|
||||
pm_runtime_set_active(&port_dev->dev);
|
||||
|
||||
/* It would be dangerous if user space couldn't
|
||||
* prevent usb device from being powered off. So don't
|
||||
* enable port runtime pm if failed to expose port's pm qos.
|
||||
*/
|
||||
if (!dev_pm_qos_expose_flags(&port_dev->dev,
|
||||
PM_QOS_FLAG_NO_POWER_OFF))
|
||||
pm_runtime_enable(&port_dev->dev);
|
||||
|
||||
device_enable_async_suspend(&port_dev->dev);
|
||||
return 0;
|
||||
|
||||
error_register:
|
||||
put_device(&port_dev->dev);
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
void usb_hub_remove_port_device(struct usb_hub *hub,
|
||||
int port1)
|
||||
{
|
||||
device_unregister(&hub->ports[port1 - 1]->dev);
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
/* Creative SB Audigy 2 NX */
|
||||
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* Microsoft LifeCam-VX700 v2.0 */
|
||||
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
/* Logitech Quickcam Fusion */
|
||||
{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include "usb.h"
|
||||
|
||||
/* Active configuration fields */
|
||||
#define usb_actconfig_show(field, multiplier, format_string) \
|
||||
#define usb_actconfig_show(field, format_string) \
|
||||
static ssize_t show_##field(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
|
|
@ -28,18 +28,31 @@ static ssize_t show_##field(struct device *dev, \
|
|||
actconfig = udev->actconfig; \
|
||||
if (actconfig) \
|
||||
return sprintf(buf, format_string, \
|
||||
actconfig->desc.field * multiplier); \
|
||||
actconfig->desc.field); \
|
||||
else \
|
||||
return 0; \
|
||||
} \
|
||||
|
||||
#define usb_actconfig_attr(field, multiplier, format_string) \
|
||||
usb_actconfig_show(field, multiplier, format_string) \
|
||||
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
|
||||
#define usb_actconfig_attr(field, format_string) \
|
||||
usb_actconfig_show(field, format_string) \
|
||||
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
|
||||
|
||||
usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
|
||||
usb_actconfig_attr(bmAttributes, 1, "%2x\n")
|
||||
usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
|
||||
usb_actconfig_attr(bNumInterfaces, "%2d\n")
|
||||
usb_actconfig_attr(bmAttributes, "%2x\n")
|
||||
|
||||
static ssize_t show_bMaxPower(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
struct usb_host_config *actconfig;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
actconfig = udev->actconfig;
|
||||
if (!actconfig)
|
||||
return 0;
|
||||
return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
|
||||
}
|
||||
static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL);
|
||||
|
||||
static ssize_t show_configuration_string(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
|
@ -56,7 +69,7 @@ static ssize_t show_configuration_string(struct device *dev,
|
|||
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
|
||||
|
||||
/* configuration value is always present, and r/w */
|
||||
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
|
||||
usb_actconfig_show(bConfigurationValue, "%u\n");
|
||||
|
||||
static ssize_t
|
||||
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
|
||||
|
|
|
|||
|
|
@ -214,9 +214,25 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
|
|||
* urb->interval is modified to reflect the actual transfer period used
|
||||
* (normally some power of two units). And for isochronous urbs,
|
||||
* urb->start_frame is modified to reflect when the URB's transfers were
|
||||
* scheduled to start. Not all isochronous transfer scheduling policies
|
||||
* will work, but most host controller drivers should easily handle ISO
|
||||
* queues going from now until 10-200 msec into the future.
|
||||
* scheduled to start.
|
||||
*
|
||||
* Not all isochronous transfer scheduling policies will work, but most
|
||||
* host controller drivers should easily handle ISO queues going from now
|
||||
* until 10-200 msec into the future. Drivers should try to keep at
|
||||
* least one or two msec of data in the queue; many controllers require
|
||||
* that new transfers start at least 1 msec in the future when they are
|
||||
* added. If the driver is unable to keep up and the queue empties out,
|
||||
* the behavior for new submissions is governed by the URB_ISO_ASAP flag.
|
||||
* If the flag is set, or if the queue is idle, then the URB is always
|
||||
* assigned to the first available (and not yet expired) slot in the
|
||||
* endpoint's schedule. If the flag is not set and the queue is active
|
||||
* then the URB is always assigned to the next slot in the schedule
|
||||
* following the end of the endpoint's previous URB, even if that slot is
|
||||
* in the past. When a packet is assigned in this way to a slot that has
|
||||
* already expired, the packet is not transmitted and the corresponding
|
||||
* usb_iso_packet_descriptor's status field will return -EXDEV. If this
|
||||
* would happen to all the packets in the URB, submission fails with a
|
||||
* -EXDEV error code.
|
||||
*
|
||||
* For control endpoints, the synchronous usb_control_msg() call is
|
||||
* often used (in non-interrupt context) instead of this call.
|
||||
|
|
@ -305,8 +321,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
struct usb_host_endpoint *ep;
|
||||
int is_out;
|
||||
|
||||
if (!urb || urb->hcpriv || !urb->complete)
|
||||
if (!urb || !urb->complete)
|
||||
return -EINVAL;
|
||||
if (urb->hcpriv) {
|
||||
WARN_ONCE(1, "URB %p submitted while active\n", urb);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev = urb->dev;
|
||||
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -210,9 +210,14 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool usb_acpi_bus_match(struct device *dev)
|
||||
{
|
||||
return is_usb_device(dev) || is_usb_port(dev);
|
||||
}
|
||||
|
||||
static struct acpi_bus_type usb_acpi_bus = {
|
||||
.bus = &usb_bus_type,
|
||||
.find_bridge = usb_acpi_find_device,
|
||||
.name = "USB",
|
||||
.match = usb_acpi_bus_match,
|
||||
.find_device = usb_acpi_find_device,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -233,7 +233,6 @@ static void usb_release_dev(struct device *dev)
|
|||
kfree(udev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_device *usb_dev;
|
||||
|
|
@ -249,14 +248,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* USB device Power-Management thunks.
|
||||
|
|
@ -370,14 +361,14 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||
struct usb_bus *bus, unsigned port1)
|
||||
{
|
||||
struct usb_device *dev;
|
||||
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
|
||||
struct usb_hcd *usb_hcd = bus_to_hcd(bus);
|
||||
unsigned root_hub = 0;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
if (!usb_get_hcd(bus_to_hcd(bus))) {
|
||||
if (!usb_get_hcd(usb_hcd)) {
|
||||
kfree(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
struct usb_hub_descriptor;
|
||||
struct dev_state;
|
||||
|
||||
/* Functions local to drivers/usb/core/ */
|
||||
|
|
@ -38,6 +39,15 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
|
|||
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
||||
extern int usb_choose_configuration(struct usb_device *udev);
|
||||
|
||||
static inline unsigned usb_get_max_power(struct usb_device *udev,
|
||||
struct usb_host_config *c)
|
||||
{
|
||||
/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
|
||||
unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
|
||||
|
||||
return c->desc.bMaxPower * mul;
|
||||
}
|
||||
|
||||
extern void usb_kick_khubd(struct usb_device *dev);
|
||||
extern int usb_match_one_id_intf(struct usb_device *dev,
|
||||
struct usb_host_interface *intf,
|
||||
|
|
@ -173,6 +183,8 @@ extern enum usb_port_connect_type
|
|||
usb_get_hub_port_connect_type(struct usb_device *hdev, int port1);
|
||||
extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
|
||||
enum usb_port_connect_type type);
|
||||
extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,
|
||||
struct usb_hub_descriptor *desc);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
extern int usb_acpi_register(void);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
config USB_DWC3
|
||||
tristate "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB && USB_GADGET)
|
||||
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
|
||||
select USB_OTG_UTILS
|
||||
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
|
||||
help
|
||||
|
|
@ -12,6 +12,35 @@ config USB_DWC3
|
|||
|
||||
if USB_DWC3
|
||||
|
||||
choice
|
||||
bool "DWC3 Mode Selection"
|
||||
default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
|
||||
default USB_DWC3_HOST if (USB && !USB_GADGET)
|
||||
default USB_DWC3_GADGET if (!USB && USB_GADGET)
|
||||
|
||||
config USB_DWC3_HOST
|
||||
bool "Host only mode"
|
||||
depends on USB
|
||||
help
|
||||
Select this when you want to use DWC3 in host mode only,
|
||||
thereby the gadget feature will be regressed.
|
||||
|
||||
config USB_DWC3_GADGET
|
||||
bool "Gadget only mode"
|
||||
depends on USB_GADGET
|
||||
help
|
||||
Select this when you want to use DWC3 in gadget mode only,
|
||||
thereby the host feature will be regressed.
|
||||
|
||||
config USB_DWC3_DUAL_ROLE
|
||||
bool "Dual Role mode"
|
||||
depends on (USB && USB_GADGET)
|
||||
help
|
||||
This is the default mode of working of DWC3 controller where
|
||||
both host and gadget features are enabled.
|
||||
|
||||
endchoice
|
||||
|
||||
config USB_DWC3_DEBUG
|
||||
bool "Enable Debugging Messages"
|
||||
help
|
||||
|
|
|
|||
|
|
@ -4,8 +4,14 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
|
|||
obj-$(CONFIG_USB_DWC3) += dwc3.o
|
||||
|
||||
dwc3-y := core.o
|
||||
dwc3-y += host.o
|
||||
dwc3-y += gadget.o ep0.o
|
||||
|
||||
ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
|
||||
dwc3-y += host.o
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
|
||||
dwc3-y += gadget.o ep0.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_DEBUG_FS),)
|
||||
dwc3-y += debugfs.o
|
||||
|
|
@ -27,19 +33,7 @@ endif
|
|||
##
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
|
||||
|
||||
##
|
||||
# REVISIT Samsung Exynos platform needs the clk API which isn't
|
||||
# defined on all architectures. If we allow dwc3-exynos.c compile
|
||||
# always we will fail the linking phase on those architectures
|
||||
# which don't provide clk api implementation and that's unnaceptable.
|
||||
#
|
||||
# When Samsung's platform start supporting pm_runtime, this check
|
||||
# for HAVE_CLK should be removed.
|
||||
##
|
||||
ifneq ($(CONFIG_HAVE_CLK),)
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
|
||||
endif
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
|
||||
|
||||
ifneq ($(CONFIG_PCI),)
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
|
||||
|
|
|
|||
|
|
@ -66,45 +66,6 @@ MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
|
|||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define DWC3_DEVS_POSSIBLE 32
|
||||
|
||||
static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
|
||||
|
||||
int dwc3_get_device_id(void)
|
||||
{
|
||||
int id;
|
||||
|
||||
again:
|
||||
id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE);
|
||||
if (id < DWC3_DEVS_POSSIBLE) {
|
||||
int old;
|
||||
|
||||
old = test_and_set_bit(id, dwc3_devs);
|
||||
if (old)
|
||||
goto again;
|
||||
} else {
|
||||
pr_err("dwc3: no space for new device\n");
|
||||
id = -ENOMEM;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc3_get_device_id);
|
||||
|
||||
void dwc3_put_device_id(int id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
ret = test_bit(id, dwc3_devs);
|
||||
WARN(!ret, "dwc3: ID %d not in use\n", id);
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(id, dwc3_devs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc3_put_device_id);
|
||||
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
{
|
||||
u32 reg;
|
||||
|
|
@ -169,7 +130,6 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
|
|||
struct dwc3_event_buffer *evt)
|
||||
{
|
||||
dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
|
||||
kfree(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -180,12 +140,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
|
|||
* Returns a pointer to the allocated event buffer structure on success
|
||||
* otherwise ERR_PTR(errno).
|
||||
*/
|
||||
static struct dwc3_event_buffer *__devinit
|
||||
dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
|
||||
static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
|
||||
evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL);
|
||||
if (!evt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -193,10 +152,8 @@ dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
|
|||
evt->length = length;
|
||||
evt->buf = dma_alloc_coherent(dwc->dev, length,
|
||||
&evt->dma, GFP_KERNEL);
|
||||
if (!evt->buf) {
|
||||
kfree(evt);
|
||||
if (!evt->buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
|
@ -215,8 +172,6 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
|||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
|
||||
kfree(dwc->ev_buffs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -227,7 +182,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
|||
* Returns 0 on success otherwise negative errno. In the error case, dwc
|
||||
* may contain some buffers allocated but not all which were requested.
|
||||
*/
|
||||
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
int num;
|
||||
int i;
|
||||
|
|
@ -235,7 +190,8 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
|||
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
|
||||
dwc->num_event_buffers = num;
|
||||
|
||||
dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL);
|
||||
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
|
||||
GFP_KERNEL);
|
||||
if (!dwc->ev_buffs) {
|
||||
dev_err(dwc->dev, "can't allocate event buffers array\n");
|
||||
return -ENOMEM;
|
||||
|
|
@ -303,7 +259,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
|||
}
|
||||
}
|
||||
|
||||
static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
||||
|
|
@ -324,7 +280,7 @@ static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
|
|||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
||||
static int dwc3_core_init(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 reg;
|
||||
|
|
@ -358,8 +314,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
|||
|
||||
dwc3_core_soft_reset(dwc);
|
||||
|
||||
dwc3_cache_hwparams(dwc);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
||||
reg &= ~DWC3_GCTL_DISSCRAMBLE;
|
||||
|
|
@ -383,24 +337,14 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
|||
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to allocate event buffers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -408,16 +352,14 @@ err0:
|
|||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
|
||||
}
|
||||
|
||||
#define DWC3_ALIGN_MASK (16 - 1)
|
||||
|
||||
static int __devinit dwc3_probe(struct platform_device *pdev)
|
||||
static int dwc3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct resource *res;
|
||||
|
|
@ -478,18 +420,27 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
if (node) {
|
||||
dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
|
||||
dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
|
||||
} else {
|
||||
dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
|
||||
dev_err(dev, "no usb2 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
|
||||
if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
|
||||
dev_err(dev, "no usb3 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
|
||||
spin_lock_init(&dwc->lock);
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
|
||||
|
|
@ -508,17 +459,25 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
|
|||
else
|
||||
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
|
||||
|
||||
if (of_get_property(node, "tx-fifo-resize", NULL))
|
||||
dwc->needs_fifo_resize = true;
|
||||
dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
pm_runtime_forbid(dev);
|
||||
|
||||
dwc3_cache_hwparams(dwc);
|
||||
|
||||
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to allocate event buffers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize core\n");
|
||||
return ret;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
mode = DWC3_MODE(dwc->hwparams.hwparams0);
|
||||
|
|
@ -590,15 +549,18 @@ err2:
|
|||
err1:
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
err0:
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dwc3_remove(struct platform_device *pdev)
|
||||
static int dwc3_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3 *dwc = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
@ -621,16 +583,28 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
|
|||
break;
|
||||
}
|
||||
|
||||
dwc3_free_event_buffers(dwc);
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id of_dwc3_match[] = {
|
||||
{
|
||||
.compatible = "synopsys,dwc3"
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver dwc3_driver = {
|
||||
.probe = dwc3_probe,
|
||||
.remove = __devexit_p(dwc3_remove),
|
||||
.remove = dwc3_remove,
|
||||
.driver = {
|
||||
.name = "dwc3",
|
||||
.of_match_table = of_match_ptr(of_dwc3_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@
|
|||
#define DWC3_ENDPOINTS_NUM 32
|
||||
#define DWC3_XHCI_RESOURCES_NUM 2
|
||||
|
||||
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
|
||||
#define DWC3_EVENT_SIZE 4 /* bytes */
|
||||
#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */
|
||||
#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
|
||||
#define DWC3_EVENT_TYPE_MASK 0xfe
|
||||
|
||||
#define DWC3_EVENT_TYPE_DEV 0
|
||||
|
|
@ -405,7 +407,6 @@ struct dwc3_event_buffer {
|
|||
* @number: endpoint number (1 - 15)
|
||||
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
||||
* @resource_index: Resource transfer index
|
||||
* @current_uf: Current uf received through last event parameter
|
||||
* @interval: the intervall on which the ISOC transfer is started
|
||||
* @name: a human readable name e.g. ep1out-bulk
|
||||
* @direction: true for TX, false for RX
|
||||
|
|
@ -439,7 +440,6 @@ struct dwc3_ep {
|
|||
u8 number;
|
||||
u8 type;
|
||||
u8 resource_index;
|
||||
u16 current_uf;
|
||||
u32 interval;
|
||||
|
||||
char name[20];
|
||||
|
|
@ -581,6 +581,7 @@ struct dwc3_request {
|
|||
struct usb_request request;
|
||||
struct list_head list;
|
||||
struct dwc3_ep *dep;
|
||||
u32 start_slot;
|
||||
|
||||
u8 epnum;
|
||||
struct dwc3_trb *trb;
|
||||
|
|
@ -721,6 +722,7 @@ struct dwc3 {
|
|||
|
||||
struct dwc3_hwparams hwparams;
|
||||
struct dentry *root;
|
||||
struct debugfs_regset32 *regset;
|
||||
|
||||
u8 test_mode;
|
||||
u8 test_mode_nr;
|
||||
|
|
@ -862,13 +864,24 @@ union dwc3_event {
|
|||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_host_init(struct dwc3 *dwc);
|
||||
void dwc3_host_exit(struct dwc3 *dwc);
|
||||
#else
|
||||
static inline int dwc3_host_init(struct dwc3 *dwc)
|
||||
{ return 0; }
|
||||
static inline void dwc3_host_exit(struct dwc3 *dwc)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_gadget_init(struct dwc3 *dwc);
|
||||
void dwc3_gadget_exit(struct dwc3 *dwc);
|
||||
|
||||
extern int dwc3_get_device_id(void);
|
||||
extern void dwc3_put_device_id(int id);
|
||||
#else
|
||||
static inline int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
{ return 0; }
|
||||
static inline void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
#endif /* __DRIVERS_USB_DWC3_CORE_H */
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@
|
|||
#define dump_register(nm) \
|
||||
{ \
|
||||
.name = __stringify(nm), \
|
||||
.offset = DWC3_ ##nm, \
|
||||
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
|
||||
}
|
||||
|
||||
static const struct debugfs_reg32 dwc3_regs[] = {
|
||||
static struct debugfs_reg32 dwc3_regs[] = {
|
||||
dump_register(GSBUSCFG0),
|
||||
dump_register(GSBUSCFG1),
|
||||
dump_register(GTXTHRCFG),
|
||||
|
|
@ -376,27 +376,6 @@ static const struct debugfs_reg32 dwc3_regs[] = {
|
|||
dump_register(OSTS),
|
||||
};
|
||||
|
||||
static int dwc3_regdump_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3 *dwc = s->private;
|
||||
|
||||
seq_printf(s, "DesignWare USB3 Core Register Dump\n");
|
||||
debugfs_print_regs32(s, dwc3_regs, ARRAY_SIZE(dwc3_regs),
|
||||
dwc->regs, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_regdump_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dwc3_regdump_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_regdump_fops = {
|
||||
.open = dwc3_regdump_open,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int dwc3_mode_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3 *dwc = s->private;
|
||||
|
|
@ -652,7 +631,7 @@ static const struct file_operations dwc3_link_state_fops = {
|
|||
.release = single_release,
|
||||
};
|
||||
|
||||
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
int dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
|
@ -666,13 +645,23 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
|||
|
||||
dwc->root = root;
|
||||
|
||||
file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
|
||||
&dwc3_regdump_fops);
|
||||
dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
|
||||
if (!dwc->regset) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc->regset->regs = dwc3_regs;
|
||||
dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
|
||||
dwc->regset->base = dwc->regs;
|
||||
|
||||
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
|
||||
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_mode_fops);
|
||||
if (!file) {
|
||||
|
|
@ -693,6 +682,7 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
|||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -703,7 +693,7 @@ err0:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
|
||||
void dwc3_debugfs_exit(struct dwc3 *dwc)
|
||||
{
|
||||
debugfs_remove_recursive(dwc->root);
|
||||
dwc->root = NULL;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/nop-usb-xceiv.h>
|
||||
|
||||
#include "core.h"
|
||||
#include <linux/of.h>
|
||||
|
||||
struct dwc3_exynos {
|
||||
struct platform_device *dwc3;
|
||||
|
|
@ -33,7 +32,7 @@ struct dwc3_exynos {
|
|||
struct clk *clk;
|
||||
};
|
||||
|
||||
static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
|
||||
static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
|
||||
{
|
||||
struct nop_usb_xceiv_platform_data pdata;
|
||||
struct platform_device *pdev;
|
||||
|
|
@ -41,7 +40,7 @@ static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
|
|||
|
||||
memset(&pdata, 0x00, sizeof(pdata));
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", 0);
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -52,7 +51,7 @@ static int __devinit dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
|
|||
if (ret)
|
||||
goto err1;
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", 1);
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
|
|
@ -87,124 +86,113 @@ err1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
|
||||
static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static int dwc3_exynos_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_exynos *exynos;
|
||||
struct clk *clk;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
int devid;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
|
||||
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
|
||||
if (!exynos) {
|
||||
dev_err(&pdev->dev, "not enough memory\n");
|
||||
goto err0;
|
||||
dev_err(dev, "not enough memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Right now device-tree probed devices don't get dma_mask set.
|
||||
* Since shared usb code relies on it, set it here for now.
|
||||
* Once we move to full device tree support this will vanish off.
|
||||
*/
|
||||
if (!pdev->dev.dma_mask)
|
||||
pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
|
||||
|
||||
platform_set_drvdata(pdev, exynos);
|
||||
|
||||
devid = dwc3_get_device_id();
|
||||
if (devid < 0)
|
||||
goto err1;
|
||||
|
||||
ret = dwc3_exynos_register_phys(exynos);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't register PHYs\n");
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
|
||||
if (!dwc3) {
|
||||
dev_err(dev, "couldn't allocate dwc3 device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, "usbdrd30");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "couldn't get clock\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3", devid);
|
||||
if (!dwc3) {
|
||||
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
|
||||
goto err2;
|
||||
}
|
||||
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
|
||||
|
||||
clk = clk_get(&pdev->dev, "usbdrd30");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "couldn't get clock\n");
|
||||
ret = -EINVAL;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
|
||||
|
||||
dwc3->dev.parent = &pdev->dev;
|
||||
dwc3->dev.dma_mask = pdev->dev.dma_mask;
|
||||
dwc3->dev.dma_parms = pdev->dev.dma_parms;
|
||||
dwc3->dev.parent = dev;
|
||||
dwc3->dev.dma_mask = dev->dma_mask;
|
||||
dwc3->dev.dma_parms = dev->dma_parms;
|
||||
exynos->dwc3 = dwc3;
|
||||
exynos->dev = &pdev->dev;
|
||||
exynos->dev = dev;
|
||||
exynos->clk = clk;
|
||||
|
||||
clk_enable(exynos->clk);
|
||||
|
||||
/* PHY initialization */
|
||||
if (!pdata) {
|
||||
dev_dbg(&pdev->dev, "missing platform data\n");
|
||||
} else {
|
||||
if (pdata->phy_init)
|
||||
pdata->phy_init(pdev, pdata->phy_type);
|
||||
}
|
||||
|
||||
ret = platform_device_add_resources(dwc3, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err4;
|
||||
dev_err(dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register dwc3 device\n");
|
||||
goto err4;
|
||||
dev_err(dev, "failed to register dwc3 device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, pdata->phy_type);
|
||||
|
||||
clk_disable(clk);
|
||||
clk_put(clk);
|
||||
err3:
|
||||
platform_device_put(dwc3);
|
||||
err2:
|
||||
dwc3_put_device_id(devid);
|
||||
clk_disable(clk);
|
||||
err1:
|
||||
kfree(exynos);
|
||||
err0:
|
||||
platform_device_put(dwc3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
|
||||
static int dwc3_exynos_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
|
||||
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
platform_device_unregister(exynos->dwc3);
|
||||
platform_device_unregister(exynos->usb2_phy);
|
||||
platform_device_unregister(exynos->usb3_phy);
|
||||
|
||||
dwc3_put_device_id(exynos->dwc3->id);
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, pdata->phy_type);
|
||||
|
||||
clk_disable(exynos->clk);
|
||||
clk_put(exynos->clk);
|
||||
|
||||
kfree(exynos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id exynos_dwc3_match[] = {
|
||||
{ .compatible = "samsung,exynos5250-dwusb3" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver dwc3_exynos_driver = {
|
||||
.probe = dwc3_exynos_probe,
|
||||
.remove = __devexit_p(dwc3_exynos_remove),
|
||||
.remove = dwc3_exynos_remove,
|
||||
.driver = {
|
||||
.name = "exynos-dwc3",
|
||||
.of_match_table = of_match_ptr(exynos_dwc3_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -43,16 +43,17 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dwc3-omap.h>
|
||||
#include <linux/usb/dwc3-omap.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/nop-usb-xceiv.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* All these registers belong to OMAP's Wrapper around the
|
||||
* DesignWare USB3 Core.
|
||||
|
|
@ -78,23 +79,6 @@
|
|||
|
||||
/* SYSCONFIG REGISTER */
|
||||
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
|
||||
#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
|
||||
|
||||
#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0
|
||||
#define USBOTGSS_STANDBYMODE_NO_STANDBY 1
|
||||
#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2
|
||||
#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3
|
||||
|
||||
#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4)
|
||||
|
||||
#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
|
||||
|
||||
#define USBOTGSS_IDLEMODE_FORCE_IDLE 0
|
||||
#define USBOTGSS_IDLEMODE_NO_IDLE 1
|
||||
#define USBOTGSS_IDLEMODE_SMART_IDLE 2
|
||||
#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3
|
||||
|
||||
#define USBOTGSS_IDLEMODE_MASK (0x03 << 2)
|
||||
|
||||
/* IRQ_EOI REGISTER */
|
||||
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
|
||||
|
|
@ -133,7 +117,6 @@ struct dwc3_omap {
|
|||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
struct platform_device *dwc3;
|
||||
struct platform_device *usb2_phy;
|
||||
struct platform_device *usb3_phy;
|
||||
struct device *dev;
|
||||
|
|
@ -147,6 +130,8 @@ struct dwc3_omap {
|
|||
u32 dma_status:1;
|
||||
};
|
||||
|
||||
struct dwc3_omap *_omap;
|
||||
|
||||
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
|
|
@ -157,7 +142,58 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
|
|||
writel(value, base + offset);
|
||||
}
|
||||
|
||||
static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
|
||||
void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
|
||||
{
|
||||
u32 val;
|
||||
struct dwc3_omap *omap = _omap;
|
||||
|
||||
switch (status) {
|
||||
case OMAP_DWC3_ID_GROUND:
|
||||
dev_dbg(omap->dev, "ID GND\n");
|
||||
|
||||
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
|
||||
val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
|
||||
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_SESSEND);
|
||||
val |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
|
||||
break;
|
||||
|
||||
case OMAP_DWC3_VBUS_VALID:
|
||||
dev_dbg(omap->dev, "VBUS Connect\n");
|
||||
|
||||
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
|
||||
val &= ~USBOTGSS_UTMI_OTG_STATUS_SESSEND;
|
||||
val |= USBOTGSS_UTMI_OTG_STATUS_IDDIG
|
||||
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_SESSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
|
||||
break;
|
||||
|
||||
case OMAP_DWC3_ID_FLOAT:
|
||||
case OMAP_DWC3_VBUS_OFF:
|
||||
dev_dbg(omap->dev, "VBUS Disconnect\n");
|
||||
|
||||
val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
|
||||
val &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
|
||||
| USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT);
|
||||
val |= USBOTGSS_UTMI_OTG_STATUS_SESSEND
|
||||
| USBOTGSS_UTMI_OTG_STATUS_IDDIG;
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_dbg(omap->dev, "ID float\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
|
||||
|
||||
static int dwc3_omap_register_phys(struct dwc3_omap *omap)
|
||||
{
|
||||
struct nop_usb_xceiv_platform_data pdata;
|
||||
struct platform_device *pdev;
|
||||
|
|
@ -165,7 +201,7 @@ static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
|
|||
|
||||
memset(&pdata, 0x00, sizeof(pdata));
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", 0);
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -176,7 +212,7 @@ static int __devinit dwc3_omap_register_phys(struct dwc3_omap *omap)
|
|||
if (ret)
|
||||
goto err1;
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", 1);
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
|
|
@ -262,17 +298,24 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit dwc3_omap_probe(struct platform_device *pdev)
|
||||
static int dwc3_omap_remove_core(struct device *dev, void *c)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_omap *omap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
int devid;
|
||||
int size;
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
|
|
@ -315,34 +358,32 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
devid = dwc3_get_device_id();
|
||||
if (devid < 0)
|
||||
return -ENODEV;
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3", devid);
|
||||
if (!dwc3) {
|
||||
dev_err(dev, "couldn't allocate dwc3 device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
|
||||
if (!context) {
|
||||
dev_err(dev, "couldn't allocate dwc3 context memory\n");
|
||||
goto err2;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
|
||||
|
||||
dwc3->dev.parent = dev;
|
||||
dwc3->dev.dma_mask = dev->dma_mask;
|
||||
dwc3->dev.dma_parms = dev->dma_parms;
|
||||
omap->resource_size = resource_size(res);
|
||||
omap->context = context;
|
||||
omap->dev = dev;
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
omap->dwc3 = dwc3;
|
||||
|
||||
/*
|
||||
* REVISIT if we ever have two instances of the wrapper, we will be
|
||||
* in big trouble
|
||||
*/
|
||||
_omap = omap;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "get_sync failed with err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
|
||||
|
||||
|
|
@ -373,21 +414,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
|
|||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
/* Set No-Idle and No-Standby */
|
||||
reg &= ~(USBOTGSS_STANDBYMODE_MASK
|
||||
| USBOTGSS_IDLEMODE_MASK);
|
||||
|
||||
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
|
||||
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
|
||||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
|
||||
|
||||
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
|
||||
"dwc3-omap", omap);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request IRQ #%d --> %d\n",
|
||||
omap->irq, ret);
|
||||
goto err2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable all IRQs */
|
||||
|
|
@ -406,57 +438,45 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
|
|||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
|
||||
|
||||
ret = platform_device_add_resources(dwc3, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 device\n");
|
||||
goto err2;
|
||||
if (node) {
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to add create dwc3 core\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
platform_device_put(dwc3);
|
||||
|
||||
err1:
|
||||
dwc3_put_device_id(devid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dwc3_omap_remove(struct platform_device *pdev)
|
||||
static int dwc3_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_omap *omap = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(omap->dwc3);
|
||||
platform_device_unregister(omap->usb2_phy);
|
||||
platform_device_unregister(omap->usb3_phy);
|
||||
|
||||
dwc3_put_device_id(omap->dwc3->id);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_dwc3_matach[] = {
|
||||
static const struct of_device_id of_dwc3_match[] = {
|
||||
{
|
||||
"ti,dwc3",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_matach);
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_match);
|
||||
|
||||
static struct platform_driver dwc3_omap_driver = {
|
||||
.probe = dwc3_omap_probe,
|
||||
.remove = __devexit_p(dwc3_omap_remove),
|
||||
.remove = dwc3_omap_remove,
|
||||
.driver = {
|
||||
.name = "omap-dwc3",
|
||||
.of_match_table = of_dwc3_matach,
|
||||
.of_match_table = of_dwc3_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@
|
|||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/nop-usb-xceiv.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* FIXME define these in <linux/pci_ids.h> */
|
||||
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||
|
|
@ -58,7 +56,7 @@ struct dwc3_pci {
|
|||
struct platform_device *usb3_phy;
|
||||
};
|
||||
|
||||
static int __devinit dwc3_pci_register_phys(struct dwc3_pci *glue)
|
||||
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
|
||||
{
|
||||
struct nop_usb_xceiv_platform_data pdata;
|
||||
struct platform_device *pdev;
|
||||
|
|
@ -112,14 +110,13 @@ err1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit dwc3_pci_probe(struct pci_dev *pci,
|
||||
static int dwc3_pci_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct resource res[2];
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_pci *glue;
|
||||
int ret = -ENOMEM;
|
||||
int devid;
|
||||
struct device *dev = &pci->dev;
|
||||
|
||||
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
|
||||
|
|
@ -145,13 +142,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
|
|||
return ret;
|
||||
}
|
||||
|
||||
devid = dwc3_get_device_id();
|
||||
if (devid < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3", devid);
|
||||
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
|
||||
if (!dwc3) {
|
||||
dev_err(dev, "couldn't allocate dwc3 device\n");
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -172,7 +163,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
|
|||
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err2;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, glue);
|
||||
|
|
@ -195,23 +186,18 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
|
|||
err3:
|
||||
pci_set_drvdata(pci, NULL);
|
||||
platform_device_put(dwc3);
|
||||
|
||||
err2:
|
||||
dwc3_put_device_id(devid);
|
||||
|
||||
err1:
|
||||
pci_disable_device(pci);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit dwc3_pci_remove(struct pci_dev *pci)
|
||||
static void dwc3_pci_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct dwc3_pci *glue = pci_get_drvdata(pci);
|
||||
|
||||
platform_device_unregister(glue->usb2_phy);
|
||||
platform_device_unregister(glue->usb3_phy);
|
||||
dwc3_put_device_id(glue->dwc3->id);
|
||||
platform_device_unregister(glue->dwc3);
|
||||
pci_set_drvdata(pci, NULL);
|
||||
pci_disable_device(pci);
|
||||
|
|
@ -230,7 +216,7 @@ static struct pci_driver dwc3_pci_driver = {
|
|||
.name = "dwc3-pci",
|
||||
.id_table = dwc3_pci_id_table,
|
||||
.probe = dwc3_pci_probe,
|
||||
.remove = __devexit_p(dwc3_pci_remove),
|
||||
.remove = dwc3_pci_remove,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -891,7 +891,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size;
|
||||
u32 transfer_size;
|
||||
u32 maxpacket;
|
||||
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
dep->number);
|
||||
|
|
@ -902,8 +903,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||
|
||||
WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
|
||||
|
||||
transfer_size = roundup(req->request.length,
|
||||
(u32) dep->endpoint.maxpacket);
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
transfer_size = roundup(req->request.length, maxpacket);
|
||||
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -241,21 +241,23 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||
int status)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int i;
|
||||
|
||||
if (req->queued) {
|
||||
if (req->request.num_mapped_sgs)
|
||||
dep->busy_slot += req->request.num_mapped_sgs;
|
||||
else
|
||||
i = 0;
|
||||
do {
|
||||
dep->busy_slot++;
|
||||
|
||||
/*
|
||||
* Skip LINK TRB. We can't use req->trb and check for
|
||||
* DWC3_TRBCTL_LINK_TRB because it points the TRB we just
|
||||
* completed (not the LINK TRB).
|
||||
*/
|
||||
if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
/*
|
||||
* Skip LINK TRB. We can't use req->trb and check for
|
||||
* DWC3_TRBCTL_LINK_TRB because it points the TRB we
|
||||
* just completed (not the LINK TRB).
|
||||
*/
|
||||
if (((dep->busy_slot & DWC3_TRB_MASK) ==
|
||||
DWC3_TRB_NUM- 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dep->busy_slot++;
|
||||
dep->busy_slot++;
|
||||
} while(++i < req->request.num_mapped_sgs);
|
||||
req->queued = false;
|
||||
}
|
||||
list_del(&req->list);
|
||||
req->trb = NULL;
|
||||
|
|
@ -749,33 +751,32 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
|
|||
*/
|
||||
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req, dma_addr_t dma,
|
||||
unsigned length, unsigned last, unsigned chain)
|
||||
unsigned length, unsigned last, unsigned chain, unsigned node)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_trb *trb;
|
||||
|
||||
unsigned int cur_slot;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
|
||||
dep->name, req, (unsigned long long) dma,
|
||||
length, last ? " last" : "",
|
||||
chain ? " chain" : "");
|
||||
|
||||
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
cur_slot = dep->free_slot;
|
||||
dep->free_slot++;
|
||||
|
||||
/* Skip the LINK-TRB on ISOC */
|
||||
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
return;
|
||||
dep->free_slot++;
|
||||
|
||||
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_request_queued(req);
|
||||
req->trb = trb;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
req->start_slot = dep->free_slot & DWC3_TRB_MASK;
|
||||
}
|
||||
|
||||
dep->free_slot++;
|
||||
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(length);
|
||||
trb->bpl = lower_32_bits(dma);
|
||||
trb->bph = upper_32_bits(dma);
|
||||
|
|
@ -786,9 +787,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
if (!node)
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
else
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
|
||||
|
||||
if (!req->request.no_interrupt)
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
break;
|
||||
|
||||
|
|
@ -807,14 +811,13 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
} else {
|
||||
if (chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CHN;
|
||||
|
||||
if (last)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_LST;
|
||||
} else if (last) {
|
||||
trb->ctrl |= DWC3_TRB_CTRL_LST;
|
||||
}
|
||||
|
||||
if (chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CHN;
|
||||
|
||||
if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
|
||||
|
||||
|
|
@ -885,6 +888,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
list_for_each_entry_safe(req, n, &dep->request_list, list) {
|
||||
unsigned length;
|
||||
dma_addr_t dma;
|
||||
last_one = false;
|
||||
|
||||
if (req->request.num_mapped_sgs > 0) {
|
||||
struct usb_request *request = &req->request;
|
||||
|
|
@ -900,7 +904,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
|
||||
if (i == (request->num_mapped_sgs - 1) ||
|
||||
sg_is_last(s)) {
|
||||
last_one = true;
|
||||
if (list_is_last(&req->list,
|
||||
&dep->request_list))
|
||||
last_one = true;
|
||||
chain = false;
|
||||
}
|
||||
|
||||
|
|
@ -912,7 +918,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
chain = false;
|
||||
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
last_one, chain);
|
||||
last_one, chain, i);
|
||||
|
||||
if (last_one)
|
||||
break;
|
||||
|
|
@ -930,7 +936,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
|||
last_one = 1;
|
||||
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
last_one, false);
|
||||
last_one, false, 0);
|
||||
|
||||
if (last_one)
|
||||
break;
|
||||
|
|
@ -977,13 +983,14 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
|||
}
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.param0 = upper_32_bits(req->trb_dma);
|
||||
params.param1 = lower_32_bits(req->trb_dma);
|
||||
|
||||
if (start_new)
|
||||
if (start_new) {
|
||||
params.param0 = upper_32_bits(req->trb_dma);
|
||||
params.param1 = lower_32_bits(req->trb_dma);
|
||||
cmd = DWC3_DEPCMD_STARTTRANSFER;
|
||||
else
|
||||
} else {
|
||||
cmd = DWC3_DEPCMD_UPDATETRANSFER;
|
||||
}
|
||||
|
||||
cmd |= DWC3_DEPCMD_PARAM(cmd_param);
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
|
|
@ -1082,8 +1089,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
*
|
||||
*/
|
||||
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If xfernotready is already elapsed and it is a case
|
||||
* of isoc transfer, then issue END TRANSFER, so that
|
||||
|
|
@ -1091,7 +1096,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* notion of current microframe.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
if (list_empty(&dep->req_queued)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1099,6 +1107,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1115,16 +1124,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. Missed ISOC Handling. We need to start isoc transfer on the saved
|
||||
* uframe number.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
||||
__dwc3_gadget_start_isoc(dwc, dep, dep->current_uf);
|
||||
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1579,7 +1579,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
|
|||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u8 epnum;
|
||||
|
|
@ -1605,6 +1605,7 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
|||
|
||||
if (epnum == 0 || epnum == 1) {
|
||||
dep->endpoint.maxpacket = 512;
|
||||
dep->endpoint.maxburst = 1;
|
||||
dep->endpoint.ops = &dwc3_gadget_ep0_ops;
|
||||
if (!epnum)
|
||||
dwc->gadget.ep0 = &dep->endpoint;
|
||||
|
|
@ -1651,14 +1652,90 @@ static void dwc3_gadget_release(struct device *dev)
|
|||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
struct dwc3_request *req, struct dwc3_trb *trb,
|
||||
const struct dwc3_event_depevt *event, int status)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int s_pkt = 0;
|
||||
unsigned int trb_status;
|
||||
|
||||
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
|
||||
/*
|
||||
* We continue despite the error. There is not much we
|
||||
* can do. If we don't clean it up we loop forever. If
|
||||
* we skip the TRB then it gets overwritten after a
|
||||
* while since we use them in a ring buffer. A BUG()
|
||||
* would help. Lets hope that if this occurs, someone
|
||||
* fixes the root cause instead of looking away :)
|
||||
*/
|
||||
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
|
||||
dep->name, trb);
|
||||
count = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
if (dep->direction) {
|
||||
if (count) {
|
||||
trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
|
||||
dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
/*
|
||||
* If missed isoc occurred and there is
|
||||
* no request queued then issue END
|
||||
* TRANSFER, so that core generates
|
||||
* next xfernotready and we will issue
|
||||
* a fresh START TRANSFER.
|
||||
* If there are still queued request
|
||||
* then wait, do not issue either END
|
||||
* or UPDATE TRANSFER, just attach next
|
||||
* request in request_list during
|
||||
* giveback.If any future queued request
|
||||
* is successfully transferred then we
|
||||
* will issue UPDATE TRANSFER for all
|
||||
* request in the request_list.
|
||||
*/
|
||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||
} else {
|
||||
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
status = -ECONNRESET;
|
||||
}
|
||||
} else {
|
||||
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
||||
}
|
||||
} else {
|
||||
if (count && (event->status & DEPEVT_STATUS_SHORT))
|
||||
s_pkt = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume here we will always receive the entire data block
|
||||
* which we should receive. Meaning, if we program RX to
|
||||
* receive 4K but we receive only 2K, we assume that's all we
|
||||
* should receive and we simply bounce the request back to the
|
||||
* gadget driver for further processing.
|
||||
*/
|
||||
req->request.actual += req->request.length - count;
|
||||
if (s_pkt)
|
||||
return 1;
|
||||
if ((event->status & DEPEVT_STATUS_LST) &&
|
||||
(trb->ctrl & (DWC3_TRB_CTRL_LST |
|
||||
DWC3_TRB_CTRL_HWO)))
|
||||
return 1;
|
||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
const struct dwc3_event_depevt *event, int status)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
struct dwc3_trb *trb;
|
||||
unsigned int count;
|
||||
unsigned int s_pkt = 0;
|
||||
unsigned int trb_status;
|
||||
unsigned int slot;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
req = next_request(&dep->req_queued);
|
||||
|
|
@ -1666,62 +1743,44 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||
WARN_ON_ONCE(1);
|
||||
return 1;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
slot = req->start_slot + i;
|
||||
if ((slot == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
slot++;
|
||||
slot %= DWC3_TRB_NUM;
|
||||
trb = &dep->trb_pool[slot];
|
||||
|
||||
trb = req->trb;
|
||||
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
||||
event, status);
|
||||
if (ret)
|
||||
break;
|
||||
}while (++i < req->request.num_mapped_sgs);
|
||||
|
||||
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
|
||||
/*
|
||||
* We continue despite the error. There is not much we
|
||||
* can do. If we don't clean it up we loop forever. If
|
||||
* we skip the TRB then it gets overwritten after a
|
||||
* while since we use them in a ring buffer. A BUG()
|
||||
* would help. Lets hope that if this occurs, someone
|
||||
* fixes the root cause instead of looking away :)
|
||||
*/
|
||||
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
|
||||
dep->name, req->trb);
|
||||
count = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
if (dep->direction) {
|
||||
if (count) {
|
||||
trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
|
||||
dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
dep->current_uf = event->parameters &
|
||||
~(dep->interval - 1);
|
||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||
} else {
|
||||
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
status = -ECONNRESET;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (count && (event->status & DEPEVT_STATUS_SHORT))
|
||||
s_pkt = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume here we will always receive the entire data block
|
||||
* which we should receive. Meaning, if we program RX to
|
||||
* receive 4K but we receive only 2K, we assume that's all we
|
||||
* should receive and we simply bounce the request back to the
|
||||
* gadget driver for further processing.
|
||||
*/
|
||||
req->request.actual += req->request.length - count;
|
||||
dwc3_gadget_giveback(dep, req, status);
|
||||
if (s_pkt)
|
||||
break;
|
||||
if ((event->status & DEPEVT_STATUS_LST) &&
|
||||
(trb->ctrl & (DWC3_TRB_CTRL_LST |
|
||||
DWC3_TRB_CTRL_HWO)))
|
||||
break;
|
||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
list_empty(&dep->req_queued)) {
|
||||
if (list_empty(&dep->request_list)) {
|
||||
/*
|
||||
* If there is no entry in request list then do
|
||||
* not issue END TRANSFER now. Just set PENDING
|
||||
* flag, so that END TRANSFER is issued when an
|
||||
* entry is added into request list.
|
||||
*/
|
||||
dep->flags = DWC3_EP_PENDING_REQUEST;
|
||||
} else {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||
return 0;
|
||||
|
|
@ -2100,7 +2159,6 @@ static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
|
|||
|
||||
static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
|
@ -2108,8 +2166,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
|||
|
||||
dev_vdbg(dwc->dev, "%s\n", __func__);
|
||||
|
||||
memset(¶ms, 0x00, sizeof(params));
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
speed = reg & DWC3_DSTS_CONNECTSPD;
|
||||
dwc->speed = speed;
|
||||
|
|
@ -2156,6 +2212,26 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Enable USB2 LPM Capability */
|
||||
|
||||
if ((dwc->revision > DWC3_REVISION_194A)
|
||||
&& (speed != DWC3_DCFG_SUPERSPEED)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
|
||||
|
||||
/*
|
||||
* TODO: This should be configurable. For now using
|
||||
* maximum allowed HIRD threshold value of 0b1100
|
||||
*/
|
||||
reg |= DWC3_DCTL_HIRD_THRES(12);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* Suspend unneeded PHY */
|
||||
|
|
@ -2374,7 +2450,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
|
|||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
|
@ -2462,20 +2538,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
|||
DWC3_DEVTEN_DISCONNEVTEN);
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
|
||||
/* Enable USB2 LPM and automatic phy suspend only on recent versions */
|
||||
/* automatic phy suspend only on recent versions */
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
|
||||
|
||||
/* TODO: This should be configurable */
|
||||
reg |= DWC3_DCTL_HIRD_THRES(28);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ int dwc3_host_init(struct dwc3 *dwc)
|
|||
struct platform_device *xhci;
|
||||
int ret;
|
||||
|
||||
xhci = platform_device_alloc("xhci-hcd", -1);
|
||||
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
|
||||
if (!xhci) {
|
||||
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
|
||||
ret = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/usb/ehci_def.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/io.h>
|
||||
|
|
@ -614,12 +615,6 @@ err:
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dbgp_external_startup(struct usb_hcd *hcd)
|
||||
{
|
||||
return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dbgp_external_startup);
|
||||
|
||||
static int ehci_reset_port(int port)
|
||||
{
|
||||
u32 portsc;
|
||||
|
|
@ -979,6 +974,7 @@ struct console early_dbgp_console = {
|
|||
.index = -1,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB)
|
||||
int dbgp_reset_prep(struct usb_hcd *hcd)
|
||||
{
|
||||
int ret = xen_dbgp_reset_prep(hcd);
|
||||
|
|
@ -1007,6 +1003,13 @@ int dbgp_reset_prep(struct usb_hcd *hcd)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dbgp_reset_prep);
|
||||
|
||||
int dbgp_external_startup(struct usb_hcd *hcd)
|
||||
{
|
||||
return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dbgp_external_startup);
|
||||
#endif /* USB */
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
|
||||
static char kgdbdbgp_buf[DBGP_MAX_PACKET];
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ config USB_S3C_HSOTG
|
|||
config USB_IMX
|
||||
tristate "Freescale i.MX1 USB Peripheral Controller"
|
||||
depends on ARCH_MXC
|
||||
depends on BROKEN
|
||||
help
|
||||
Freescale's i.MX1 includes an integrated full speed
|
||||
USB 1.1 device controller.
|
||||
|
|
@ -319,6 +320,7 @@ config USB_S3C_HSUDC
|
|||
|
||||
config USB_MV_UDC
|
||||
tristate "Marvell USB2.0 Device Controller"
|
||||
depends on GENERIC_HARDIRQS
|
||||
help
|
||||
Marvell Socs (including PXA and MMP series) include a high speed
|
||||
USB2.0 OTG controller, which can be configured as high speed or
|
||||
|
|
@ -440,7 +442,7 @@ config USB_GOKU
|
|||
|
||||
config USB_EG20T
|
||||
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
|
||||
depends on PCI
|
||||
depends on PCI && GENERIC_HARDIRQS
|
||||
help
|
||||
This is a USB device driver for EG20T PCH.
|
||||
EG20T PCH is the platform controller hub that is used in Intel's
|
||||
|
|
@ -500,6 +502,15 @@ config USB_LIBCOMPOSITE
|
|||
tristate
|
||||
depends on USB_GADGET
|
||||
|
||||
config USB_F_ACM
|
||||
tristate
|
||||
|
||||
config USB_F_SS_LB
|
||||
tristate
|
||||
|
||||
config USB_U_SERIAL
|
||||
tristate
|
||||
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
default USB_ETH
|
||||
|
|
@ -524,6 +535,7 @@ choice
|
|||
config USB_ZERO
|
||||
tristate "Gadget Zero (DEVELOPMENT)"
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_F_SS_LB
|
||||
help
|
||||
Gadget Zero is a two-configuration device. It either sinks and
|
||||
sources bulk data; or it loops back a configurable number of
|
||||
|
|
@ -721,31 +733,6 @@ config USB_FUNCTIONFS_GENERIC
|
|||
Include a configuration with the Function Filesystem alone with
|
||||
no Ethernet interface.
|
||||
|
||||
config USB_FILE_STORAGE
|
||||
tristate "File-backed Storage Gadget (DEPRECATED)"
|
||||
depends on BLOCK
|
||||
help
|
||||
The File-backed 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.
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "g_file_storage".
|
||||
|
||||
NOTE: This driver is deprecated. Its replacement is the
|
||||
Mass Storage Gadget.
|
||||
|
||||
config USB_FILE_STORAGE_TEST
|
||||
bool "File-backed Storage Gadget testing version"
|
||||
depends on USB_FILE_STORAGE
|
||||
default n
|
||||
help
|
||||
Say "y" to generate the larger testing version of the
|
||||
File-backed Storage Gadget, useful for probing the
|
||||
behavior of USB Mass Storage hosts. Not needed for
|
||||
normal operation.
|
||||
|
||||
config USB_MASS_STORAGE
|
||||
tristate "Mass Storage Gadget"
|
||||
depends on BLOCK
|
||||
|
|
@ -756,8 +743,8 @@ config USB_MASS_STORAGE
|
|||
device (in much the same way as the "loop" device driver),
|
||||
specified as a module parameter or sysfs option.
|
||||
|
||||
This driver is an updated replacement for the deprecated
|
||||
File-backed Storage Gadget (g_file_storage).
|
||||
This driver is a replacement for now removed File-backed
|
||||
Storage Gadget (g_file_storage).
|
||||
|
||||
Say "y" to link the driver statically, or "m" to build
|
||||
a dynamically linked module called "g_mass_storage".
|
||||
|
|
@ -775,6 +762,9 @@ config USB_GADGET_TARGET
|
|||
|
||||
config USB_G_SERIAL
|
||||
tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
|
||||
depends on TTY
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
select USB_LIBCOMPOSITE
|
||||
help
|
||||
The Serial Gadget talks to the Linux-USB generic serial driver.
|
||||
|
|
@ -824,10 +814,14 @@ config USB_G_PRINTER
|
|||
For more information, see Documentation/usb/gadget_printer.txt
|
||||
which includes sample code for accessing the device file.
|
||||
|
||||
if TTY
|
||||
|
||||
config USB_CDC_COMPOSITE
|
||||
tristate "CDC Composite Device (Ethernet and ACM)"
|
||||
depends on NET
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
help
|
||||
This driver provides two functions in one configuration:
|
||||
a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
|
||||
|
|
@ -843,6 +837,7 @@ config USB_G_NOKIA
|
|||
tristate "Nokia composite gadget"
|
||||
depends on PHONET
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_SERIAL
|
||||
help
|
||||
The Nokia composite gadget provides support for acm, obex
|
||||
and phonet in only one composite gadget driver.
|
||||
|
|
@ -854,6 +849,8 @@ config USB_G_ACM_MS
|
|||
tristate "CDC Composite Device (ACM and mass storage)"
|
||||
depends on BLOCK
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
help
|
||||
This driver provides two functions in one configuration:
|
||||
a mass storage, and a CDC ACM (serial port) link.
|
||||
|
|
@ -866,6 +863,8 @@ config USB_G_MULTI
|
|||
depends on BLOCK && NET
|
||||
select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
help
|
||||
The Multifunction Composite Gadget provides Ethernet (RNDIS
|
||||
and/or CDC Ethernet), mass storage and ACM serial link
|
||||
|
|
@ -904,6 +903,8 @@ config USB_G_MULTI_CDC
|
|||
|
||||
If unsure, say "y".
|
||||
|
||||
endif # TTY
|
||||
|
||||
config USB_G_HID
|
||||
tristate "HID Gadget"
|
||||
select USB_LIBCOMPOSITE
|
||||
|
|
@ -920,6 +921,7 @@ config USB_G_HID
|
|||
# Standalone / single function gadgets
|
||||
config USB_G_DBGP
|
||||
tristate "EHCI Debug Device Gadget"
|
||||
depends on TTY
|
||||
select USB_LIBCOMPOSITE
|
||||
help
|
||||
This gadget emulates an EHCI Debug device. This is useful when you want
|
||||
|
|
@ -941,6 +943,7 @@ config USB_G_DBGP_PRINTK
|
|||
|
||||
config USB_G_DBGP_SERIAL
|
||||
depends on USB_G_DBGP
|
||||
select USB_U_SERIAL
|
||||
bool "serial"
|
||||
help
|
||||
Userland can interact using /dev/ttyGSxxx.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
|
|||
obj-$(CONFIG_USB_GADGET) += udc-core.o
|
||||
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
|
||||
libcomposite-y := usbstring.o config.o epautoconf.o
|
||||
libcomposite-y += composite.o
|
||||
libcomposite-y += composite.o functions.o
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
|
|
@ -35,6 +35,12 @@ mv_udc-y := mv_udc_core.o
|
|||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
|
||||
# USB Functions
|
||||
obj-$(CONFIG_USB_F_ACM) += f_acm.o
|
||||
f_ss_lb-y := f_loopback.o f_sourcesink.o
|
||||
obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o
|
||||
obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
#
|
||||
|
|
@ -44,7 +50,6 @@ g_ether-y := ether.o
|
|||
g_serial-y := serial.o
|
||||
g_midi-y := gmidi.o
|
||||
gadgetfs-y := inode.o
|
||||
g_file_storage-y := file_storage.o
|
||||
g_mass_storage-y := mass_storage.o
|
||||
g_printer-y := printer.o
|
||||
g_cdc-y := cdc2.o
|
||||
|
|
@ -62,7 +67,6 @@ obj-$(CONFIG_USB_AUDIO) += g_audio.o
|
|||
obj-$(CONFIG_USB_ETH) += g_ether.o
|
||||
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
|
||||
obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o
|
||||
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
|
||||
obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
|
||||
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
|
||||
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
|
||||
|
|
|
|||
|
|
@ -40,9 +40,6 @@
|
|||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include "u_serial.c"
|
||||
#include "f_acm.c"
|
||||
#include "f_mass_storage.c"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -112,12 +109,15 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
|
|||
static struct fsg_common fsg_common;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static unsigned char tty_line;
|
||||
static struct usb_function *f_acm;
|
||||
static struct usb_function_instance *f_acm_inst;
|
||||
/*
|
||||
* We _always_ have both ACM and mass storage functions.
|
||||
*/
|
||||
static int __init acm_ms_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
int status;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
|
|
@ -125,16 +125,35 @@ 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);
|
||||
|
||||
status = acm_bind_config(c, 0);
|
||||
opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
|
||||
opts->port_num = tty_line;
|
||||
|
||||
f_acm = usb_get_function(f_acm_inst);
|
||||
if (IS_ERR(f_acm)) {
|
||||
status = PTR_ERR(f_acm);
|
||||
goto err_func;
|
||||
}
|
||||
|
||||
status = usb_add_function(c, f_acm);
|
||||
if (status < 0)
|
||||
return status;
|
||||
goto err_conf;
|
||||
|
||||
status = fsg_bind_config(c->cdev, c, &fsg_common);
|
||||
if (status < 0)
|
||||
return status;
|
||||
goto err_fsg;
|
||||
|
||||
return 0;
|
||||
err_fsg:
|
||||
usb_remove_function(c, f_acm);
|
||||
err_conf:
|
||||
usb_put_function(f_acm);
|
||||
err_func:
|
||||
usb_put_function_instance(f_acm_inst);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration acm_ms_config_driver = {
|
||||
|
|
@ -153,7 +172,7 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
|
|||
void *retp;
|
||||
|
||||
/* set up serial link layer */
|
||||
status = gserial_setup(cdev->gadget, 1);
|
||||
status = gserial_alloc_line(&tty_line);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
|
|
@ -189,14 +208,15 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
|
|||
fail1:
|
||||
fsg_common_put(&fsg_common);
|
||||
fail0:
|
||||
gserial_cleanup();
|
||||
gserial_free_line(tty_line);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
gserial_cleanup();
|
||||
|
||||
usb_put_function(f_acm);
|
||||
usb_put_function_instance(f_acm_inst);
|
||||
gserial_free_line(tty_line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1400,15 +1400,16 @@ static int udc_wakeup(struct usb_gadget *gadget)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amd5536_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
|
||||
static int amd5536_stop(struct usb_gadget_driver *driver);
|
||||
static int amd5536_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
static int amd5536_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
/* gadget operations */
|
||||
static const struct usb_gadget_ops udc_ops = {
|
||||
.wakeup = udc_wakeup,
|
||||
.get_frame = udc_get_frame,
|
||||
.start = amd5536_start,
|
||||
.stop = amd5536_stop,
|
||||
.udc_start = amd5536_udc_start,
|
||||
.udc_stop = amd5536_udc_stop,
|
||||
};
|
||||
|
||||
/* Setups endpoint parameters, adds endpoints to linked list */
|
||||
|
|
@ -1913,41 +1914,22 @@ static int setup_ep0(struct udc *dev)
|
|||
}
|
||||
|
||||
/* Called by gadget driver to register itself */
|
||||
static int amd5536_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int amd5536_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct udc *dev = udc;
|
||||
int retval;
|
||||
struct udc *dev = to_amd5536_udc(g);
|
||||
u32 tmp;
|
||||
|
||||
if (!driver || !bind || !driver->setup
|
||||
|| driver->max_speed < USB_SPEED_HIGH)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = bind(&dev->gadget, driver);
|
||||
|
||||
/* Some gadget drivers use both ep0 directions.
|
||||
* NOTE: to gadget driver, ep0 is just one endpoint...
|
||||
*/
|
||||
dev->ep[UDC_EP0OUT_IX].ep.driver_data =
|
||||
dev->ep[UDC_EP0IN_IX].ep.driver_data;
|
||||
|
||||
if (retval) {
|
||||
DBG(dev, "binding to %s returning %d\n",
|
||||
driver->driver.name, retval);
|
||||
dev->driver = NULL;
|
||||
dev->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* get ready for ep0 traffic */
|
||||
setup_ep0(dev);
|
||||
|
||||
|
|
@ -1969,14 +1951,9 @@ __acquires(dev->lock)
|
|||
{
|
||||
int tmp;
|
||||
|
||||
if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
|
||||
spin_unlock(&dev->lock);
|
||||
driver->disconnect(&dev->gadget);
|
||||
spin_lock(&dev->lock);
|
||||
}
|
||||
|
||||
/* empty queues and init hardware */
|
||||
udc_basic_init(dev);
|
||||
|
||||
for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
|
||||
empty_req_queue(&dev->ep[tmp]);
|
||||
|
||||
|
|
@ -1984,23 +1961,18 @@ __acquires(dev->lock)
|
|||
}
|
||||
|
||||
/* Called by gadget driver to unregister itself */
|
||||
static int amd5536_stop(struct usb_gadget_driver *driver)
|
||||
static int amd5536_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct udc *dev = udc;
|
||||
unsigned long flags;
|
||||
struct udc *dev = to_amd5536_udc(g);
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
udc_mask_unused_interrupts(dev);
|
||||
shutdown(dev, driver);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
driver->unbind(&dev->gadget);
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
|
||||
|
|
@ -2009,9 +1981,6 @@ static int amd5536_stop(struct usb_gadget_driver *driver)
|
|||
tmp |= AMD_BIT(UDC_DEVCTL_SD);
|
||||
writel(tmp, &dev->regs->ctl);
|
||||
|
||||
|
||||
DBG(dev, "%s: unregistered\n", driver->driver.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3231,7 +3200,7 @@ static int udc_pci_probe(
|
|||
}
|
||||
|
||||
if (!pdev->irq) {
|
||||
dev_err(&dev->pdev->dev, "irq not set\n");
|
||||
dev_err(&pdev->dev, "irq not set\n");
|
||||
kfree(dev);
|
||||
dev = NULL;
|
||||
retval = -ENODEV;
|
||||
|
|
@ -3250,7 +3219,7 @@ static int udc_pci_probe(
|
|||
dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
|
||||
|
||||
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
|
||||
dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
|
||||
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
|
||||
kfree(dev);
|
||||
dev = NULL;
|
||||
retval = -EBUSY;
|
||||
|
|
|
|||
|
|
@ -563,6 +563,8 @@ struct udc {
|
|||
u16 cur_alt;
|
||||
};
|
||||
|
||||
#define to_amd5536_udc(g) (container_of((g), struct udc, gadget))
|
||||
|
||||
/* setup request data */
|
||||
union udc_setup_data {
|
||||
u32 data[2];
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/usb/gadget.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <mach/hardware.h>
|
||||
|
|
@ -38,7 +39,6 @@
|
|||
#include <asm/irq.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <mach/board.h>
|
||||
#include <mach/cpu.h>
|
||||
#include <mach/at91sam9261_matrix.h>
|
||||
#include <mach/at91_matrix.h>
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
* full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
|
||||
* at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
|
||||
*
|
||||
* This driver expects the board has been wired with two GPIOs suppporting
|
||||
* This driver expects the board has been wired with two GPIOs supporting
|
||||
* a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the
|
||||
* testing hasn't covered such cases.)
|
||||
*
|
||||
|
|
@ -1621,8 +1621,7 @@ static void at91_vbus_timer(unsigned long data)
|
|||
* bus such as i2c or spi which may sleep, so schedule some work
|
||||
* to read the vbus gpio
|
||||
*/
|
||||
if (!work_pending(&udc->vbus_timer_work))
|
||||
schedule_work(&udc->vbus_timer_work);
|
||||
schedule_work(&udc->vbus_timer_work);
|
||||
}
|
||||
|
||||
static int at91_start(struct usb_gadget *gadget,
|
||||
|
|
@ -1673,7 +1672,7 @@ static void at91udc_shutdown(struct platform_device *dev)
|
|||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
}
|
||||
|
||||
static void __devinit at91udc_of_init(struct at91_udc *udc,
|
||||
static void at91udc_of_init(struct at91_udc *udc,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct at91_udc_data *board = &udc->board;
|
||||
|
|
@ -1693,7 +1692,7 @@ static void __devinit at91udc_of_init(struct at91_udc *udc,
|
|||
board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int __devinit at91udc_probe(struct platform_device *pdev)
|
||||
static int at91udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct at91_udc *udc;
|
||||
|
|
@ -1739,7 +1738,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
|
|||
|
||||
/* rm9200 needs manual D+ pullup; off by default */
|
||||
if (cpu_is_at91rm9200()) {
|
||||
if (gpio_is_valid(udc->board.pullup_pin)) {
|
||||
if (!gpio_is_valid(udc->board.pullup_pin)) {
|
||||
DBG("no D+ pullup?\n");
|
||||
retval = -ENODEV;
|
||||
goto fail0;
|
||||
|
|
@ -1982,17 +1981,7 @@ static struct platform_driver at91_udc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init udc_init_module(void)
|
||||
{
|
||||
return platform_driver_probe(&at91_udc_driver, at91udc_probe);
|
||||
}
|
||||
module_init(udc_init_module);
|
||||
|
||||
static void __exit udc_exit_module(void)
|
||||
{
|
||||
platform_driver_unregister(&at91_udc_driver);
|
||||
}
|
||||
module_exit(udc_exit_module);
|
||||
module_platform_driver_probe(at91_udc_driver, at91udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("AT91 udc driver");
|
||||
MODULE_AUTHOR("Thomas Rathbone, David Brownell");
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@
|
|||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/atmel_usba_udc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <mach/board.h>
|
||||
|
||||
#include "atmel_usba_udc.h"
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
|
|||
if (!access_ok(VERIFY_WRITE, buf, nbytes))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_lock(&file_inode(file)->i_mutex);
|
||||
list_for_each_entry_safe(req, tmp_req, queue, queue) {
|
||||
len = snprintf(tmpbuf, sizeof(tmpbuf),
|
||||
"%8p %08x %c%c%c %5d %c%c%c\n",
|
||||
|
|
@ -120,7 +120,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
|
|||
nbytes -= len;
|
||||
buf += len;
|
||||
}
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
mutex_unlock(&file_inode(file)->i_mutex);
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
|
@ -168,13 +168,13 @@ out:
|
|||
static ssize_t regs_dbg_read(struct file *file, char __user *buf,
|
||||
size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
struct inode *inode = file_inode(file);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = simple_read_from_buffer(buf, nbytes, ppos,
|
||||
file->private_data,
|
||||
file->f_dentry->d_inode->i_size);
|
||||
file_inode(file)->i_size);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return ret;
|
||||
|
|
@ -2066,17 +2066,7 @@ static struct platform_driver udc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&udc_driver, usba_udc_probe);
|
||||
}
|
||||
module_init(udc_init);
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
}
|
||||
module_exit(udc_exit);
|
||||
module_platform_driver_probe(udc_driver, usba_udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("Atmel USBA UDC driver");
|
||||
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
|
||||
|
|
|
|||
|
|
@ -2323,7 +2323,7 @@ static void bcm63xx_udc_gadget_release(struct device *dev)
|
|||
* Note that platform data is required, because pd.port_no varies from chip
|
||||
* to chip and is used to switch the correct USB port to device mode.
|
||||
*/
|
||||
static int __devinit bcm63xx_udc_probe(struct platform_device *pdev)
|
||||
static int bcm63xx_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
|
||||
|
|
@ -2351,19 +2351,20 @@ static int __devinit bcm63xx_udc_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "error finding USBD resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
udc->usbd_regs = devm_request_and_ioremap(dev, res);
|
||||
|
||||
udc->usbd_regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(udc->usbd_regs))
|
||||
return PTR_ERR(udc->usbd_regs);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "error finding IUDMA resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
udc->iudma_regs = devm_request_and_ioremap(dev, res);
|
||||
|
||||
if (!udc->usbd_regs || !udc->iudma_regs) {
|
||||
dev_err(dev, "error requesting resources\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
udc->iudma_regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(udc->iudma_regs))
|
||||
return PTR_ERR(udc->iudma_regs);
|
||||
|
||||
spin_lock_init(&udc->lock);
|
||||
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
|
||||
|
|
@ -2433,7 +2434,7 @@ out_uninit:
|
|||
* bcm63xx_udc_remove - Remove the device from the system.
|
||||
* @pdev: Platform device struct from the bcm63xx BSP code.
|
||||
*/
|
||||
static int __devexit bcm63xx_udc_remove(struct platform_device *pdev)
|
||||
static int bcm63xx_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm63xx_udc *udc = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -2450,7 +2451,7 @@ static int __devexit bcm63xx_udc_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver bcm63xx_udc_driver = {
|
||||
.probe = bcm63xx_udc_probe,
|
||||
.remove = __devexit_p(bcm63xx_udc_remove),
|
||||
.remove = bcm63xx_udc_remove,
|
||||
.driver = {
|
||||
.name = DRV_MODULE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -42,9 +42,6 @@ USB_GADGET_COMPOSITE_OPTIONS();
|
|||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#include "u_serial.c"
|
||||
#include "f_acm.c"
|
||||
#include "f_ecm.c"
|
||||
#include "u_ether.c"
|
||||
|
||||
|
|
@ -108,12 +105,16 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct usb_function *f_acm;
|
||||
static struct usb_function_instance *fi_serial;
|
||||
|
||||
static unsigned char tty_line;
|
||||
/*
|
||||
* We _always_ have both CDC ECM and CDC ACM functions.
|
||||
*/
|
||||
static int __init cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
int status;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
|
|
@ -125,11 +126,26 @@ static int __init cdc_do_config(struct usb_configuration *c)
|
|||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = acm_bind_config(c, 0);
|
||||
if (status < 0)
|
||||
return status;
|
||||
fi_serial = usb_get_function_instance("acm");
|
||||
if (IS_ERR(fi_serial))
|
||||
return PTR_ERR(fi_serial);
|
||||
|
||||
opts = container_of(fi_serial, struct f_serial_opts, func_inst);
|
||||
opts->port_num = tty_line;
|
||||
|
||||
f_acm = usb_get_function(fi_serial);
|
||||
if (IS_ERR(f_acm))
|
||||
goto err_func_acm;
|
||||
|
||||
status = usb_add_function(c, f_acm);
|
||||
if (status)
|
||||
goto err_conf;
|
||||
return 0;
|
||||
err_conf:
|
||||
usb_put_function(f_acm);
|
||||
err_func_acm:
|
||||
usb_put_function_instance(fi_serial);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration cdc_config_driver = {
|
||||
|
|
@ -158,7 +174,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
|||
return status;
|
||||
|
||||
/* set up serial link layer */
|
||||
status = gserial_setup(cdev->gadget, 1);
|
||||
status = gserial_alloc_line(&tty_line);
|
||||
if (status < 0)
|
||||
goto fail0;
|
||||
|
||||
|
|
@ -184,7 +200,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
|
||||
fail1:
|
||||
gserial_cleanup();
|
||||
gserial_free_line(tty_line);
|
||||
fail0:
|
||||
gether_cleanup();
|
||||
return status;
|
||||
|
|
@ -192,7 +208,9 @@ fail0:
|
|||
|
||||
static int __exit cdc_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
gserial_cleanup();
|
||||
usb_put_function(f_acm);
|
||||
usb_put_function_instance(fi_serial);
|
||||
gserial_free_line(tty_line);
|
||||
gether_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@
|
|||
* with the relevant device-wide data.
|
||||
*/
|
||||
|
||||
static struct usb_gadget_strings **get_containers_gs(
|
||||
struct usb_gadget_string_container *uc)
|
||||
{
|
||||
return (struct usb_gadget_strings **)uc->stash;
|
||||
}
|
||||
|
||||
/**
|
||||
* next_ep_desc() - advance to the next EP descriptor
|
||||
* @t: currect pointer within descriptor array
|
||||
|
|
@ -107,7 +113,7 @@ int config_ep_by_speed(struct usb_gadget *g,
|
|||
}
|
||||
/* else: fall through */
|
||||
default:
|
||||
speed_desc = f->descriptors;
|
||||
speed_desc = f->fs_descriptors;
|
||||
}
|
||||
/* find descriptors */
|
||||
for_each_ep_desc(speed_desc, d_spd) {
|
||||
|
|
@ -200,7 +206,7 @@ int usb_add_function(struct usb_configuration *config,
|
|||
* as full speed ... it's the function drivers that will need
|
||||
* to avoid bulk and ISO transfers.
|
||||
*/
|
||||
if (!config->fullspeed && function->descriptors)
|
||||
if (!config->fullspeed && function->fs_descriptors)
|
||||
config->fullspeed = true;
|
||||
if (!config->highspeed && function->hs_descriptors)
|
||||
config->highspeed = true;
|
||||
|
|
@ -215,6 +221,18 @@ done:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_function);
|
||||
|
||||
void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
if (f->disable)
|
||||
f->disable(f);
|
||||
|
||||
bitmap_zero(f->endpoints, 32);
|
||||
list_del(&f->list);
|
||||
if (f->unbind)
|
||||
f->unbind(c, f);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_remove_function);
|
||||
|
||||
/**
|
||||
* usb_function_deactivate - prevent function and gadget enumeration
|
||||
* @function: the function that isn't yet ready to respond
|
||||
|
|
@ -320,6 +338,25 @@ int usb_interface_id(struct usb_configuration *config,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_interface_id);
|
||||
|
||||
static u8 encode_bMaxPower(enum usb_device_speed speed,
|
||||
struct usb_configuration *c)
|
||||
{
|
||||
unsigned val;
|
||||
|
||||
if (c->MaxPower)
|
||||
val = c->MaxPower;
|
||||
else
|
||||
val = CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
if (!val)
|
||||
return 0;
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
return DIV_ROUND_UP(val, 8);
|
||||
default:
|
||||
return DIV_ROUND_UP(val, 2);
|
||||
};
|
||||
}
|
||||
|
||||
static int config_buf(struct usb_configuration *config,
|
||||
enum usb_device_speed speed, void *buf, u8 type)
|
||||
{
|
||||
|
|
@ -339,7 +376,7 @@ static int config_buf(struct usb_configuration *config,
|
|||
c->bConfigurationValue = config->bConfigurationValue;
|
||||
c->iConfiguration = config->iConfiguration;
|
||||
c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
|
||||
c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
|
||||
c->bMaxPower = encode_bMaxPower(speed, config);
|
||||
|
||||
/* There may be e.g. OTG descriptors */
|
||||
if (config->descriptors) {
|
||||
|
|
@ -363,7 +400,7 @@ static int config_buf(struct usb_configuration *config,
|
|||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
default:
|
||||
descriptors = f->descriptors;
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
if (!descriptors)
|
||||
|
|
@ -620,7 +657,7 @@ static int set_config(struct usb_composite_dev *cdev,
|
|||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
default:
|
||||
descriptors = f->descriptors;
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
for (; *descriptors; ++descriptors) {
|
||||
|
|
@ -656,7 +693,7 @@ static int set_config(struct usb_composite_dev *cdev,
|
|||
}
|
||||
|
||||
/* when we return, be sure our power usage is valid */
|
||||
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
done:
|
||||
usb_gadget_vbus_draw(gadget, power);
|
||||
if (result >= 0 && cdev->delayed_status)
|
||||
|
|
@ -664,6 +701,31 @@ done:
|
|||
return result;
|
||||
}
|
||||
|
||||
int usb_add_config_only(struct usb_composite_dev *cdev,
|
||||
struct usb_configuration *config)
|
||||
{
|
||||
struct usb_configuration *c;
|
||||
|
||||
if (!config->bConfigurationValue)
|
||||
return -EINVAL;
|
||||
|
||||
/* Prevent duplicate configuration identifiers */
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
if (c->bConfigurationValue == config->bConfigurationValue)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
config->cdev = cdev;
|
||||
list_add_tail(&config->list, &cdev->configs);
|
||||
|
||||
INIT_LIST_HEAD(&config->functions);
|
||||
config->next_interface_id = 0;
|
||||
memset(config->interface, 0, sizeof(config->interface));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_config_only);
|
||||
|
||||
/**
|
||||
* usb_add_config() - add a configuration to a device.
|
||||
* @cdev: wraps the USB gadget
|
||||
|
|
@ -684,30 +746,18 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
|||
int (*bind)(struct usb_configuration *))
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct usb_configuration *c;
|
||||
|
||||
if (!bind)
|
||||
goto done;
|
||||
|
||||
DBG(cdev, "adding config #%u '%s'/%p\n",
|
||||
config->bConfigurationValue,
|
||||
config->label, config);
|
||||
|
||||
if (!config->bConfigurationValue || !bind)
|
||||
status = usb_add_config_only(cdev, config);
|
||||
if (status)
|
||||
goto done;
|
||||
|
||||
/* Prevent duplicate configuration identifiers */
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
if (c->bConfigurationValue == config->bConfigurationValue) {
|
||||
status = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
config->cdev = cdev;
|
||||
list_add_tail(&config->list, &cdev->configs);
|
||||
|
||||
INIT_LIST_HEAD(&config->functions);
|
||||
config->next_interface_id = 0;
|
||||
memset(config->interface, 0, sizeof(config->interface));
|
||||
|
||||
status = bind(config);
|
||||
if (status < 0) {
|
||||
while (!list_empty(&config->functions)) {
|
||||
|
|
@ -860,6 +910,7 @@ static int get_string(struct usb_composite_dev *cdev,
|
|||
void *buf, u16 language, int id)
|
||||
{
|
||||
struct usb_composite_driver *composite = cdev->driver;
|
||||
struct usb_gadget_string_container *uc;
|
||||
struct usb_configuration *c;
|
||||
struct usb_function *f;
|
||||
int len;
|
||||
|
|
@ -892,6 +943,12 @@ static int get_string(struct usb_composite_dev *cdev,
|
|||
collect_langs(sp, s->wData);
|
||||
}
|
||||
}
|
||||
list_for_each_entry(uc, &cdev->gstrings, list) {
|
||||
struct usb_gadget_strings **sp;
|
||||
|
||||
sp = get_containers_gs(uc);
|
||||
collect_langs(sp, s->wData);
|
||||
}
|
||||
|
||||
for (len = 0; len <= 126 && s->wData[len]; len++)
|
||||
continue;
|
||||
|
|
@ -902,6 +959,15 @@ static int get_string(struct usb_composite_dev *cdev,
|
|||
return s->bLength;
|
||||
}
|
||||
|
||||
list_for_each_entry(uc, &cdev->gstrings, list) {
|
||||
struct usb_gadget_strings **sp;
|
||||
|
||||
sp = get_containers_gs(uc);
|
||||
len = lookup_string(sp, buf, language, id);
|
||||
if (len > 0)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* String IDs are device-scoped, so we look up each string
|
||||
* table we're told about. These lookups are infrequent;
|
||||
* simpler-is-better here.
|
||||
|
|
@ -987,6 +1053,119 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_string_ids_tab);
|
||||
|
||||
static struct usb_gadget_string_container *copy_gadget_strings(
|
||||
struct usb_gadget_strings **sp, unsigned n_gstrings,
|
||||
unsigned n_strings)
|
||||
{
|
||||
struct usb_gadget_string_container *uc;
|
||||
struct usb_gadget_strings **gs_array;
|
||||
struct usb_gadget_strings *gs;
|
||||
struct usb_string *s;
|
||||
unsigned mem;
|
||||
unsigned n_gs;
|
||||
unsigned n_s;
|
||||
void *stash;
|
||||
|
||||
mem = sizeof(*uc);
|
||||
mem += sizeof(void *) * (n_gstrings + 1);
|
||||
mem += sizeof(struct usb_gadget_strings) * n_gstrings;
|
||||
mem += sizeof(struct usb_string) * (n_strings + 1) * (n_gstrings);
|
||||
uc = kmalloc(mem, GFP_KERNEL);
|
||||
if (!uc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
gs_array = get_containers_gs(uc);
|
||||
stash = uc->stash;
|
||||
stash += sizeof(void *) * (n_gstrings + 1);
|
||||
for (n_gs = 0; n_gs < n_gstrings; n_gs++) {
|
||||
struct usb_string *org_s;
|
||||
|
||||
gs_array[n_gs] = stash;
|
||||
gs = gs_array[n_gs];
|
||||
stash += sizeof(struct usb_gadget_strings);
|
||||
gs->language = sp[n_gs]->language;
|
||||
gs->strings = stash;
|
||||
org_s = sp[n_gs]->strings;
|
||||
|
||||
for (n_s = 0; n_s < n_strings; n_s++) {
|
||||
s = stash;
|
||||
stash += sizeof(struct usb_string);
|
||||
if (org_s->s)
|
||||
s->s = org_s->s;
|
||||
else
|
||||
s->s = "";
|
||||
org_s++;
|
||||
}
|
||||
s = stash;
|
||||
s->s = NULL;
|
||||
stash += sizeof(struct usb_string);
|
||||
|
||||
}
|
||||
gs_array[n_gs] = NULL;
|
||||
return uc;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_gstrings_attach() - attach gadget strings to a cdev and assign ids
|
||||
* @cdev: the device whose string descriptor IDs are being allocated
|
||||
* and attached.
|
||||
* @sp: an array of usb_gadget_strings to attach.
|
||||
* @n_strings: number of entries in each usb_strings array (sp[]->strings)
|
||||
*
|
||||
* This function will create a deep copy of usb_gadget_strings and usb_string
|
||||
* and attach it to the cdev. The actual string (usb_string.s) will not be
|
||||
* copied but only a referenced will be made. The struct usb_gadget_strings
|
||||
* array may contain multiple languges and should be NULL terminated.
|
||||
* The ->language pointer of each struct usb_gadget_strings has to contain the
|
||||
* same amount of entries.
|
||||
* For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
|
||||
* usb_string entry of es-ES containts the translation of the first usb_string
|
||||
* entry of en-US. Therefore both entries become the same id assign.
|
||||
*/
|
||||
struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
|
||||
struct usb_gadget_strings **sp, unsigned n_strings)
|
||||
{
|
||||
struct usb_gadget_string_container *uc;
|
||||
struct usb_gadget_strings **n_gs;
|
||||
unsigned n_gstrings = 0;
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; sp[i]; i++)
|
||||
n_gstrings++;
|
||||
|
||||
if (!n_gstrings)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
uc = copy_gadget_strings(sp, n_gstrings, n_strings);
|
||||
if (IS_ERR(uc))
|
||||
return ERR_PTR(PTR_ERR(uc));
|
||||
|
||||
n_gs = get_containers_gs(uc);
|
||||
ret = usb_string_ids_tab(cdev, n_gs[0]->strings);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
for (i = 1; i < n_gstrings; i++) {
|
||||
struct usb_string *m_s;
|
||||
struct usb_string *s;
|
||||
unsigned n;
|
||||
|
||||
m_s = n_gs[0]->strings;
|
||||
s = n_gs[i]->strings;
|
||||
for (n = 0; n < n_strings; n++) {
|
||||
s->id = m_s->id;
|
||||
s++;
|
||||
m_s++;
|
||||
}
|
||||
}
|
||||
list_add_tail(&uc->list, &cdev->gstrings);
|
||||
return n_gs[0]->strings;
|
||||
err:
|
||||
kfree(uc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gstrings_attach);
|
||||
|
||||
/**
|
||||
* usb_string_ids_n() - allocate unused string IDs in batch
|
||||
* @c: the device whose string descriptor IDs are being allocated
|
||||
|
|
@ -1033,7 +1212,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
* housekeeping for the gadget function we're implementing. Most of
|
||||
* the work is in config and function specific setup.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
|
|
@ -1300,7 +1479,7 @@ done:
|
|||
return value;
|
||||
}
|
||||
|
||||
static void composite_disconnect(struct usb_gadget *gadget)
|
||||
void composite_disconnect(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
unsigned long flags;
|
||||
|
|
@ -1330,8 +1509,7 @@ static ssize_t composite_show_suspended(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
|
||||
|
||||
static void
|
||||
composite_unbind(struct usb_gadget *gadget)
|
||||
static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
|
||||
|
|
@ -1348,19 +1526,21 @@ composite_unbind(struct usb_gadget *gadget)
|
|||
struct usb_configuration, list);
|
||||
remove_config(cdev, c);
|
||||
}
|
||||
if (cdev->driver->unbind)
|
||||
if (cdev->driver->unbind && unbind_driver)
|
||||
cdev->driver->unbind(cdev);
|
||||
|
||||
if (cdev->req) {
|
||||
kfree(cdev->req->buf);
|
||||
usb_ep_free_request(gadget->ep0, cdev->req);
|
||||
}
|
||||
device_remove_file(&gadget->dev, &dev_attr_suspended);
|
||||
composite_dev_cleanup(cdev);
|
||||
|
||||
kfree(cdev->def_manufacturer);
|
||||
kfree(cdev);
|
||||
set_gadget_data(gadget, NULL);
|
||||
}
|
||||
|
||||
static void composite_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
__composite_unbind(gadget, true);
|
||||
}
|
||||
|
||||
static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
|
||||
const struct usb_device_descriptor *old)
|
||||
{
|
||||
|
|
@ -1399,34 +1579,25 @@ static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
|
|||
new->iProduct = iProduct;
|
||||
}
|
||||
|
||||
static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
|
||||
int composite_dev_prepare(struct usb_composite_driver *composite,
|
||||
struct usb_composite_dev *cdev)
|
||||
{
|
||||
return container_of(gdrv, struct usb_composite_driver, gadget_driver);
|
||||
}
|
||||
|
||||
static int composite_bind(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *gdriver)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
struct usb_composite_driver *composite = to_cdriver(gdriver);
|
||||
int status = -ENOMEM;
|
||||
|
||||
cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return status;
|
||||
|
||||
spin_lock_init(&cdev->lock);
|
||||
cdev->gadget = gadget;
|
||||
set_gadget_data(gadget, cdev);
|
||||
INIT_LIST_HEAD(&cdev->configs);
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* preallocate control response and buffer */
|
||||
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
|
||||
if (!cdev->req)
|
||||
goto fail;
|
||||
return -ENOMEM;
|
||||
|
||||
cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
|
||||
if (!cdev->req->buf)
|
||||
goto fail;
|
||||
|
||||
ret = device_create_file(&gadget->dev, &dev_attr_suspended);
|
||||
if (ret)
|
||||
goto fail_dev;
|
||||
|
||||
cdev->req->complete = composite_setup_complete;
|
||||
gadget->ep0->driver_data = cdev;
|
||||
|
||||
|
|
@ -1444,7 +1615,51 @@ static int composite_bind(struct usb_gadget *gadget,
|
|||
* we force endpoints to start unassigned; few controller
|
||||
* drivers will zero ep->driver_data.
|
||||
*/
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
usb_ep_autoconfig_reset(gadget);
|
||||
return 0;
|
||||
fail_dev:
|
||||
kfree(cdev->req->buf);
|
||||
fail:
|
||||
usb_ep_free_request(gadget->ep0, cdev->req);
|
||||
cdev->req = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void composite_dev_cleanup(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget_string_container *uc, *tmp;
|
||||
|
||||
list_for_each_entry_safe(uc, tmp, &cdev->gstrings, list) {
|
||||
list_del(&uc->list);
|
||||
kfree(uc);
|
||||
}
|
||||
if (cdev->req) {
|
||||
kfree(cdev->req->buf);
|
||||
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
|
||||
}
|
||||
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
|
||||
}
|
||||
|
||||
static int composite_bind(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *gdriver)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
struct usb_composite_driver *composite = to_cdriver(gdriver);
|
||||
int status = -ENOMEM;
|
||||
|
||||
cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return status;
|
||||
|
||||
spin_lock_init(&cdev->lock);
|
||||
cdev->gadget = gadget;
|
||||
set_gadget_data(gadget, cdev);
|
||||
INIT_LIST_HEAD(&cdev->configs);
|
||||
INIT_LIST_HEAD(&cdev->gstrings);
|
||||
|
||||
status = composite_dev_prepare(composite, cdev);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* composite gadget needs to assign strings for whole device (like
|
||||
* serial number), register function drivers, potentially update
|
||||
|
|
@ -1460,16 +1675,11 @@ static int composite_bind(struct usb_gadget *gadget,
|
|||
if (composite->needs_serial && !cdev->desc.iSerialNumber)
|
||||
WARNING(cdev, "userspace failed to provide iSerialNumber\n");
|
||||
|
||||
/* finish up */
|
||||
status = device_create_file(&gadget->dev, &dev_attr_suspended);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
INFO(cdev, "%s ready\n", composite->name);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
composite_unbind(gadget);
|
||||
__composite_unbind(gadget, false);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -1518,10 +1728,10 @@ composite_resume(struct usb_gadget *gadget)
|
|||
f->resume(f);
|
||||
}
|
||||
|
||||
maxpower = cdev->config->bMaxPower;
|
||||
maxpower = cdev->config->MaxPower;
|
||||
|
||||
usb_gadget_vbus_draw(gadget, maxpower ?
|
||||
(2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
|
||||
maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
|
||||
}
|
||||
|
||||
cdev->suspended = 0;
|
||||
|
|
@ -1547,10 +1757,7 @@ static const struct usb_gadget_driver composite_driver_template = {
|
|||
/**
|
||||
* usb_composite_probe() - register a composite driver
|
||||
* @driver: the driver to register
|
||||
* @bind: the callback used to allocate resources that are shared across the
|
||||
* whole device, such as string IDs, and add its configurations using
|
||||
* @usb_add_config(). This may fail by returning a negative errno
|
||||
* value; it should return zero on successful initialization.
|
||||
*
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* This function is used to register drivers using the composite driver
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
/**
|
||||
* usb_descriptor_fillbuf - fill buffer with descriptors
|
||||
|
|
@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_copy_descriptors);
|
||||
|
||||
int usb_assign_descriptors(struct usb_function *f,
|
||||
struct usb_descriptor_header **fs,
|
||||
struct usb_descriptor_header **hs,
|
||||
struct usb_descriptor_header **ss)
|
||||
{
|
||||
struct usb_gadget *g = f->config->cdev->gadget;
|
||||
|
||||
if (fs) {
|
||||
f->fs_descriptors = usb_copy_descriptors(fs);
|
||||
if (!f->fs_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (hs && gadget_is_dualspeed(g)) {
|
||||
f->hs_descriptors = usb_copy_descriptors(hs);
|
||||
if (!f->hs_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (ss && gadget_is_superspeed(g)) {
|
||||
f->ss_descriptors = usb_copy_descriptors(ss);
|
||||
if (!f->ss_descriptors)
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
usb_free_all_descriptors(f);
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_assign_descriptors);
|
||||
|
||||
void usb_free_all_descriptors(struct usb_function *f)
|
||||
{
|
||||
usb_free_descriptors(f->fs_descriptors);
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@
|
|||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
#include "u_serial.c"
|
||||
#endif
|
||||
#include "u_serial.h"
|
||||
|
||||
#define DRIVER_VENDOR_ID 0x0525 /* NetChip */
|
||||
#define DRIVER_PRODUCT_ID 0xc0de /* undefined */
|
||||
|
|
@ -233,6 +231,10 @@ static void dbgp_unbind(struct usb_gadget *gadget)
|
|||
gadget->ep0->driver_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
static unsigned char tty_line;
|
||||
#endif
|
||||
|
||||
static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
|
||||
{
|
||||
int stp;
|
||||
|
|
@ -270,7 +272,7 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
|
|||
dbgp.serial->in->desc = &i_desc;
|
||||
dbgp.serial->out->desc = &o_desc;
|
||||
|
||||
if (gserial_setup(gadget, 1) < 0) {
|
||||
if (gserial_alloc_line(&tty_line)) {
|
||||
stp = 3;
|
||||
goto fail_3;
|
||||
}
|
||||
|
|
@ -379,7 +381,7 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
#ifdef CONFIG_USB_G_DBGP_PRINTK
|
||||
err = dbgp_enable_ep();
|
||||
#else
|
||||
err = gserial_connect(dbgp.serial, 0);
|
||||
err = gserial_connect(dbgp.serial, tty_line);
|
||||
#endif
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
|
@ -422,7 +424,7 @@ static void __exit dbgp_exit(void)
|
|||
{
|
||||
usb_gadget_unregister_driver(&dbgp_driver);
|
||||
#ifdef CONFIG_USB_G_DBGP_SERIAL
|
||||
gserial_cleanup();
|
||||
gserial_free_line(tty_line);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,16 +63,20 @@ MODULE_LICENSE("GPL");
|
|||
struct dummy_hcd_module_parameters {
|
||||
bool is_super_speed;
|
||||
bool is_high_speed;
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
static struct dummy_hcd_module_parameters mod_data = {
|
||||
.is_super_speed = false,
|
||||
.is_high_speed = true,
|
||||
.num = 1,
|
||||
};
|
||||
module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
|
||||
module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
|
||||
module_param_named(num, mod_data.num, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(num, "number of emulated controllers");
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* gadget side driver data structres */
|
||||
|
|
@ -126,10 +130,7 @@ static const char ep0name[] = "ep0";
|
|||
static const char *const ep_name[] = {
|
||||
ep0name, /* everyone has ep0 */
|
||||
|
||||
/* act like a net2280: high speed, six configurable endpoints */
|
||||
"ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
|
||||
|
||||
/* or like pxa250: fifteen fixed function endpoints */
|
||||
/* act like a pxa250: fifteen fixed function endpoints */
|
||||
"ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
|
||||
"ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
|
||||
"ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
|
||||
|
|
@ -137,6 +138,10 @@ static const char *const ep_name[] = {
|
|||
|
||||
/* or like sa1100: two fixed function endpoints */
|
||||
"ep1out-bulk", "ep2in-bulk",
|
||||
|
||||
/* and now some generic EPs so we have enough in multi config */
|
||||
"ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in",
|
||||
"ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out",
|
||||
};
|
||||
#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name)
|
||||
|
||||
|
|
@ -238,8 +243,6 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
|
|||
return container_of(dev, struct dummy, gadget.dev);
|
||||
}
|
||||
|
||||
static struct dummy the_controller;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* SLAVE/GADGET SIDE UTILITY ROUTINES */
|
||||
|
|
@ -973,9 +976,10 @@ static void init_dummy_udc_hw(struct dummy *dum)
|
|||
|
||||
static int dummy_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dummy *dum = &the_controller;
|
||||
struct dummy *dum;
|
||||
int rc;
|
||||
|
||||
dum = *((void **)dev_get_platdata(&pdev->dev));
|
||||
dum->gadget.name = gadget_name;
|
||||
dum->gadget.ops = &dummy_ops;
|
||||
dum->gadget.max_speed = USB_SPEED_SUPER;
|
||||
|
|
@ -2398,10 +2402,13 @@ static int dummy_h_get_frame(struct usb_hcd *hcd)
|
|||
|
||||
static int dummy_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct dummy *dum;
|
||||
|
||||
dum = *((void **)dev_get_platdata(hcd->self.controller));
|
||||
hcd->self.sg_tablesize = ~0;
|
||||
if (usb_hcd_is_primary_hcd(hcd)) {
|
||||
the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
|
||||
the_controller.hs_hcd->dum = &the_controller;
|
||||
dum->hs_hcd = hcd_to_dummy_hcd(hcd);
|
||||
dum->hs_hcd->dum = dum;
|
||||
/*
|
||||
* Mark the first roothub as being USB 2.0.
|
||||
* The USB 3.0 roothub will be registered later by
|
||||
|
|
@ -2410,8 +2417,8 @@ static int dummy_setup(struct usb_hcd *hcd)
|
|||
hcd->speed = HCD_USB2;
|
||||
hcd->self.root_hub->speed = USB_SPEED_HIGH;
|
||||
} else {
|
||||
the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
|
||||
the_controller.ss_hcd->dum = &the_controller;
|
||||
dum->ss_hcd = hcd_to_dummy_hcd(hcd);
|
||||
dum->ss_hcd->dum = dum;
|
||||
hcd->speed = HCD_USB3;
|
||||
hcd->self.root_hub->speed = USB_SPEED_SUPER;
|
||||
}
|
||||
|
|
@ -2524,11 +2531,13 @@ static struct hc_driver dummy_hcd = {
|
|||
|
||||
static int dummy_hcd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dummy *dum;
|
||||
struct usb_hcd *hs_hcd;
|
||||
struct usb_hcd *ss_hcd;
|
||||
int retval;
|
||||
|
||||
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
|
||||
dum = *((void **)dev_get_platdata(&pdev->dev));
|
||||
|
||||
if (!mod_data.is_super_speed)
|
||||
dummy_hcd.flags = HCD_USB2;
|
||||
|
|
@ -2561,7 +2570,7 @@ dealloc_usb2_hcd:
|
|||
usb_remove_hcd(hs_hcd);
|
||||
put_usb2_hcd:
|
||||
usb_put_hcd(hs_hcd);
|
||||
the_controller.hs_hcd = the_controller.ss_hcd = NULL;
|
||||
dum->hs_hcd = dum->ss_hcd = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -2579,8 +2588,8 @@ static int dummy_hcd_remove(struct platform_device *pdev)
|
|||
usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
|
||||
usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
|
||||
|
||||
the_controller.hs_hcd = NULL;
|
||||
the_controller.ss_hcd = NULL;
|
||||
dum->hs_hcd = NULL;
|
||||
dum->ss_hcd = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2627,13 +2636,15 @@ static struct platform_driver dummy_hcd_driver = {
|
|||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct platform_device *the_udc_pdev;
|
||||
static struct platform_device *the_hcd_pdev;
|
||||
#define MAX_NUM_UDC 2
|
||||
static struct platform_device *the_udc_pdev[MAX_NUM_UDC];
|
||||
static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
int i;
|
||||
struct dummy *dum[MAX_NUM_UDC];
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
|
@ -2641,65 +2652,129 @@ static int __init init(void)
|
|||
if (!mod_data.is_high_speed && mod_data.is_super_speed)
|
||||
return -EINVAL;
|
||||
|
||||
the_hcd_pdev = platform_device_alloc(driver_name, -1);
|
||||
if (!the_hcd_pdev)
|
||||
return retval;
|
||||
the_udc_pdev = platform_device_alloc(gadget_name, -1);
|
||||
if (!the_udc_pdev)
|
||||
goto err_alloc_udc;
|
||||
if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) {
|
||||
pr_err("Number of emulated UDC must be in range of 1…%d\n",
|
||||
MAX_NUM_UDC);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
|
||||
if (!the_hcd_pdev[i]) {
|
||||
i--;
|
||||
while (i >= 0)
|
||||
platform_device_put(the_hcd_pdev[i--]);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
the_udc_pdev[i] = platform_device_alloc(gadget_name, i);
|
||||
if (!the_udc_pdev[i]) {
|
||||
i--;
|
||||
while (i >= 0)
|
||||
platform_device_put(the_udc_pdev[i--]);
|
||||
goto err_alloc_udc;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL);
|
||||
if (!dum[i])
|
||||
goto err_add_pdata;
|
||||
retval = platform_device_add_data(the_hcd_pdev[i], &dum[i],
|
||||
sizeof(void *));
|
||||
if (retval)
|
||||
goto err_add_pdata;
|
||||
retval = platform_device_add_data(the_udc_pdev[i], &dum[i],
|
||||
sizeof(void *));
|
||||
if (retval)
|
||||
goto err_add_pdata;
|
||||
}
|
||||
|
||||
retval = platform_driver_register(&dummy_hcd_driver);
|
||||
if (retval < 0)
|
||||
goto err_register_hcd_driver;
|
||||
goto err_add_pdata;
|
||||
retval = platform_driver_register(&dummy_udc_driver);
|
||||
if (retval < 0)
|
||||
goto err_register_udc_driver;
|
||||
|
||||
retval = platform_device_add(the_hcd_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_hcd;
|
||||
if (!the_controller.hs_hcd ||
|
||||
(!the_controller.ss_hcd && mod_data.is_super_speed)) {
|
||||
/*
|
||||
* The hcd was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_add_udc;
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
retval = platform_device_add(the_hcd_pdev[i]);
|
||||
if (retval < 0) {
|
||||
i--;
|
||||
while (i >= 0)
|
||||
platform_device_del(the_hcd_pdev[i--]);
|
||||
goto err_add_hcd;
|
||||
}
|
||||
}
|
||||
retval = platform_device_add(the_udc_pdev);
|
||||
if (retval < 0)
|
||||
goto err_add_udc;
|
||||
if (!platform_get_drvdata(the_udc_pdev)) {
|
||||
/*
|
||||
* The udc was added successfully but its probe function failed
|
||||
* for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_probe_udc;
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
if (!dum[i]->hs_hcd ||
|
||||
(!dum[i]->ss_hcd && mod_data.is_super_speed)) {
|
||||
/*
|
||||
* The hcd was added successfully but its probe
|
||||
* function failed for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_add_udc;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
retval = platform_device_add(the_udc_pdev[i]);
|
||||
if (retval < 0) {
|
||||
i--;
|
||||
while (i >= 0)
|
||||
platform_device_del(the_udc_pdev[i]);
|
||||
goto err_add_udc;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
if (!platform_get_drvdata(the_udc_pdev[i])) {
|
||||
/*
|
||||
* The udc was added successfully but its probe
|
||||
* function failed for some reason.
|
||||
*/
|
||||
retval = -EINVAL;
|
||||
goto err_probe_udc;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
|
||||
err_probe_udc:
|
||||
platform_device_del(the_udc_pdev);
|
||||
for (i = 0; i < mod_data.num; i++)
|
||||
platform_device_del(the_udc_pdev[i]);
|
||||
err_add_udc:
|
||||
platform_device_del(the_hcd_pdev);
|
||||
for (i = 0; i < mod_data.num; i++)
|
||||
platform_device_del(the_hcd_pdev[i]);
|
||||
err_add_hcd:
|
||||
platform_driver_unregister(&dummy_udc_driver);
|
||||
err_register_udc_driver:
|
||||
platform_driver_unregister(&dummy_hcd_driver);
|
||||
err_register_hcd_driver:
|
||||
platform_device_put(the_udc_pdev);
|
||||
err_add_pdata:
|
||||
for (i = 0; i < mod_data.num; i++)
|
||||
kfree(dum[i]);
|
||||
for (i = 0; i < mod_data.num; i++)
|
||||
platform_device_put(the_udc_pdev[i]);
|
||||
err_alloc_udc:
|
||||
platform_device_put(the_hcd_pdev);
|
||||
for (i = 0; i < mod_data.num; i++)
|
||||
platform_device_put(the_hcd_pdev[i]);
|
||||
return retval;
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
static void __exit cleanup(void)
|
||||
{
|
||||
platform_device_unregister(the_udc_pdev);
|
||||
platform_device_unregister(the_hcd_pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mod_data.num; i++) {
|
||||
struct dummy *dum;
|
||||
|
||||
dum = *((void **)dev_get_platdata(&the_udc_pdev[i]->dev));
|
||||
|
||||
platform_device_unregister(the_udc_pdev[i]);
|
||||
platform_device_unregister(the_hcd_pdev[i]);
|
||||
kfree(dum);
|
||||
}
|
||||
platform_driver_unregister(&dummy_udc_driver);
|
||||
platform_driver_unregister(&dummy_hcd_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#include "gadget_chips.h"
|
||||
|
|
@ -87,7 +89,7 @@ static inline struct f_acm *port_to_acm(struct gserial *p)
|
|||
|
||||
/* notification endpoint uses smallish and infrequent fixed-size messages */
|
||||
|
||||
#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
|
||||
#define GS_NOTIFY_INTERVAL_MS 32
|
||||
#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
|
||||
|
||||
/* interface and class descriptors: */
|
||||
|
|
@ -167,7 +169,7 @@ static struct usb_endpoint_descriptor acm_fs_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
|
||||
.bInterval = GS_NOTIFY_INTERVAL_MS,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_fs_in_desc = {
|
||||
|
|
@ -199,14 +201,13 @@ static struct usb_descriptor_header *acm_fs_function[] = {
|
|||
};
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(GS_NOTIFY_INTERVAL_MS),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor acm_hs_in_desc = {
|
||||
|
|
@ -284,7 +285,6 @@ static struct usb_string acm_string_defs[] = {
|
|||
[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
|
||||
[ACM_DATA_IDX].s = "CDC ACM Data",
|
||||
[ACM_IAD_IDX ].s = "CDC Serial",
|
||||
{ /* ZEROES END LIST */ },
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings acm_string_table = {
|
||||
|
|
@ -606,9 +606,23 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
struct usb_string *us;
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
/* REVISIT might want instance-specific strings to help
|
||||
* distinguish instances ...
|
||||
*/
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
us = usb_gstrings_attach(cdev, acm_strings,
|
||||
ARRAY_SIZE(acm_string_defs));
|
||||
if (IS_ERR(us))
|
||||
return PTR_ERR(us);
|
||||
acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id;
|
||||
acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
|
||||
acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;
|
||||
|
||||
/* allocate instance-specific interface IDs, and patch descriptors */
|
||||
status = usb_interface_id(c, f);
|
||||
if (status < 0)
|
||||
|
|
@ -659,37 +673,22 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
acm->notify_req->complete = acm_cdc_notify_complete;
|
||||
acm->notify_req->context = acm;
|
||||
|
||||
/* copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(acm_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
acm_hs_in_desc.bEndpointAddress =
|
||||
acm_fs_in_desc.bEndpointAddress;
|
||||
acm_hs_out_desc.bEndpointAddress =
|
||||
acm_fs_out_desc.bEndpointAddress;
|
||||
acm_hs_notify_desc.bEndpointAddress =
|
||||
acm_fs_notify_desc.bEndpointAddress;
|
||||
acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
|
||||
acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
|
||||
acm_hs_notify_desc.bEndpointAddress =
|
||||
acm_fs_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors */
|
||||
f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
|
||||
}
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
acm_ss_in_desc.bEndpointAddress =
|
||||
acm_fs_in_desc.bEndpointAddress;
|
||||
acm_ss_out_desc.bEndpointAddress =
|
||||
acm_fs_out_desc.bEndpointAddress;
|
||||
acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
|
||||
acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
|
||||
acm_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
|
||||
acm->port_num,
|
||||
|
|
@ -716,27 +715,42 @@ fail:
|
|||
return status;
|
||||
}
|
||||
|
||||
static struct f_acm *acm_alloc_basic_func(void)
|
||||
{
|
||||
struct f_acm *acm;
|
||||
|
||||
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
|
||||
if (!acm)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&acm->lock);
|
||||
|
||||
acm->port.connect = acm_connect;
|
||||
acm->port.disconnect = acm_disconnect;
|
||||
acm->port.send_break = acm_send_break;
|
||||
|
||||
acm->port.func.name = "acm";
|
||||
/* descriptors are per-instance copies */
|
||||
acm->port.func.bind = acm_bind;
|
||||
acm->port.func.set_alt = acm_set_alt;
|
||||
acm->port.func.setup = acm_setup;
|
||||
acm->port.func.disable = acm_disable;
|
||||
|
||||
return acm;
|
||||
}
|
||||
|
||||
#ifdef USB_FACM_INCLUDED
|
||||
static void
|
||||
acm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
usb_free_all_descriptors(f);
|
||||
if (acm->notify_req)
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
/* Some controllers can't support CDC ACM ... */
|
||||
static inline bool can_support_cdc(struct usb_configuration *c)
|
||||
{
|
||||
/* everything else is *probably* fine ... */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* acm_bind_config - add a CDC ACM function to a configuration
|
||||
* @c: the configuration to support the CDC ACM instance
|
||||
|
|
@ -745,70 +759,80 @@ static inline bool can_support_cdc(struct usb_configuration *c)
|
|||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gserial_setup() with enough ports to
|
||||
* handle all the ones it binds. Caller is also responsible
|
||||
* for calling @gserial_cleanup() before module unload.
|
||||
*/
|
||||
int acm_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
struct f_acm *acm;
|
||||
int status;
|
||||
|
||||
if (!can_support_cdc(c))
|
||||
return -EINVAL;
|
||||
|
||||
/* REVISIT might want instance-specific strings to help
|
||||
* distinguish instances ...
|
||||
*/
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
acm_string_defs[ACM_CTRL_IDX].id = status;
|
||||
|
||||
acm_control_interface_desc.iInterface = status;
|
||||
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
acm_string_defs[ACM_DATA_IDX].id = status;
|
||||
|
||||
acm_data_interface_desc.iInterface = status;
|
||||
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
acm_string_defs[ACM_IAD_IDX].id = status;
|
||||
|
||||
acm_iad_descriptor.iFunction = status;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
acm = kzalloc(sizeof *acm, GFP_KERNEL);
|
||||
acm = acm_alloc_basic_func();
|
||||
if (!acm)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&acm->lock);
|
||||
|
||||
acm->port_num = port_num;
|
||||
|
||||
acm->port.connect = acm_connect;
|
||||
acm->port.disconnect = acm_disconnect;
|
||||
acm->port.send_break = acm_send_break;
|
||||
|
||||
acm->port.func.name = "acm";
|
||||
acm->port.func.strings = acm_strings;
|
||||
/* descriptors are per-instance copies */
|
||||
acm->port.func.bind = acm_bind;
|
||||
acm->port.func.unbind = acm_unbind;
|
||||
acm->port.func.set_alt = acm_set_alt;
|
||||
acm->port.func.setup = acm_setup;
|
||||
acm->port.func.disable = acm_disable;
|
||||
acm->port.func.unbind = acm_old_unbind;
|
||||
|
||||
status = usb_add_function(c, &acm->port.func);
|
||||
if (status)
|
||||
kfree(acm);
|
||||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
|
||||
acm_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
if (acm->notify_req)
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
}
|
||||
|
||||
static void acm_free_func(struct usb_function *f)
|
||||
{
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
struct f_acm *acm;
|
||||
|
||||
acm = acm_alloc_basic_func();
|
||||
if (!acm)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
acm->port_num = opts->port_num;
|
||||
acm->port.func.unbind = acm_unbind;
|
||||
acm->port.func.free_func = acm_free_func;
|
||||
|
||||
return &acm->port.func;
|
||||
}
|
||||
|
||||
static void acm_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *acm_alloc_instance(void)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
opts->func_inst.free_func_inst = acm_free_instance;
|
||||
return &opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g)
|
|||
* encapsulated commands (vendor-specific, using control-OUT).
|
||||
*/
|
||||
|
||||
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
|
||||
#define ECM_STATUS_INTERVAL_MS 32
|
||||
#define ECM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
|
||||
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ static struct usb_endpoint_descriptor fs_ecm_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
.bInterval = ECM_STATUS_INTERVAL_MS,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ecm_in_desc = {
|
||||
|
|
@ -239,7 +239,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_ecm_in_desc = {
|
||||
|
|
@ -288,7 +288,7 @@ static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS),
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = {
|
||||
|
|
@ -330,6 +330,7 @@ static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = {
|
|||
|
||||
static struct usb_descriptor_header *ecm_ss_function[] = {
|
||||
/* CDC ECM control descriptors */
|
||||
(struct usb_descriptor_header *) &ecm_iad_descriptor,
|
||||
(struct usb_descriptor_header *) &ecm_control_intf,
|
||||
(struct usb_descriptor_header *) &ecm_header_desc,
|
||||
(struct usb_descriptor_header *) &ecm_union_desc,
|
||||
|
|
@ -353,7 +354,7 @@ static struct usb_descriptor_header *ecm_ss_function[] = {
|
|||
|
||||
static struct usb_string ecm_string_defs[] = {
|
||||
[0].s = "CDC Ethernet Control Model (ECM)",
|
||||
[1].s = NULL /* DYNAMIC */,
|
||||
[1].s = "",
|
||||
[2].s = "CDC Ethernet Data",
|
||||
[3].s = "CDC ECM",
|
||||
{ } /* end of list */
|
||||
|
|
@ -742,42 +743,24 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
ecm->notify_req->context = ecm;
|
||||
ecm->notify_req->complete = ecm_notify_complete;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(ecm_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_ecm_in_desc.bEndpointAddress =
|
||||
fs_ecm_in_desc.bEndpointAddress;
|
||||
hs_ecm_out_desc.bEndpointAddress =
|
||||
fs_ecm_out_desc.bEndpointAddress;
|
||||
hs_ecm_notify_desc.bEndpointAddress =
|
||||
fs_ecm_notify_desc.bEndpointAddress;
|
||||
hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
|
||||
hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
|
||||
hs_ecm_notify_desc.bEndpointAddress =
|
||||
fs_ecm_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
|
||||
ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
|
||||
ss_ecm_notify_desc.bEndpointAddress =
|
||||
fs_ecm_notify_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_ecm_in_desc.bEndpointAddress =
|
||||
fs_ecm_in_desc.bEndpointAddress;
|
||||
ss_ecm_out_desc.bEndpointAddress =
|
||||
fs_ecm_out_desc.bEndpointAddress;
|
||||
ss_ecm_notify_desc.bEndpointAddress =
|
||||
fs_ecm_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
|
||||
ecm_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* NOTE: all that is done without knowing or caring about
|
||||
* the network link ... which is unavailable to this code
|
||||
|
|
@ -795,11 +778,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
if (f->hs_descriptors)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
|
||||
if (ecm->notify_req) {
|
||||
kfree(ecm->notify_req->buf);
|
||||
usb_ep_free_request(ecm->notify, ecm->notify_req);
|
||||
|
|
@ -808,9 +786,9 @@ fail:
|
|||
/* we might as well release our claims on endpoints */
|
||||
if (ecm->notify)
|
||||
ecm->notify->driver_data = NULL;
|
||||
if (ecm->port.out_ep->desc)
|
||||
if (ecm->port.out_ep)
|
||||
ecm->port.out_ep->driver_data = NULL;
|
||||
if (ecm->port.in_ep->desc)
|
||||
if (ecm->port.in_ep)
|
||||
ecm->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
|
@ -825,16 +803,11 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
DBG(c->cdev, "ecm unbind\n");
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
ecm_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(ecm->notify_req->buf);
|
||||
usb_ep_free_request(ecm->notify, ecm->notify_req);
|
||||
|
||||
ecm_string_defs[1].s = NULL;
|
||||
kfree(ecm);
|
||||
}
|
||||
|
||||
|
|
@ -859,36 +832,15 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
|
||||
return -EINVAL;
|
||||
|
||||
/* maybe allocate device-global string IDs */
|
||||
if (ecm_string_defs[0].id == 0) {
|
||||
|
||||
/* control interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
status = usb_string_ids_tab(c->cdev, ecm_string_defs);
|
||||
if (status)
|
||||
return status;
|
||||
ecm_string_defs[0].id = status;
|
||||
ecm_control_intf.iInterface = status;
|
||||
|
||||
/* data interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ecm_string_defs[2].id = status;
|
||||
ecm_data_intf.iInterface = status;
|
||||
|
||||
/* MAC address */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ecm_string_defs[1].id = status;
|
||||
ecm_desc.iMACAddress = status;
|
||||
|
||||
/* IAD label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ecm_string_defs[3].id = status;
|
||||
ecm_iad_descriptor.iFunction = status;
|
||||
ecm_control_intf.iInterface = ecm_string_defs[0].id;
|
||||
ecm_data_intf.iInterface = ecm_string_defs[2].id;
|
||||
ecm_desc.iMACAddress = ecm_string_defs[1].id;
|
||||
ecm_iad_descriptor.iFunction = ecm_string_defs[3].id;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
|
|
@ -913,9 +865,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
ecm->port.func.disable = ecm_disable;
|
||||
|
||||
status = usb_add_function(c, &ecm->port.func);
|
||||
if (status) {
|
||||
ecm_string_defs[1].s = NULL;
|
||||
if (status)
|
||||
kfree(ecm);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,38 +274,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
status = -ENOMEM;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(eem_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
eem_hs_in_desc.bEndpointAddress =
|
||||
eem_fs_in_desc.bEndpointAddress;
|
||||
eem_hs_out_desc.bEndpointAddress =
|
||||
eem_fs_out_desc.bEndpointAddress;
|
||||
eem_hs_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
|
||||
eem_hs_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
eem_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
|
||||
eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
eem_ss_in_desc.bEndpointAddress =
|
||||
eem_fs_in_desc.bEndpointAddress;
|
||||
eem_ss_out_desc.bEndpointAddress =
|
||||
eem_fs_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
|
||||
eem_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
|
|
@ -314,15 +296,10 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
if (f->hs_descriptors)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (eem->port.out_ep->desc)
|
||||
usb_free_all_descriptors(f);
|
||||
if (eem->port.out_ep)
|
||||
eem->port.out_ep->driver_data = NULL;
|
||||
if (eem->port.in_ep->desc)
|
||||
if (eem->port.in_ep)
|
||||
eem->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
|
@ -337,11 +314,7 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
DBG(c->cdev, "eem unbind\n");
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(eem);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1103,8 +1103,8 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
|||
return 0;
|
||||
|
||||
for (;;) {
|
||||
char *end, *eq, *comma;
|
||||
unsigned long value;
|
||||
char *eq, *comma;
|
||||
|
||||
/* Option limit */
|
||||
comma = strchr(opts, ',');
|
||||
|
|
@ -1120,8 +1120,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
|||
*eq = 0;
|
||||
|
||||
/* Parse value */
|
||||
value = simple_strtoul(eq + 1, &end, 0);
|
||||
if (unlikely(*end != ',' && *end != 0)) {
|
||||
if (kstrtoul(eq + 1, 0, &value)) {
|
||||
pr_err("%s: invalid value: %s\n", opts, eq + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1153,15 +1152,15 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
|||
pr_err("%s: unmapped value: %lu\n", opts, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else if (!memcmp(opts, "gid", 3))
|
||||
} else if (!memcmp(opts, "gid", 3)) {
|
||||
data->perms.gid = make_kgid(current_user_ns(), value);
|
||||
if (!gid_valid(data->perms.gid)) {
|
||||
pr_err("%s: unmapped value: %lu\n", opts, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1236,6 +1235,7 @@ static struct file_system_type ffs_fs_type = {
|
|||
.mount = ffs_fs_mount,
|
||||
.kill_sb = ffs_fs_kill_sb,
|
||||
};
|
||||
MODULE_ALIAS_FS("functionfs");
|
||||
|
||||
|
||||
/* Driver's main init/cleanup functions *************************************/
|
||||
|
|
@ -2097,7 +2097,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
|||
if (isHS)
|
||||
func->function.hs_descriptors[(long)valuep] = desc;
|
||||
else
|
||||
func->function.descriptors[(long)valuep] = desc;
|
||||
func->function.fs_descriptors[(long)valuep] = desc;
|
||||
|
||||
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
|
||||
return 0;
|
||||
|
|
@ -2249,7 +2249,7 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|||
* numbers without worrying that it may be described later on.
|
||||
*/
|
||||
if (likely(full)) {
|
||||
func->function.descriptors = data->fs_descs;
|
||||
func->function.fs_descriptors = data->fs_descs;
|
||||
ret = ffs_do_descs(ffs->fs_descs_count,
|
||||
data->raw_descs,
|
||||
sizeof data->raw_descs,
|
||||
|
|
|
|||
|
|
@ -573,7 +573,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
goto fail;
|
||||
hidg_interface_desc.bInterfaceNumber = status;
|
||||
|
||||
|
||||
/* allocate instance-specific endpoints */
|
||||
status = -ENODEV;
|
||||
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
|
||||
|
|
@ -609,20 +608,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
hidg_desc.desc[0].wDescriptorLength =
|
||||
cpu_to_le16(hidg->report_desc_length);
|
||||
|
||||
/* copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
hidg_hs_in_ep_desc.bEndpointAddress =
|
||||
hidg_fs_in_ep_desc.bEndpointAddress;
|
||||
hidg_hs_out_ep_desc.bEndpointAddress =
|
||||
hidg_fs_out_ep_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hidg_hs_in_ep_desc.bEndpointAddress =
|
||||
hidg_fs_in_ep_desc.bEndpointAddress;
|
||||
hidg_hs_out_ep_desc.bEndpointAddress =
|
||||
hidg_fs_out_ep_desc.bEndpointAddress;
|
||||
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, hidg_fs_descriptors,
|
||||
hidg_hs_descriptors, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
mutex_init(&hidg->lock);
|
||||
spin_lock_init(&hidg->spinlock);
|
||||
|
|
@ -649,9 +643,7 @@ fail:
|
|||
usb_ep_free_request(hidg->in_ep, hidg->req);
|
||||
}
|
||||
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -668,9 +660,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
kfree(hidg->req->buf);
|
||||
usb_ep_free_request(hidg->in_ep, hidg->req);
|
||||
|
||||
/* free descriptors copies */
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(hidg->report_desc);
|
||||
kfree(hidg);
|
||||
|
|
|
|||
|
|
@ -15,10 +15,11 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
#include "g_zero.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
/*
|
||||
* LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
|
||||
|
|
@ -44,9 +45,8 @@ static inline struct f_loopback *func_to_loop(struct usb_function *f)
|
|||
return container_of(f, struct f_loopback, function);
|
||||
}
|
||||
|
||||
static unsigned qlen = 32;
|
||||
module_param(qlen, uint, 0);
|
||||
MODULE_PARM_DESC(qlenn, "depth of loopback queue");
|
||||
static unsigned qlen;
|
||||
static unsigned buflen;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -171,12 +171,12 @@ static struct usb_gadget_strings *loopback_strings[] = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init
|
||||
loopback_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_loopback *loop = func_to_loop(f);
|
||||
int id;
|
||||
int ret;
|
||||
|
||||
/* allocate interface ID(s) */
|
||||
id = usb_interface_id(c, f);
|
||||
|
|
@ -184,6 +184,12 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return id;
|
||||
loopback_intf.bInterfaceNumber = id;
|
||||
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
strings_loopback[0].id = id;
|
||||
loopback_intf.iInterface = id;
|
||||
|
||||
/* allocate endpoints */
|
||||
|
||||
loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
|
||||
|
|
@ -201,22 +207,19 @@ autoconf_fail:
|
|||
loop->out_ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_loop_source_desc.bEndpointAddress =
|
||||
fs_loop_source_desc.bEndpointAddress;
|
||||
hs_loop_sink_desc.bEndpointAddress =
|
||||
fs_loop_sink_desc.bEndpointAddress;
|
||||
f->hs_descriptors = hs_loopback_descs;
|
||||
}
|
||||
hs_loop_source_desc.bEndpointAddress =
|
||||
fs_loop_source_desc.bEndpointAddress;
|
||||
hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
|
||||
|
||||
/* support super speed hardware */
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_loop_source_desc.bEndpointAddress =
|
||||
fs_loop_source_desc.bEndpointAddress;
|
||||
ss_loop_sink_desc.bEndpointAddress =
|
||||
fs_loop_sink_desc.bEndpointAddress;
|
||||
f->ss_descriptors = ss_loopback_descs;
|
||||
}
|
||||
ss_loop_source_desc.bEndpointAddress =
|
||||
fs_loop_source_desc.bEndpointAddress;
|
||||
ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
|
||||
ss_loopback_descs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
|
||||
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
|
|
@ -225,9 +228,9 @@ autoconf_fail:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
loopback_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
static void lb_free_func(struct usb_function *f)
|
||||
{
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_loop(f));
|
||||
}
|
||||
|
||||
|
|
@ -367,64 +370,64 @@ static void loopback_disable(struct usb_function *f)
|
|||
disable_loopback(loop);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init loopback_bind_config(struct usb_configuration *c)
|
||||
static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_loopback *loop;
|
||||
int status;
|
||||
struct f_lb_opts *lb_opts;
|
||||
|
||||
loop = kzalloc(sizeof *loop, GFP_KERNEL);
|
||||
if (!loop)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
lb_opts = container_of(fi, struct f_lb_opts, func_inst);
|
||||
buflen = lb_opts->bulk_buflen;
|
||||
qlen = lb_opts->qlen;
|
||||
if (!qlen)
|
||||
qlen = 32;
|
||||
|
||||
loop->function.name = "loopback";
|
||||
loop->function.descriptors = fs_loopback_descs;
|
||||
loop->function.bind = loopback_bind;
|
||||
loop->function.unbind = loopback_unbind;
|
||||
loop->function.set_alt = loopback_set_alt;
|
||||
loop->function.disable = loopback_disable;
|
||||
loop->function.strings = loopback_strings;
|
||||
|
||||
status = usb_add_function(c, &loop->function);
|
||||
if (status)
|
||||
kfree(loop);
|
||||
return status;
|
||||
loop->function.free_func = lb_free_func;
|
||||
|
||||
return &loop->function;
|
||||
}
|
||||
|
||||
static struct usb_configuration loopback_driver = {
|
||||
.label = "loopback",
|
||||
.strings = loopback_strings,
|
||||
.bConfigurationValue = 2,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
};
|
||||
|
||||
/**
|
||||
* loopback_add - add a loopback testing configuration to a device
|
||||
* @cdev: the device to support the loopback configuration
|
||||
*/
|
||||
int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
static void lb_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
int id;
|
||||
struct f_lb_opts *lb_opts;
|
||||
|
||||
/* allocate string ID(s) */
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
strings_loopback[0].id = id;
|
||||
|
||||
loopback_intf.iInterface = id;
|
||||
loopback_driver.iConfiguration = id;
|
||||
|
||||
/* support autoresume for remote wakeup testing */
|
||||
if (autoresume)
|
||||
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* support OTG systems */
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
loopback_driver.descriptors = otg_desc;
|
||||
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return usb_add_config(cdev, &loopback_driver, loopback_bind_config);
|
||||
lb_opts = container_of(fi, struct f_lb_opts, func_inst);
|
||||
kfree(lb_opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *loopback_alloc_instance(void)
|
||||
{
|
||||
struct f_lb_opts *lb_opts;
|
||||
|
||||
lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
|
||||
if (!lb_opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
lb_opts->func_inst.free_func_inst = lb_free_instance;
|
||||
return &lb_opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
|
||||
|
||||
int __init lb_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_function_register(&Loopbackusb_func);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
void __exit lb_modexit(void)
|
||||
{
|
||||
usb_function_unregister(&Loopbackusb_func);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -228,10 +228,6 @@
|
|||
|
||||
static const char fsg_string_interface[] = "Mass Storage";
|
||||
|
||||
#define FSG_NO_DEVICE_STRINGS 1
|
||||
#define FSG_NO_OTG 1
|
||||
#define FSG_NO_INTR_EP 1
|
||||
|
||||
#include "storage_common.c"
|
||||
|
||||
|
||||
|
|
@ -250,20 +246,6 @@ struct fsg_operations {
|
|||
* set).
|
||||
*/
|
||||
int (*thread_exits)(struct fsg_common *common);
|
||||
|
||||
/*
|
||||
* Called prior to ejection. Negative return means error,
|
||||
* zero means to continue with ejection, positive means not to
|
||||
* eject.
|
||||
*/
|
||||
int (*pre_eject)(struct fsg_common *common,
|
||||
struct fsg_lun *lun, int num);
|
||||
/*
|
||||
* Called after ejection. Negative return means error, zero
|
||||
* or positive is just a success.
|
||||
*/
|
||||
int (*post_eject)(struct fsg_common *common,
|
||||
struct fsg_lun *lun, int num);
|
||||
};
|
||||
|
||||
/* Data shared by all the FSG instances. */
|
||||
|
|
@ -996,7 +978,7 @@ static int do_synchronize_cache(struct fsg_common *common)
|
|||
static void invalidate_sub(struct fsg_lun *curlun)
|
||||
{
|
||||
struct file *filp = curlun->filp;
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
struct inode *inode = file_inode(filp);
|
||||
unsigned long rc;
|
||||
|
||||
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
|
||||
|
|
@ -1378,26 +1360,13 @@ static int do_start_stop(struct fsg_common *common)
|
|||
if (!loej)
|
||||
return 0;
|
||||
|
||||
/* Simulate an unload/eject */
|
||||
if (common->ops && common->ops->pre_eject) {
|
||||
int r = common->ops->pre_eject(common, curlun,
|
||||
curlun - common->luns);
|
||||
if (unlikely(r < 0))
|
||||
return r;
|
||||
else if (r)
|
||||
return 0;
|
||||
}
|
||||
|
||||
up_read(&common->filesem);
|
||||
down_write(&common->filesem);
|
||||
fsg_lun_close(curlun);
|
||||
up_write(&common->filesem);
|
||||
down_read(&common->filesem);
|
||||
|
||||
return common->ops && common->ops->post_eject
|
||||
? min(0, common->ops->post_eject(common, curlun,
|
||||
curlun - common->luns))
|
||||
: 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_prevent_allow(struct fsg_common *common)
|
||||
|
|
@ -1722,7 +1691,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
int needs_medium, const char *name)
|
||||
{
|
||||
int i;
|
||||
int lun = common->cmnd[1] >> 5;
|
||||
unsigned int lun = common->cmnd[1] >> 5;
|
||||
static const char dirletter[4] = {'u', 'o', 'i', 'n'};
|
||||
char hdlen[20];
|
||||
struct fsg_lun *curlun;
|
||||
|
|
@ -1788,7 +1757,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
|
||||
/* Check that the LUN values are consistent */
|
||||
if (common->lun != lun)
|
||||
DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
|
||||
DBG(common, "using LUN %u from CBW, not LUN %u from CDB\n",
|
||||
common->lun, lun);
|
||||
|
||||
/* Check the LUN */
|
||||
|
|
@ -1808,7 +1777,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
*/
|
||||
if (common->cmnd[0] != INQUIRY &&
|
||||
common->cmnd[0] != REQUEST_SENSE) {
|
||||
DBG(common, "unsupported LUN %d\n", common->lun);
|
||||
DBG(common, "unsupported LUN %u\n", common->lun);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -2200,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
if (common->data_size == 0)
|
||||
common->data_dir = DATA_DIR_NONE;
|
||||
common->lun = cbw->Lun;
|
||||
if (common->lun >= 0 && common->lun < common->nluns)
|
||||
if (common->lun < common->nluns)
|
||||
common->curlun = &common->luns[common->lun];
|
||||
else
|
||||
common->curlun = NULL;
|
||||
|
|
@ -2904,9 +2873,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
}
|
||||
|
||||
fsg_common_put(common);
|
||||
usb_free_descriptors(fsg->function.descriptors);
|
||||
usb_free_descriptors(fsg->function.hs_descriptors);
|
||||
usb_free_descriptors(fsg->function.ss_descriptors);
|
||||
usb_free_all_descriptors(&fsg->function);
|
||||
kfree(fsg);
|
||||
}
|
||||
|
||||
|
|
@ -2916,6 +2883,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
struct usb_gadget *gadget = c->cdev->gadget;
|
||||
int i;
|
||||
struct usb_ep *ep;
|
||||
unsigned max_burst;
|
||||
int ret;
|
||||
|
||||
fsg->gadget = gadget;
|
||||
|
||||
|
|
@ -2939,45 +2908,27 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
ep->driver_data = fsg->common; /* claim the endpoint */
|
||||
fsg->bulk_out = ep;
|
||||
|
||||
/* Copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(fsg_fs_function);
|
||||
if (unlikely(!f->descriptors))
|
||||
return -ENOMEM;
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
fsg_hs_bulk_in_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
fsg_hs_bulk_out_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_out_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
/* Assume endpoint addresses are the same for both speeds */
|
||||
fsg_hs_bulk_in_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
fsg_hs_bulk_out_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_out_desc.bEndpointAddress;
|
||||
f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
|
||||
if (unlikely(!f->hs_descriptors)) {
|
||||
usb_free_descriptors(f->descriptors);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
/* Calculate bMaxBurst, we know packet size is 1024 */
|
||||
max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
|
||||
|
||||
if (gadget_is_superspeed(gadget)) {
|
||||
unsigned max_burst;
|
||||
fsg_ss_bulk_in_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
|
||||
|
||||
/* Calculate bMaxBurst, we know packet size is 1024 */
|
||||
max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
|
||||
fsg_ss_bulk_out_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_out_desc.bEndpointAddress;
|
||||
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
|
||||
|
||||
fsg_ss_bulk_in_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_in_desc.bEndpointAddress;
|
||||
fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
|
||||
|
||||
fsg_ss_bulk_out_desc.bEndpointAddress =
|
||||
fsg_fs_bulk_out_desc.bEndpointAddress;
|
||||
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
|
||||
|
||||
f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
|
||||
if (unlikely(!f->ss_descriptors)) {
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function,
|
||||
fsg_ss_function);
|
||||
if (ret)
|
||||
goto autoconf_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -2986,7 +2937,6 @@ autoconf_fail:
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
/****************************** ADD FUNCTION ******************************/
|
||||
|
||||
static struct usb_gadget_strings *fsg_strings_array[] = {
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
kfree(midi->id);
|
||||
midi->id = NULL;
|
||||
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(midi);
|
||||
}
|
||||
|
||||
|
|
@ -881,19 +881,25 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
* both speeds
|
||||
*/
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->fs_descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->fs_descriptors)
|
||||
goto fail_f_midi;
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
c->highspeed = true;
|
||||
bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
f->hs_descriptors = usb_copy_descriptors(midi_function);
|
||||
} else {
|
||||
f->descriptors = usb_copy_descriptors(midi_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail_f_midi;
|
||||
}
|
||||
|
||||
kfree(midi_function);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_f_midi:
|
||||
kfree(midi_function);
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
fail:
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (midi->out_ep)
|
||||
|
|
|
|||
|
|
@ -56,8 +56,9 @@ struct f_ncm {
|
|||
u8 notify_state;
|
||||
bool is_open;
|
||||
|
||||
struct ndp_parser_opts *parser_opts;
|
||||
const struct ndp_parser_opts *parser_opts;
|
||||
bool is_crc;
|
||||
u32 ndp_sign;
|
||||
|
||||
/*
|
||||
* for notification, it is accessed from both
|
||||
|
|
@ -102,7 +103,7 @@ static inline unsigned ncm_bitrate(struct usb_gadget *g)
|
|||
USB_CDC_NCM_NTB32_SUPPORTED)
|
||||
|
||||
static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
|
||||
.wLength = sizeof ntb_parameters,
|
||||
.wLength = cpu_to_le16(sizeof(ntb_parameters)),
|
||||
.bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
|
||||
.dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
|
||||
.wNdpInDivisor = cpu_to_le16(4),
|
||||
|
|
@ -121,7 +122,7 @@ static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
|
|||
* waste less bandwidth.
|
||||
*/
|
||||
|
||||
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
|
||||
#define NCM_STATUS_INTERVAL_MS 32
|
||||
#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
|
||||
|
||||
static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
|
||||
|
|
@ -230,7 +231,7 @@ static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
.bInterval = NCM_STATUS_INTERVAL_MS,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
|
||||
|
|
@ -275,7 +276,7 @@ static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS),
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
|
|
@ -321,7 +322,7 @@ static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
|
|||
|
||||
static struct usb_string ncm_string_defs[] = {
|
||||
[STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
|
||||
[STRING_MAC_IDX].s = NULL /* DYNAMIC */,
|
||||
[STRING_MAC_IDX].s = "",
|
||||
[STRING_DATA_IDX].s = "CDC Network Data",
|
||||
[STRING_IAD_IDX].s = "CDC NCM",
|
||||
{ } /* end of list */
|
||||
|
|
@ -390,8 +391,8 @@ struct ndp_parser_opts {
|
|||
.next_fp_index = 2, \
|
||||
}
|
||||
|
||||
static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
|
||||
static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
|
||||
static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
|
||||
static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
|
||||
|
||||
static inline void put_ncm(__le16 **p, unsigned size, unsigned val)
|
||||
{
|
||||
|
|
@ -732,8 +733,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
default:
|
||||
goto invalid;
|
||||
}
|
||||
ncm->parser_opts->ndp_sign &= ~NCM_NDP_HDR_CRC_MASK;
|
||||
ncm->parser_opts->ndp_sign |= ndp_hdr_crc;
|
||||
ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc;
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -869,15 +869,19 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
|
|||
struct sk_buff *skb2;
|
||||
int ncb_len = 0;
|
||||
__le16 *tmp;
|
||||
int div = ntb_parameters.wNdpInDivisor;
|
||||
int rem = ntb_parameters.wNdpInPayloadRemainder;
|
||||
int div;
|
||||
int rem;
|
||||
int pad;
|
||||
int ndp_align = ntb_parameters.wNdpInAlignment;
|
||||
int ndp_align;
|
||||
int ndp_pad;
|
||||
unsigned max_size = ncm->port.fixed_in_len;
|
||||
struct ndp_parser_opts *opts = ncm->parser_opts;
|
||||
const struct ndp_parser_opts *opts = ncm->parser_opts;
|
||||
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
|
||||
|
||||
div = le16_to_cpu(ntb_parameters.wNdpInDivisor);
|
||||
rem = le16_to_cpu(ntb_parameters.wNdpInPayloadRemainder);
|
||||
ndp_align = le16_to_cpu(ntb_parameters.wNdpInAlignment);
|
||||
|
||||
ncb_len += opts->nth_size;
|
||||
ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len;
|
||||
ncb_len += ndp_pad;
|
||||
|
|
@ -917,7 +921,7 @@ static struct sk_buff *ncm_wrap_ntb(struct gether *port,
|
|||
tmp = (void *)tmp + ndp_pad;
|
||||
|
||||
/* NDP */
|
||||
put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */
|
||||
put_unaligned_le32(ncm->ndp_sign, tmp); /* dwSignature */
|
||||
tmp += 2;
|
||||
/* wLength */
|
||||
put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++);
|
||||
|
|
@ -961,7 +965,7 @@ static int ncm_unwrap_ntb(struct gether *port,
|
|||
struct sk_buff *skb2;
|
||||
int ret = -EINVAL;
|
||||
unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
|
||||
struct ndp_parser_opts *opts = ncm->parser_opts;
|
||||
const struct ndp_parser_opts *opts = ncm->parser_opts;
|
||||
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
|
||||
int dgram_counter;
|
||||
|
||||
|
|
@ -998,7 +1002,7 @@ static int ncm_unwrap_ntb(struct gether *port,
|
|||
|
||||
/* walk through NDP */
|
||||
tmp = ((void *)skb->data) + index;
|
||||
if (get_unaligned_le32(tmp) != opts->ndp_sign) {
|
||||
if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
|
||||
INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -1208,30 +1212,18 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
ncm->notify_req->context = ncm;
|
||||
ncm->notify_req->complete = ncm_notify_complete;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(ncm_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_ncm_in_desc.bEndpointAddress =
|
||||
fs_ncm_in_desc.bEndpointAddress;
|
||||
hs_ncm_out_desc.bEndpointAddress =
|
||||
fs_ncm_out_desc.bEndpointAddress;
|
||||
hs_ncm_notify_desc.bEndpointAddress =
|
||||
fs_ncm_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
|
||||
hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
|
||||
hs_ncm_notify_desc.bEndpointAddress =
|
||||
fs_ncm_notify_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
|
||||
NULL);
|
||||
/*
|
||||
* NOTE: all that is done without knowing or caring about
|
||||
* the network link ... which is unavailable to this code
|
||||
|
|
@ -1248,9 +1240,7 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
if (ncm->notify_req) {
|
||||
kfree(ncm->notify_req->buf);
|
||||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
|
|
@ -1259,9 +1249,9 @@ fail:
|
|||
/* we might as well release our claims on endpoints */
|
||||
if (ncm->notify)
|
||||
ncm->notify->driver_data = NULL;
|
||||
if (ncm->port.out_ep->desc)
|
||||
if (ncm->port.out_ep)
|
||||
ncm->port.out_ep->driver_data = NULL;
|
||||
if (ncm->port.in_ep->desc)
|
||||
if (ncm->port.in_ep)
|
||||
ncm->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
|
@ -1276,14 +1266,12 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
DBG(c->cdev, "ncm unbind\n");
|
||||
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
ncm_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(ncm->notify_req->buf);
|
||||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
|
||||
ncm_string_defs[1].s = NULL;
|
||||
kfree(ncm);
|
||||
}
|
||||
|
||||
|
|
@ -1307,37 +1295,19 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
|
||||
return -EINVAL;
|
||||
|
||||
/* maybe allocate device-global string IDs */
|
||||
if (ncm_string_defs[0].id == 0) {
|
||||
|
||||
/* control interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
status = usb_string_ids_tab(c->cdev, ncm_string_defs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ncm_string_defs[STRING_CTRL_IDX].id = status;
|
||||
ncm_control_intf.iInterface = status;
|
||||
ncm_control_intf.iInterface =
|
||||
ncm_string_defs[STRING_CTRL_IDX].id;
|
||||
|
||||
/* data interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ncm_string_defs[STRING_DATA_IDX].id = status;
|
||||
status = ncm_string_defs[STRING_DATA_IDX].id;
|
||||
ncm_data_nop_intf.iInterface = status;
|
||||
ncm_data_intf.iInterface = status;
|
||||
|
||||
/* MAC address */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ncm_string_defs[STRING_MAC_IDX].id = status;
|
||||
ecm_desc.iMACAddress = status;
|
||||
|
||||
/* IAD */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
ncm_string_defs[STRING_IAD_IDX].id = status;
|
||||
ncm_iad_desc.iFunction = status;
|
||||
ecm_desc.iMACAddress = ncm_string_defs[STRING_MAC_IDX].id;
|
||||
ncm_iad_desc.iFunction = ncm_string_defs[STRING_IAD_IDX].id;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
|
|
@ -1347,7 +1317,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
|
||||
/* export host's Ethernet address in CDC format */
|
||||
snprintf(ncm->ethaddr, sizeof ncm->ethaddr, "%pm", ethaddr);
|
||||
ncm_string_defs[1].s = ncm->ethaddr;
|
||||
ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
|
||||
|
||||
spin_lock_init(&ncm->lock);
|
||||
ncm_reset_values(ncm);
|
||||
|
|
@ -1367,9 +1337,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
ncm->port.unwrap = ncm_unwrap_ntb;
|
||||
|
||||
status = usb_add_function(c, &ncm->port.func);
|
||||
if (status) {
|
||||
ncm_string_defs[1].s = NULL;
|
||||
if (status)
|
||||
kfree(ncm);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,23 +331,19 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
obex->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(fs_function);
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
|
||||
obex_hs_ep_in_desc.bEndpointAddress =
|
||||
obex_fs_ep_in_desc.bEndpointAddress;
|
||||
obex_hs_ep_out_desc.bEndpointAddress =
|
||||
obex_fs_ep_out_desc.bEndpointAddress;
|
||||
obex_hs_ep_in_desc.bEndpointAddress =
|
||||
obex_fs_ep_in_desc.bEndpointAddress;
|
||||
obex_hs_ep_out_desc.bEndpointAddress =
|
||||
obex_fs_ep_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(hs_function);
|
||||
}
|
||||
status = usb_assign_descriptors(f, fs_function, hs_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* Avoid letting this gadget enumerate until the userspace
|
||||
* OBEX server is active.
|
||||
|
|
@ -368,6 +364,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
usb_free_all_descriptors(f);
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (obex->port.out)
|
||||
obex->port.out->driver_data = NULL;
|
||||
|
|
@ -382,9 +379,8 @@ fail:
|
|||
static void
|
||||
obex_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
obex_string_defs[OBEX_CTRL_IDX].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_obex(f));
|
||||
}
|
||||
|
||||
|
|
@ -410,10 +406,6 @@ static inline bool can_support_obex(struct usb_configuration *c)
|
|||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gserial_setup() with enough ports to
|
||||
* handle all the ones it binds. Caller is also responsible
|
||||
* for calling @gserial_cleanup() before module unload.
|
||||
*/
|
||||
int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
|
|
@ -423,22 +415,16 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
|
|||
if (!can_support_obex(c))
|
||||
return -EINVAL;
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
status = usb_string_ids_tab(c->cdev, obex_string_defs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
obex_string_defs[OBEX_CTRL_IDX].id = status;
|
||||
obex_control_intf.iInterface =
|
||||
obex_string_defs[OBEX_CTRL_IDX].id;
|
||||
|
||||
obex_control_intf.iInterface = status;
|
||||
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
obex_string_defs[OBEX_DATA_IDX].id = status;
|
||||
|
||||
obex_data_nop_intf.iInterface =
|
||||
obex_data_intf.iInterface = status;
|
||||
status = obex_string_defs[OBEX_DATA_IDX].id;
|
||||
obex_data_nop_intf.iInterface = status;
|
||||
obex_data_intf.iInterface = status;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
|
|
|
|||
|
|
@ -515,14 +515,14 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
fp->in_ep = ep;
|
||||
ep->driver_data = fp; /* Claim */
|
||||
|
||||
pn_hs_sink_desc.bEndpointAddress =
|
||||
pn_fs_sink_desc.bEndpointAddress;
|
||||
pn_hs_source_desc.bEndpointAddress =
|
||||
pn_fs_source_desc.bEndpointAddress;
|
||||
pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
|
||||
pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
|
||||
|
||||
/* Do not try to bind Phonet twice... */
|
||||
fp->function.descriptors = fs_pn_function;
|
||||
fp->function.hs_descriptors = hs_pn_function;
|
||||
status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
|
||||
NULL);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
/* Incoming USB requests */
|
||||
status = -ENOMEM;
|
||||
|
|
@ -531,7 +531,7 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto err;
|
||||
goto err_req;
|
||||
|
||||
req->complete = pn_rx_complete;
|
||||
fp->out_reqv[i] = req;
|
||||
|
|
@ -540,14 +540,18 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
/* Outgoing USB requests */
|
||||
fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL);
|
||||
if (!fp->in_req)
|
||||
goto err;
|
||||
goto err_req;
|
||||
|
||||
INFO(cdev, "USB CDC Phonet function\n");
|
||||
INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name,
|
||||
fp->out_ep->name, fp->in_ep->name);
|
||||
return 0;
|
||||
|
||||
err_req:
|
||||
for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
|
||||
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
|
||||
err:
|
||||
usb_free_all_descriptors(f);
|
||||
if (fp->out_ep)
|
||||
fp->out_ep->driver_data = NULL;
|
||||
if (fp->in_ep)
|
||||
|
|
@ -569,6 +573,7 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
if (fp->out_reqv[i])
|
||||
usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(fp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ static unsigned int bitrate(struct usb_gadget *g)
|
|||
/*
|
||||
*/
|
||||
|
||||
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
|
||||
#define RNDIS_STATUS_INTERVAL_MS 32
|
||||
#define STATUS_BYTECOUNT 8 /* 8 bytes data */
|
||||
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
.bInterval = RNDIS_STATUS_INTERVAL_MS,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_in_desc = {
|
||||
|
|
@ -236,7 +236,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS)
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_in_desc = {
|
||||
|
|
@ -284,7 +284,7 @@ static struct usb_endpoint_descriptor ss_notify_desc = {
|
|||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
.bInterval = USB_MS_TO_HS_INTERVAL(RNDIS_STATUS_INTERVAL_MS)
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
|
||||
|
|
@ -722,42 +722,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
rndis->notify_req->context = rndis;
|
||||
rndis->notify_req->complete = rndis_response_complete;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(eth_fs_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_in_desc.bEndpointAddress =
|
||||
fs_in_desc.bEndpointAddress;
|
||||
hs_out_desc.bEndpointAddress =
|
||||
fs_out_desc.bEndpointAddress;
|
||||
hs_notify_desc.bEndpointAddress =
|
||||
fs_notify_desc.bEndpointAddress;
|
||||
hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
|
||||
hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
|
||||
hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
|
||||
ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
|
||||
ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_in_desc.bEndpointAddress =
|
||||
fs_in_desc.bEndpointAddress;
|
||||
ss_out_desc.bEndpointAddress =
|
||||
fs_out_desc.bEndpointAddress;
|
||||
ss_notify_desc.bEndpointAddress =
|
||||
fs_notify_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
|
||||
eth_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
rndis->port.open = rndis_open;
|
||||
rndis->port.close = rndis_close;
|
||||
|
|
@ -788,12 +768,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
if (rndis->notify_req) {
|
||||
kfree(rndis->notify_req->buf);
|
||||
|
|
@ -803,9 +778,9 @@ fail:
|
|||
/* we might as well release our claims on endpoints */
|
||||
if (rndis->notify)
|
||||
rndis->notify->driver_data = NULL;
|
||||
if (rndis->port.out_ep->desc)
|
||||
if (rndis->port.out_ep)
|
||||
rndis->port.out_ep->driver_data = NULL;
|
||||
if (rndis->port.in_ep->desc)
|
||||
if (rndis->port.in_ep)
|
||||
rndis->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
|
@ -820,13 +795,9 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
rndis_deregister(rndis->config);
|
||||
rndis_exit();
|
||||
rndis_string_defs[0].id = 0;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
rndis_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(rndis->notify_req->buf);
|
||||
usb_ep_free_request(rndis->notify, rndis->notify_req);
|
||||
|
|
@ -851,34 +822,19 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
|||
if (!can_support_rndis(c) || !ethaddr)
|
||||
return -EINVAL;
|
||||
|
||||
/* maybe allocate device-global string IDs */
|
||||
if (rndis_string_defs[0].id == 0) {
|
||||
|
||||
/* ... and setup RNDIS itself */
|
||||
status = rndis_init();
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* control interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
status = usb_string_ids_tab(c->cdev, rndis_string_defs);
|
||||
if (status)
|
||||
return status;
|
||||
rndis_string_defs[0].id = status;
|
||||
rndis_control_intf.iInterface = status;
|
||||
|
||||
/* data interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
rndis_string_defs[1].id = status;
|
||||
rndis_data_intf.iInterface = status;
|
||||
|
||||
/* IAD iFunction label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
rndis_string_defs[2].id = status;
|
||||
rndis_iad_descriptor.iFunction = status;
|
||||
rndis_control_intf.iInterface = rndis_string_defs[0].id;
|
||||
rndis_data_intf.iInterface = rndis_string_defs[1].id;
|
||||
rndis_iad_descriptor.iFunction = rndis_string_defs[2].id;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
|
|
|
|||
|
|
@ -213,34 +213,20 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
gser->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(gser_fs_function);
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
gser_hs_in_desc.bEndpointAddress =
|
||||
gser_fs_in_desc.bEndpointAddress;
|
||||
gser_hs_out_desc.bEndpointAddress =
|
||||
gser_fs_out_desc.bEndpointAddress;
|
||||
gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
|
||||
gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
|
||||
}
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
gser_ss_in_desc.bEndpointAddress =
|
||||
gser_fs_in_desc.bEndpointAddress;
|
||||
gser_ss_out_desc.bEndpointAddress =
|
||||
gser_fs_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
|
||||
gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
|
||||
gser_ss_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
gser->port_num,
|
||||
gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
|
|
@ -263,11 +249,7 @@ fail:
|
|||
static void
|
||||
gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_gser(f));
|
||||
}
|
||||
|
||||
|
|
@ -278,10 +260,6 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gserial_setup() with enough ports to
|
||||
* handle all the ones it binds. Caller is also responsible
|
||||
* for calling @gserial_cleanup() before module unload.
|
||||
*/
|
||||
int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "g_zero.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
/*
|
||||
* SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
|
||||
* controller drivers.
|
||||
|
|
@ -62,24 +63,11 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
|
|||
}
|
||||
|
||||
static unsigned pattern;
|
||||
module_param(pattern, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
|
||||
|
||||
static unsigned isoc_interval = 4;
|
||||
module_param(isoc_interval, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(isoc_interval, "1 - 16");
|
||||
|
||||
static unsigned isoc_maxpacket = 1024;
|
||||
module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
|
||||
|
||||
static unsigned isoc_interval;
|
||||
static unsigned isoc_maxpacket;
|
||||
static unsigned isoc_mult;
|
||||
module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
|
||||
|
||||
static unsigned isoc_maxburst;
|
||||
module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
|
||||
static unsigned buflen;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -313,12 +301,63 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
if (len)
|
||||
req->length = len;
|
||||
else
|
||||
req->length = buflen;
|
||||
req->buf = kmalloc(req->length, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
|
||||
{
|
||||
int value;
|
||||
|
||||
if (ep->driver_data) {
|
||||
value = usb_ep_disable(ep);
|
||||
if (value < 0)
|
||||
DBG(cdev, "disable %s --> %d\n",
|
||||
ep->name, value);
|
||||
ep->driver_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void disable_endpoints(struct usb_composite_dev *cdev,
|
||||
struct usb_ep *in, struct usb_ep *out,
|
||||
struct usb_ep *iso_in, struct usb_ep *iso_out)
|
||||
{
|
||||
disable_ep(cdev, in);
|
||||
disable_ep(cdev, out);
|
||||
if (iso_in)
|
||||
disable_ep(cdev, iso_in);
|
||||
if (iso_out)
|
||||
disable_ep(cdev, iso_out);
|
||||
}
|
||||
|
||||
static int
|
||||
sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_sourcesink *ss = func_to_ss(f);
|
||||
int id;
|
||||
int ret;
|
||||
|
||||
/* allocate interface ID(s) */
|
||||
id = usb_interface_id(c, f);
|
||||
|
|
@ -387,64 +426,57 @@ no_iso:
|
|||
isoc_maxpacket = 1024;
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_source_desc.bEndpointAddress =
|
||||
fs_source_desc.bEndpointAddress;
|
||||
hs_sink_desc.bEndpointAddress =
|
||||
fs_sink_desc.bEndpointAddress;
|
||||
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
|
||||
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
|
||||
|
||||
/*
|
||||
* Fill in the HS isoc descriptors from the module parameters.
|
||||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_source_desc.bInterval = isoc_interval;
|
||||
hs_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
/*
|
||||
* Fill in the HS isoc descriptors from the module parameters.
|
||||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_source_desc.bInterval = isoc_interval;
|
||||
hs_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
|
||||
hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_sink_desc.bInterval = isoc_interval;
|
||||
hs_iso_sink_desc.bEndpointAddress =
|
||||
fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
f->hs_descriptors = hs_source_sink_descs;
|
||||
}
|
||||
hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
|
||||
hs_iso_sink_desc.bInterval = isoc_interval;
|
||||
hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
/* support super speed hardware */
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_source_desc.bEndpointAddress =
|
||||
fs_source_desc.bEndpointAddress;
|
||||
ss_sink_desc.bEndpointAddress =
|
||||
fs_sink_desc.bEndpointAddress;
|
||||
ss_source_desc.bEndpointAddress =
|
||||
fs_source_desc.bEndpointAddress;
|
||||
ss_sink_desc.bEndpointAddress =
|
||||
fs_sink_desc.bEndpointAddress;
|
||||
|
||||
/*
|
||||
* Fill in the SS isoc descriptors from the module parameters.
|
||||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_source_desc.bInterval = isoc_interval;
|
||||
ss_iso_source_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_source_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
/*
|
||||
* Fill in the SS isoc descriptors from the module parameters.
|
||||
* We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_source_desc.bInterval = isoc_interval;
|
||||
ss_iso_source_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_source_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_source_desc.bEndpointAddress =
|
||||
fs_iso_source_desc.bEndpointAddress;
|
||||
|
||||
ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_sink_desc.bInterval = isoc_interval;
|
||||
ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_sink_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_sink_desc.bEndpointAddress =
|
||||
fs_iso_sink_desc.bEndpointAddress;
|
||||
ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
|
||||
ss_iso_sink_desc.bInterval = isoc_interval;
|
||||
ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
|
||||
ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
|
||||
ss_iso_sink_comp_desc.wBytesPerInterval =
|
||||
isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
|
||||
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
f->ss_descriptors = ss_source_sink_descs;
|
||||
}
|
||||
ret = usb_assign_descriptors(f, fs_source_sink_descs,
|
||||
hs_source_sink_descs, ss_source_sink_descs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
|
||||
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
|
||||
|
|
@ -456,8 +488,9 @@ no_iso:
|
|||
}
|
||||
|
||||
static void
|
||||
sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
sourcesink_free_func(struct usb_function *f)
|
||||
{
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_ss(f));
|
||||
}
|
||||
|
||||
|
|
@ -536,8 +569,7 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
check_read_data(ss, req);
|
||||
if (pattern != 2)
|
||||
memset(req->buf, 0x55, req->length);
|
||||
} else
|
||||
reinit_write_data(ep, req);
|
||||
}
|
||||
break;
|
||||
|
||||
/* this endpoint is normally active while we're configured */
|
||||
|
|
@ -763,32 +795,10 @@ static void sourcesink_disable(struct usb_function *f)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init sourcesink_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_sourcesink *ss;
|
||||
int status;
|
||||
|
||||
ss = kzalloc(sizeof *ss, GFP_KERNEL);
|
||||
if (!ss)
|
||||
return -ENOMEM;
|
||||
|
||||
ss->function.name = "source/sink";
|
||||
ss->function.descriptors = fs_source_sink_descs;
|
||||
ss->function.bind = sourcesink_bind;
|
||||
ss->function.unbind = sourcesink_unbind;
|
||||
ss->function.set_alt = sourcesink_set_alt;
|
||||
ss->function.get_alt = sourcesink_get_alt;
|
||||
ss->function.disable = sourcesink_disable;
|
||||
|
||||
status = usb_add_function(c, &ss->function);
|
||||
if (status)
|
||||
kfree(ss);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int sourcesink_setup(struct usb_configuration *c,
|
||||
static int sourcesink_setup(struct usb_function *f,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct usb_configuration *c = f->config;
|
||||
struct usb_request *req = c->cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
|
|
@ -857,42 +867,76 @@ unknown:
|
|||
return value;
|
||||
}
|
||||
|
||||
static struct usb_configuration sourcesink_driver = {
|
||||
.label = "source/sink",
|
||||
.strings = sourcesink_strings,
|
||||
.setup = sourcesink_setup,
|
||||
.bConfigurationValue = 3,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
};
|
||||
|
||||
/**
|
||||
* sourcesink_add - add a source/sink testing configuration to a device
|
||||
* @cdev: the device to support the configuration
|
||||
*/
|
||||
int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
|
||||
static struct usb_function *source_sink_alloc_func(
|
||||
struct usb_function_instance *fi)
|
||||
{
|
||||
int id;
|
||||
struct f_sourcesink *ss;
|
||||
struct f_ss_opts *ss_opts;
|
||||
|
||||
/* allocate string ID(s) */
|
||||
id = usb_string_id(cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
strings_sourcesink[0].id = id;
|
||||
ss = kzalloc(sizeof(*ss), GFP_KERNEL);
|
||||
if (!ss)
|
||||
return NULL;
|
||||
|
||||
source_sink_intf_alt0.iInterface = id;
|
||||
source_sink_intf_alt1.iInterface = id;
|
||||
sourcesink_driver.iConfiguration = id;
|
||||
ss_opts = container_of(fi, struct f_ss_opts, func_inst);
|
||||
pattern = ss_opts->pattern;
|
||||
isoc_interval = ss_opts->isoc_interval;
|
||||
isoc_maxpacket = ss_opts->isoc_maxpacket;
|
||||
isoc_mult = ss_opts->isoc_mult;
|
||||
isoc_maxburst = ss_opts->isoc_maxburst;
|
||||
buflen = ss_opts->bulk_buflen;
|
||||
|
||||
/* support autoresume for remote wakeup testing */
|
||||
if (autoresume)
|
||||
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
ss->function.name = "source/sink";
|
||||
ss->function.bind = sourcesink_bind;
|
||||
ss->function.set_alt = sourcesink_set_alt;
|
||||
ss->function.get_alt = sourcesink_get_alt;
|
||||
ss->function.disable = sourcesink_disable;
|
||||
ss->function.setup = sourcesink_setup;
|
||||
ss->function.strings = sourcesink_strings;
|
||||
|
||||
/* support OTG systems */
|
||||
if (gadget_is_otg(cdev->gadget)) {
|
||||
sourcesink_driver.descriptors = otg_desc;
|
||||
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
ss->function.free_func = sourcesink_free_func;
|
||||
|
||||
return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);
|
||||
return &ss->function;
|
||||
}
|
||||
|
||||
static void acm_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_ss_opts *ss_opts;
|
||||
|
||||
ss_opts = container_of(fi, struct f_ss_opts, func_inst);
|
||||
kfree(ss_opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *source_sink_alloc_inst(void)
|
||||
{
|
||||
struct f_ss_opts *ss_opts;
|
||||
|
||||
ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);
|
||||
if (!ss_opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ss_opts->func_inst.free_func_inst = acm_free_instance;
|
||||
return &ss_opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,
|
||||
source_sink_alloc_func);
|
||||
|
||||
static int __init sslb_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_function_register(&SourceSinkusb_func);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = lb_modinit();
|
||||
if (ret)
|
||||
usb_function_unregister(&SourceSinkusb_func);
|
||||
return ret;
|
||||
}
|
||||
static void __exit sslb_modexit(void)
|
||||
{
|
||||
usb_function_unregister(&SourceSinkusb_func);
|
||||
lb_modexit();
|
||||
}
|
||||
module_init(sslb_modinit);
|
||||
module_exit(sslb_modexit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ static struct usb_descriptor_header *ss_eth_function[] = {
|
|||
|
||||
static struct usb_string geth_string_defs[] = {
|
||||
[0].s = "CDC Ethernet Subset/SAFE",
|
||||
[1].s = NULL /* DYNAMIC */,
|
||||
[1].s = "",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
|
|
@ -319,38 +319,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
geth->port.out_ep = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(fs_eth_function);
|
||||
if (!f->descriptors)
|
||||
goto fail;
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hs_subset_in_desc.bEndpointAddress =
|
||||
fs_subset_in_desc.bEndpointAddress;
|
||||
hs_subset_out_desc.bEndpointAddress =
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
|
||||
hs_subset_out_desc.bEndpointAddress =
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
ss_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
|
||||
ss_subset_out_desc.bEndpointAddress =
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
ss_subset_in_desc.bEndpointAddress =
|
||||
fs_subset_in_desc.bEndpointAddress;
|
||||
ss_subset_out_desc.bEndpointAddress =
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->ss_descriptors = usb_copy_descriptors(ss_eth_function);
|
||||
if (!f->ss_descriptors)
|
||||
goto fail;
|
||||
}
|
||||
status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
|
||||
ss_eth_function);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* NOTE: all that is done without knowing or caring about
|
||||
* the network link ... which is unavailable to this code
|
||||
|
|
@ -364,15 +348,11 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
if (f->descriptors)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
if (f->hs_descriptors)
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (geth->port.out_ep->desc)
|
||||
if (geth->port.out_ep)
|
||||
geth->port.out_ep->driver_data = NULL;
|
||||
if (geth->port.in_ep->desc)
|
||||
if (geth->port.in_ep)
|
||||
geth->port.in_ep->driver_data = NULL;
|
||||
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
|
@ -383,12 +363,8 @@ fail:
|
|||
static void
|
||||
geth_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
geth_string_defs[1].s = NULL;
|
||||
geth_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_geth(f));
|
||||
}
|
||||
|
||||
|
|
@ -414,20 +390,11 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
|
||||
/* maybe allocate device-global string IDs */
|
||||
if (geth_string_defs[0].id == 0) {
|
||||
|
||||
/* interface label */
|
||||
status = usb_string_id(c->cdev);
|
||||
status = usb_string_ids_tab(c->cdev, geth_string_defs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
geth_string_defs[0].id = status;
|
||||
subset_data_intf.iInterface = status;
|
||||
|
||||
/* MAC address */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
geth_string_defs[1].id = status;
|
||||
ether_desc.iMACAddress = status;
|
||||
subset_data_intf.iInterface = geth_string_defs[0].id;
|
||||
ether_desc.iMACAddress = geth_string_defs[1].id;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
|
|
@ -449,9 +416,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
geth->port.func.disable = geth_disable;
|
||||
|
||||
status = usb_add_function(c, &geth->port.func);
|
||||
if (status) {
|
||||
geth_string_defs[1].s = NULL;
|
||||
if (status)
|
||||
kfree(geth);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,6 +418,7 @@ static int audio_get_intf_req(struct usb_function *f,
|
|||
|
||||
req->context = audio;
|
||||
req->complete = f_audio_complete;
|
||||
len = min_t(size_t, sizeof(value), len);
|
||||
memcpy(req->buf, &value, len);
|
||||
|
||||
return len;
|
||||
|
|
@ -630,7 +631,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_audio *audio = func_to_audio(f);
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
struct usb_ep *ep = NULL;
|
||||
|
||||
f_audio_build_desc(audio);
|
||||
|
||||
|
|
@ -659,22 +660,14 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
status = -ENOMEM;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(f_audio_desc);
|
||||
|
||||
/*
|
||||
* support all relevant hardware speeds... we expect that when
|
||||
* hardware is dual speed, all bulk-capable endpoints work at
|
||||
* both speeds
|
||||
*/
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
c->highspeed = true;
|
||||
f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
|
||||
}
|
||||
|
||||
status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
if (ep)
|
||||
ep->driver_data = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -683,8 +676,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
{
|
||||
struct f_audio *audio = func_to_audio(f);
|
||||
|
||||
usb_free_descriptors(f->descriptors);
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(audio);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,13 +50,6 @@ static int c_ssize = 2;
|
|||
module_param(c_ssize, uint, S_IRUGO);
|
||||
MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0)
|
||||
#define ALT_GET(x) ((x) & 0xff)
|
||||
#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0)
|
||||
#define INTF_GET(x) ((x >> 8) & 0xff)
|
||||
|
||||
/* Keep everyone on toes */
|
||||
#define USB_XFERS 2
|
||||
|
||||
|
|
@ -144,8 +137,9 @@ static struct snd_pcm_hardware uac2_pcm_hardware = {
|
|||
};
|
||||
|
||||
struct audio_dev {
|
||||
/* Currently active {Interface[15:8] | AltSettings[7:0]} */
|
||||
__u16 ac_alt, as_out_alt, as_in_alt;
|
||||
u8 ac_intf, ac_alt;
|
||||
u8 as_out_intf, as_out_alt;
|
||||
u8 as_in_intf, as_in_alt;
|
||||
|
||||
struct usb_ep *in_ep, *out_ep;
|
||||
struct usb_function func;
|
||||
|
|
@ -266,19 +260,14 @@ static int
|
|||
uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
|
||||
struct audio_dev *agdev = uac2_to_agdev(uac2);
|
||||
struct uac2_rtd_params *prm;
|
||||
unsigned long flags;
|
||||
struct usb_ep *ep;
|
||||
int err = 0;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ep = agdev->in_ep;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
prm = &uac2->p_prm;
|
||||
} else {
|
||||
ep = agdev->out_ep;
|
||||
else
|
||||
prm = &uac2->c_prm;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&prm->lock, flags);
|
||||
|
||||
|
|
@ -408,7 +397,7 @@ static struct snd_pcm_ops uac2_pcm_ops = {
|
|||
.prepare = uac2_pcm_null,
|
||||
};
|
||||
|
||||
static int __devinit snd_uac2_probe(struct platform_device *pdev)
|
||||
static int snd_uac2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev);
|
||||
struct snd_card *card;
|
||||
|
|
@ -526,32 +515,22 @@ enum {
|
|||
STR_AS_IN_ALT1,
|
||||
};
|
||||
|
||||
static const char ifassoc[] = "Source/Sink";
|
||||
static const char ifctrl[] = "Topology Control";
|
||||
static char clksrc_in[8];
|
||||
static char clksrc_out[8];
|
||||
static const char usb_it[] = "USBH Out";
|
||||
static const char io_it[] = "USBD Out";
|
||||
static const char usb_ot[] = "USBH In";
|
||||
static const char io_ot[] = "USBD In";
|
||||
static const char out_alt0[] = "Playback Inactive";
|
||||
static const char out_alt1[] = "Playback Active";
|
||||
static const char in_alt0[] = "Capture Inactive";
|
||||
static const char in_alt1[] = "Capture Active";
|
||||
|
||||
static struct usb_string strings_fn[] = {
|
||||
[STR_ASSOC].s = ifassoc,
|
||||
[STR_IF_CTRL].s = ifctrl,
|
||||
[STR_ASSOC].s = "Source/Sink",
|
||||
[STR_IF_CTRL].s = "Topology Control",
|
||||
[STR_CLKSRC_IN].s = clksrc_in,
|
||||
[STR_CLKSRC_OUT].s = clksrc_out,
|
||||
[STR_USB_IT].s = usb_it,
|
||||
[STR_IO_IT].s = io_it,
|
||||
[STR_USB_OT].s = usb_ot,
|
||||
[STR_IO_OT].s = io_ot,
|
||||
[STR_AS_OUT_ALT0].s = out_alt0,
|
||||
[STR_AS_OUT_ALT1].s = out_alt1,
|
||||
[STR_AS_IN_ALT0].s = in_alt0,
|
||||
[STR_AS_IN_ALT1].s = in_alt1,
|
||||
[STR_USB_IT].s = "USBH Out",
|
||||
[STR_IO_IT].s = "USBD Out",
|
||||
[STR_USB_OT].s = "USBH In",
|
||||
[STR_IO_OT].s = "USBD In",
|
||||
[STR_AS_OUT_ALT0].s = "Playback Inactive",
|
||||
[STR_AS_OUT_ALT1].s = "Playback Active",
|
||||
[STR_AS_IN_ALT0].s = "Capture Inactive",
|
||||
[STR_AS_IN_ALT1].s = "Capture Active",
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
@ -952,8 +931,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
return ret;
|
||||
}
|
||||
std_ac_if_desc.bInterfaceNumber = ret;
|
||||
ALT_SET(agdev->ac_alt, 0);
|
||||
INTF_SET(agdev->ac_alt, ret);
|
||||
agdev->ac_intf = ret;
|
||||
agdev->ac_alt = 0;
|
||||
|
||||
ret = usb_interface_id(cfg, fn);
|
||||
if (ret < 0) {
|
||||
|
|
@ -963,8 +942,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
}
|
||||
std_as_out_if0_desc.bInterfaceNumber = ret;
|
||||
std_as_out_if1_desc.bInterfaceNumber = ret;
|
||||
ALT_SET(agdev->as_out_alt, 0);
|
||||
INTF_SET(agdev->as_out_alt, ret);
|
||||
agdev->as_out_intf = ret;
|
||||
agdev->as_out_alt = 0;
|
||||
|
||||
ret = usb_interface_id(cfg, fn);
|
||||
if (ret < 0) {
|
||||
|
|
@ -974,19 +953,23 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
}
|
||||
std_as_in_if0_desc.bInterfaceNumber = ret;
|
||||
std_as_in_if1_desc.bInterfaceNumber = ret;
|
||||
ALT_SET(agdev->as_in_alt, 0);
|
||||
INTF_SET(agdev->as_in_alt, ret);
|
||||
agdev->as_in_intf = ret;
|
||||
agdev->as_in_alt = 0;
|
||||
|
||||
agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
|
||||
if (!agdev->out_ep)
|
||||
if (!agdev->out_ep) {
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
agdev->out_ep->driver_data = agdev;
|
||||
|
||||
agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
|
||||
if (!agdev->in_ep)
|
||||
if (!agdev->in_ep) {
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
agdev->in_ep->driver_data = agdev;
|
||||
|
||||
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
|
||||
|
|
@ -994,9 +977,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
|
||||
hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
|
||||
|
||||
fn->descriptors = usb_copy_descriptors(fs_audio_desc);
|
||||
if (gadget_is_dualspeed(gadget))
|
||||
fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc);
|
||||
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
prm = &agdev->uac2.c_prm;
|
||||
prm->max_psize = hs_epout_desc.wMaxPacketSize;
|
||||
|
|
@ -1005,6 +988,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
prm->max_psize = 0;
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
prm = &agdev->uac2.p_prm;
|
||||
|
|
@ -1014,17 +998,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
prm->max_psize = 0;
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return alsa_uac2_init(agdev);
|
||||
ret = alsa_uac2_init(agdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
return 0;
|
||||
err:
|
||||
kfree(agdev->uac2.p_prm.rbuf);
|
||||
kfree(agdev->uac2.c_prm.rbuf);
|
||||
usb_free_all_descriptors(fn);
|
||||
if (agdev->in_ep)
|
||||
agdev->in_ep->driver_data = NULL;
|
||||
if (agdev->out_ep)
|
||||
agdev->out_ep->driver_data = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
|
||||
{
|
||||
struct audio_dev *agdev = func_to_agdev(fn);
|
||||
struct usb_composite_dev *cdev = cfg->cdev;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct uac2_rtd_params *prm;
|
||||
|
||||
alsa_uac2_exit(agdev);
|
||||
|
|
@ -1034,10 +1029,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
|
|||
|
||||
prm = &agdev->uac2.c_prm;
|
||||
kfree(prm->rbuf);
|
||||
|
||||
if (gadget_is_dualspeed(gadget))
|
||||
usb_free_descriptors(fn->hs_descriptors);
|
||||
usb_free_descriptors(fn->descriptors);
|
||||
usb_free_all_descriptors(fn);
|
||||
|
||||
if (agdev->in_ep)
|
||||
agdev->in_ep->driver_data = NULL;
|
||||
|
|
@ -1064,7 +1056,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (intf == INTF_GET(agdev->ac_alt)) {
|
||||
if (intf == agdev->ac_intf) {
|
||||
/* Control I/f has only 1 AltSetting - 0 */
|
||||
if (alt) {
|
||||
dev_err(&uac2->pdev.dev,
|
||||
|
|
@ -1074,16 +1066,16 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (intf == INTF_GET(agdev->as_out_alt)) {
|
||||
if (intf == agdev->as_out_intf) {
|
||||
ep = agdev->out_ep;
|
||||
prm = &uac2->c_prm;
|
||||
config_ep_by_speed(gadget, fn, ep);
|
||||
ALT_SET(agdev->as_out_alt, alt);
|
||||
} else if (intf == INTF_GET(agdev->as_in_alt)) {
|
||||
agdev->as_out_alt = alt;
|
||||
} else if (intf == agdev->as_in_intf) {
|
||||
ep = agdev->in_ep;
|
||||
prm = &uac2->p_prm;
|
||||
config_ep_by_speed(gadget, fn, ep);
|
||||
ALT_SET(agdev->as_in_alt, alt);
|
||||
agdev->as_in_alt = alt;
|
||||
} else {
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
|
|
@ -1117,7 +1109,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
|
|||
prm->ureq[i].pp = prm;
|
||||
|
||||
req->zero = 0;
|
||||
req->dma = DMA_ADDR_INVALID;
|
||||
req->context = &prm->ureq[i];
|
||||
req->length = prm->max_psize;
|
||||
req->complete = agdev_iso_complete;
|
||||
|
|
@ -1136,12 +1127,12 @@ afunc_get_alt(struct usb_function *fn, unsigned intf)
|
|||
struct audio_dev *agdev = func_to_agdev(fn);
|
||||
struct snd_uac2_chip *uac2 = &agdev->uac2;
|
||||
|
||||
if (intf == INTF_GET(agdev->ac_alt))
|
||||
return ALT_GET(agdev->ac_alt);
|
||||
else if (intf == INTF_GET(agdev->as_out_alt))
|
||||
return ALT_GET(agdev->as_out_alt);
|
||||
else if (intf == INTF_GET(agdev->as_in_alt))
|
||||
return ALT_GET(agdev->as_in_alt);
|
||||
if (intf == agdev->ac_intf)
|
||||
return agdev->ac_alt;
|
||||
else if (intf == agdev->as_out_intf)
|
||||
return agdev->as_out_alt;
|
||||
else if (intf == agdev->as_in_intf)
|
||||
return agdev->as_in_alt;
|
||||
else
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Invalid Interface %d!\n",
|
||||
|
|
@ -1157,10 +1148,10 @@ afunc_disable(struct usb_function *fn)
|
|||
struct snd_uac2_chip *uac2 = &agdev->uac2;
|
||||
|
||||
free_ep(&uac2->p_prm, agdev->in_ep);
|
||||
ALT_SET(agdev->as_in_alt, 0);
|
||||
agdev->as_in_alt = 0;
|
||||
|
||||
free_ep(&uac2->c_prm, agdev->out_ep);
|
||||
ALT_SET(agdev->as_out_alt, 0);
|
||||
agdev->as_out_alt = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1267,7 +1258,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
|
|||
u16 w_index = le16_to_cpu(cr->wIndex);
|
||||
u8 intf = w_index & 0xff;
|
||||
|
||||
if (intf != INTF_GET(agdev->ac_alt)) {
|
||||
if (intf != agdev->ac_intf) {
|
||||
dev_err(&uac2->pdev.dev,
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1316,7 +1307,7 @@ afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
|
|||
|
||||
static int audio_bind_config(struct usb_configuration *cfg)
|
||||
{
|
||||
int id, res;
|
||||
int res;
|
||||
|
||||
agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL);
|
||||
if (agdev_g == NULL) {
|
||||
|
|
@ -1324,89 +1315,21 @@ static int audio_bind_config(struct usb_configuration *cfg)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_ASSOC].id = id;
|
||||
iad_desc.iFunction = id,
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_IF_CTRL].id = id;
|
||||
std_ac_if_desc.iInterface = id,
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_CLKSRC_IN].id = id;
|
||||
in_clk_src_desc.iClockSource = id,
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_CLKSRC_OUT].id = id;
|
||||
out_clk_src_desc.iClockSource = id,
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_USB_IT].id = id;
|
||||
usb_out_it_desc.iTerminal = id,
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_IO_IT].id = id;
|
||||
io_in_it_desc.iTerminal = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_USB_OT].id = id;
|
||||
usb_in_ot_desc.iTerminal = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_IO_OT].id = id;
|
||||
io_out_ot_desc.iTerminal = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_AS_OUT_ALT0].id = id;
|
||||
std_as_out_if0_desc.iInterface = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_AS_OUT_ALT1].id = id;
|
||||
std_as_out_if1_desc.iInterface = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_AS_IN_ALT0].id = id;
|
||||
std_as_in_if0_desc.iInterface = id;
|
||||
|
||||
id = usb_string_id(cfg->cdev);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
strings_fn[STR_AS_IN_ALT1].id = id;
|
||||
std_as_in_if1_desc.iInterface = id;
|
||||
res = usb_string_ids_tab(cfg->cdev, strings_fn);
|
||||
if (res)
|
||||
return res;
|
||||
iad_desc.iFunction = strings_fn[STR_ASSOC].id;
|
||||
std_ac_if_desc.iInterface = strings_fn[STR_IF_CTRL].id;
|
||||
in_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_IN].id;
|
||||
out_clk_src_desc.iClockSource = strings_fn[STR_CLKSRC_OUT].id;
|
||||
usb_out_it_desc.iTerminal = strings_fn[STR_USB_IT].id;
|
||||
io_in_it_desc.iTerminal = strings_fn[STR_IO_IT].id;
|
||||
usb_in_ot_desc.iTerminal = strings_fn[STR_USB_OT].id;
|
||||
io_out_ot_desc.iTerminal = strings_fn[STR_IO_OT].id;
|
||||
std_as_out_if0_desc.iInterface = strings_fn[STR_AS_OUT_ALT0].id;
|
||||
std_as_out_if1_desc.iInterface = strings_fn[STR_AS_OUT_ALT1].id;
|
||||
std_as_in_if0_desc.iInterface = strings_fn[STR_AS_IN_ALT0].id;
|
||||
std_as_in_if1_desc.iInterface = strings_fn[STR_AS_IN_ALT1].id;
|
||||
|
||||
agdev_g->func.name = "uac2_func";
|
||||
agdev_g->func.strings = fn_strings;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/video.h>
|
||||
|
|
@ -417,10 +418,9 @@ uvc_register_video(struct uvc_device *uvc)
|
|||
return -ENOMEM;
|
||||
|
||||
video->parent = &cdev->gadget->dev;
|
||||
video->minor = -1;
|
||||
video->fops = &uvc_v4l2_fops;
|
||||
video->release = video_device_release;
|
||||
strncpy(video->name, cdev->gadget->name, sizeof(video->name));
|
||||
strlcpy(video->name, cdev->gadget->name, sizeof(video->name));
|
||||
|
||||
uvc->vdev = video;
|
||||
video_set_drvdata(video, uvc);
|
||||
|
|
@ -577,27 +577,15 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
INFO(cdev, "uvc_function_unbind\n");
|
||||
|
||||
if (uvc->vdev) {
|
||||
if (uvc->vdev->minor == -1)
|
||||
video_device_release(uvc->vdev);
|
||||
else
|
||||
video_unregister_device(uvc->vdev);
|
||||
uvc->vdev = NULL;
|
||||
}
|
||||
video_unregister_device(uvc->vdev);
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
if (uvc->control_ep)
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
if (uvc->video.ep)
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0;
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
|
||||
if (uvc->control_req) {
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
}
|
||||
|
||||
kfree(f->descriptors);
|
||||
kfree(f->hs_descriptors);
|
||||
kfree(f->ss_descriptors);
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(uvc);
|
||||
}
|
||||
|
|
@ -663,49 +651,40 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
/* sanity check the streaming endpoint module parameters */
|
||||
if (streaming_maxpacket > 1024)
|
||||
streaming_maxpacket = 1024;
|
||||
/*
|
||||
* Fill in the HS descriptors from the module parameters for the Video
|
||||
* Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
|
||||
uvc_hs_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_hs_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* Copy descriptors for FS. */
|
||||
f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
/*
|
||||
* Fill in the SS descriptors from the module parameters for the Video
|
||||
* Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_ss_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_ss_streaming_comp.bmAttributes = streaming_mult;
|
||||
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
|
||||
uvc_ss_streaming_comp.wBytesPerInterval =
|
||||
streaming_maxpacket * (streaming_mult + 1) *
|
||||
(streaming_maxburst + 1);
|
||||
uvc_ss_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(cdev->gadget)) {
|
||||
/*
|
||||
* Fill in the HS descriptors from the module parameters for the
|
||||
* Video Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and
|
||||
* won't give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
|
||||
uvc_hs_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_hs_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* Copy descriptors. */
|
||||
/* Copy descriptors */
|
||||
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
if (gadget_is_dualspeed(cdev->gadget))
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
}
|
||||
|
||||
/* support super speed hardware */
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
/*
|
||||
* Fill in the SS descriptors from the module parameters for the
|
||||
* Video Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and
|
||||
* won't give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_ss_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_ss_streaming_comp.bmAttributes = streaming_mult;
|
||||
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
|
||||
uvc_ss_streaming_comp.wBytesPerInterval =
|
||||
streaming_maxpacket * (streaming_mult + 1) *
|
||||
(streaming_maxburst + 1);
|
||||
uvc_ss_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* Copy descriptors. */
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
|
||||
}
|
||||
|
||||
/* Preallocate control endpoint request. */
|
||||
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
|
||||
|
|
@ -740,7 +719,20 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
return 0;
|
||||
|
||||
error:
|
||||
uvc_function_unbind(c, f);
|
||||
if (uvc->vdev)
|
||||
video_device_release(uvc->vdev);
|
||||
|
||||
if (uvc->control_ep)
|
||||
uvc->control_ep->driver_data = NULL;
|
||||
if (uvc->video.ep)
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
if (uvc->control_req) {
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
}
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -808,25 +800,16 @@ uvc_bind_config(struct usb_configuration *c,
|
|||
uvc->desc.hs_streaming = hs_streaming;
|
||||
uvc->desc.ss_streaming = ss_streaming;
|
||||
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
/* Allocate string descriptor numbers. */
|
||||
if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
|
||||
/* Allocate string descriptor numbers. */
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
|
||||
if (ret)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
|
||||
uvc_iad.iFunction = ret;
|
||||
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
|
||||
uvc_control_intf.iInterface = ret;
|
||||
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
|
||||
uvc_iad.iFunction =
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id;
|
||||
uvc_control_intf.iInterface =
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
|
||||
ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id;
|
||||
uvc_streaming_intf_alt0.iInterface = ret;
|
||||
uvc_streaming_intf_alt1.iInterface = ret;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -18,14 +18,13 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static struct clk *mxc_ahb_clk;
|
||||
static struct clk *mxc_per_clk;
|
||||
static struct clk *mxc_ipg_clk;
|
||||
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
#define USBPHYCTRL_OTGBASE_OFFSET 0x608
|
||||
#define MX35_USBPHYCTRL_OFFSET 0x600
|
||||
#define USBPHYCTRL_OTGBASE_OFFSET 0x8
|
||||
#define USBPHYCTRL_EVDO (1 << 23)
|
||||
|
||||
int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
|
|
@ -59,7 +58,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
|
|||
clk_prepare_enable(mxc_per_clk);
|
||||
|
||||
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
|
||||
if (!cpu_is_mx51()) {
|
||||
if (!strcmp(pdev->id_entry->name, "imx-udc-mx27")) {
|
||||
freq = clk_get_rate(mxc_per_clk);
|
||||
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
|
||||
(freq < 59999000 || freq > 60001000)) {
|
||||
|
|
@ -79,27 +78,40 @@ eclkrate:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
int fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
if (cpu_is_mx35()) {
|
||||
unsigned int v;
|
||||
int ret = 0;
|
||||
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
|
||||
v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
|
||||
USBPHYCTRL_OTGBASE_OFFSET));
|
||||
writel(v | USBPHYCTRL_EVDO,
|
||||
MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
|
||||
USBPHYCTRL_OTGBASE_OFFSET));
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
|
||||
unsigned int v;
|
||||
struct resource *res = platform_get_resource
|
||||
(pdev, IORESOURCE_MEM, 0);
|
||||
void __iomem *phy_regs = ioremap(res->start +
|
||||
MX35_USBPHYCTRL_OFFSET, 512);
|
||||
if (!phy_regs) {
|
||||
dev_err(&pdev->dev, "ioremap for phy address fails\n");
|
||||
ret = -EINVAL;
|
||||
goto ioremap_err;
|
||||
}
|
||||
|
||||
v = readl(phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
|
||||
writel(v | USBPHYCTRL_EVDO,
|
||||
phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
|
||||
|
||||
iounmap(phy_regs);
|
||||
}
|
||||
|
||||
|
||||
ioremap_err:
|
||||
/* ULPI transceivers don't need usbpll */
|
||||
if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
|
||||
clk_disable_unprepare(mxc_per_clk);
|
||||
mxc_per_clk = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fsl_udc_clk_release(void)
|
||||
|
|
|
|||
|
|
@ -1894,7 +1894,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
|
|||
struct usb_gadget_driver *driver);
|
||||
|
||||
/* defined in usb_gadget.h */
|
||||
static struct usb_gadget_ops qe_gadget_ops = {
|
||||
static const struct usb_gadget_ops qe_gadget_ops = {
|
||||
.get_frame = qe_get_frame,
|
||||
.udc_start = fsl_qe_start,
|
||||
.udc_stop = fsl_qe_stop,
|
||||
|
|
@ -2347,7 +2347,7 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
|
|||
}
|
||||
|
||||
/* udc structure's alloc and setup, include ep-param alloc */
|
||||
static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
|
||||
static struct qe_udc *qe_udc_config(struct platform_device *ofdev)
|
||||
{
|
||||
struct qe_udc *udc;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
|
|
@ -2402,7 +2402,7 @@ cleanup:
|
|||
}
|
||||
|
||||
/* USB Controller register init */
|
||||
static int __devinit qe_udc_reg_init(struct qe_udc *udc)
|
||||
static int qe_udc_reg_init(struct qe_udc *udc)
|
||||
{
|
||||
struct usb_ctlr __iomem *qe_usbregs;
|
||||
qe_usbregs = udc->usb_regs;
|
||||
|
|
@ -2420,7 +2420,7 @@ static int __devinit qe_udc_reg_init(struct qe_udc *udc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
|
||||
static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
|
||||
{
|
||||
struct qe_ep *ep = &udc->eps[pipe_num];
|
||||
|
||||
|
|
@ -2473,7 +2473,7 @@ static void qe_udc_release(struct device *dev)
|
|||
|
||||
/* Driver probe functions */
|
||||
static const struct of_device_id qe_udc_match[];
|
||||
static int __devinit qe_udc_probe(struct platform_device *ofdev)
|
||||
static int qe_udc_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct qe_udc *udc;
|
||||
const struct of_device_id *match;
|
||||
|
|
@ -2651,7 +2651,7 @@ static int qe_udc_resume(struct platform_device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int __devexit qe_udc_remove(struct platform_device *ofdev)
|
||||
static int qe_udc_remove(struct platform_device *ofdev)
|
||||
{
|
||||
struct qe_udc *udc = dev_get_drvdata(&ofdev->dev);
|
||||
struct qe_ep *ep;
|
||||
|
|
@ -2710,7 +2710,7 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)
|
|||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static const struct of_device_id qe_udc_match[] __devinitconst = {
|
||||
static const struct of_device_id qe_udc_match[] = {
|
||||
{
|
||||
.compatible = "fsl,mpc8323-qe-usb",
|
||||
.data = (void *)PORT_QE,
|
||||
|
|
@ -2735,7 +2735,7 @@ static struct platform_driver udc_driver = {
|
|||
.of_match_table = qe_udc_match,
|
||||
},
|
||||
.probe = qe_udc_probe,
|
||||
.remove = __devexit_p(qe_udc_remove),
|
||||
.remove = qe_udc_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = qe_udc_suspend,
|
||||
.resume = qe_udc_resume,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/fsl_devices.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/io.h>
|
||||
|
|
@ -1254,19 +1255,20 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
|
||||
static int fsl_stop(struct usb_gadget_driver *driver);
|
||||
static int fsl_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
static int fsl_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
/* defined in gadget.h */
|
||||
static struct usb_gadget_ops fsl_gadget_ops = {
|
||||
static const struct usb_gadget_ops fsl_gadget_ops = {
|
||||
.get_frame = fsl_get_frame,
|
||||
.wakeup = fsl_wakeup,
|
||||
/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */
|
||||
.vbus_session = fsl_vbus_session,
|
||||
.vbus_draw = fsl_vbus_draw,
|
||||
.pullup = fsl_pullup,
|
||||
.start = fsl_start,
|
||||
.stop = fsl_stop,
|
||||
.udc_start = fsl_udc_start,
|
||||
.udc_stop = fsl_udc_stop,
|
||||
};
|
||||
|
||||
/* Set protocol stall on ep0, protocol stall will automatically be cleared
|
||||
|
|
@ -1950,22 +1952,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
|
|||
* Hook to gadget drivers
|
||||
* Called by initialization code of gadget drivers
|
||||
*----------------------------------------------------------------*/
|
||||
static int fsl_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int fsl_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
int retval = 0;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (!udc_controller)
|
||||
return -ENODEV;
|
||||
|
||||
if (!driver || driver->max_speed < USB_SPEED_FULL
|
||||
|| !bind || !driver->disconnect || !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
if (udc_controller->driver)
|
||||
return -EBUSY;
|
||||
|
||||
/* lock is needed but whether should use this lock or another */
|
||||
spin_lock_irqsave(&udc_controller->lock, flags);
|
||||
|
||||
|
|
@ -1975,15 +1967,6 @@ static int fsl_start(struct usb_gadget_driver *driver,
|
|||
udc_controller->gadget.dev.driver = &driver->driver;
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
/* bind udc driver to gadget driver */
|
||||
retval = bind(&udc_controller->gadget, driver);
|
||||
if (retval) {
|
||||
VDBG("bind to %s --> %d", driver->driver.name, retval);
|
||||
udc_controller->gadget.dev.driver = NULL;
|
||||
udc_controller->driver = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
/* Suspend the controller until OTG enable it */
|
||||
udc_controller->stopped = 1;
|
||||
|
|
@ -2009,28 +1992,17 @@ static int fsl_start(struct usb_gadget_driver *driver,
|
|||
udc_controller->ep0_state = WAIT_FOR_SETUP;
|
||||
udc_controller->ep0_dir = 0;
|
||||
}
|
||||
printk(KERN_INFO "%s: bind to driver %s\n",
|
||||
udc_controller->gadget.name, driver->driver.name);
|
||||
|
||||
out:
|
||||
if (retval)
|
||||
printk(KERN_WARNING "gadget driver register failed %d\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Disconnect from gadget driver */
|
||||
static int fsl_stop(struct usb_gadget_driver *driver)
|
||||
static int fsl_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct fsl_ep *loop_ep;
|
||||
unsigned long flags;
|
||||
|
||||
if (!udc_controller)
|
||||
return -ENODEV;
|
||||
|
||||
if (!driver || driver != udc_controller->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
|
||||
otg_set_peripheral(udc_controller->transceiver->otg, NULL);
|
||||
|
||||
|
|
@ -2051,16 +2023,9 @@ static int fsl_stop(struct usb_gadget_driver *driver)
|
|||
nuke(loop_ep, -ESHUTDOWN);
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
/* report disconnect; the controller is already quiesced */
|
||||
driver->disconnect(&udc_controller->gadget);
|
||||
|
||||
/* unbind gadget and unhook driver. */
|
||||
driver->unbind(&udc_controller->gadget);
|
||||
udc_controller->gadget.dev.driver = NULL;
|
||||
udc_controller->driver = NULL;
|
||||
|
||||
printk(KERN_WARNING "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2126,7 +2091,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
|
|||
|
||||
tmp_reg = fsl_readl(&dr_regs->usbintr);
|
||||
t = scnprintf(next, size,
|
||||
"USB Intrrupt Enable Reg:\n"
|
||||
"USB Interrupt Enable Reg:\n"
|
||||
"Sleep Enable: %d SOF Received Enable: %d "
|
||||
"Reset Enable: %d\n"
|
||||
"System Error Enable: %d "
|
||||
|
|
@ -2438,11 +2403,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
unsigned int i;
|
||||
u32 dccparams;
|
||||
|
||||
if (strcmp(pdev->name, driver_name)) {
|
||||
VDBG("Wrong device");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
|
||||
if (udc_controller == NULL) {
|
||||
ERR("malloc udc failed\n");
|
||||
|
|
@ -2547,7 +2507,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
dr_controller_setup(udc_controller);
|
||||
}
|
||||
|
||||
fsl_udc_clk_finalize(pdev);
|
||||
ret = fsl_udc_clk_finalize(pdev);
|
||||
if (ret)
|
||||
goto err_free_irq;
|
||||
|
||||
/* Setup gadget structure */
|
||||
udc_controller->gadget.ops = &fsl_gadget_ops;
|
||||
|
|
@ -2756,22 +2718,32 @@ static int fsl_udc_otg_resume(struct device *dev)
|
|||
|
||||
return fsl_udc_resume(NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Register entry point for the peripheral controller driver
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
static const struct platform_device_id fsl_udc_devtype[] = {
|
||||
{
|
||||
.name = "imx-udc-mx27",
|
||||
}, {
|
||||
.name = "imx-udc-mx51",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
|
||||
static struct platform_driver udc_driver = {
|
||||
.remove = __exit_p(fsl_udc_remove),
|
||||
.remove = __exit_p(fsl_udc_remove),
|
||||
/* Just for FSL i.mx SoC currently */
|
||||
.id_table = fsl_udc_devtype,
|
||||
/* these suspend and resume are not usb suspend and resume */
|
||||
.suspend = fsl_udc_suspend,
|
||||
.resume = fsl_udc_resume,
|
||||
.driver = {
|
||||
.name = (char *)driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
/* udc suspend/resume called from OTG driver */
|
||||
.suspend = fsl_udc_otg_suspend,
|
||||
.resume = fsl_udc_otg_resume,
|
||||
.suspend = fsl_udc_suspend,
|
||||
.resume = fsl_udc_resume,
|
||||
.driver = {
|
||||
.name = (char *)driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
/* udc suspend/resume called from OTG driver */
|
||||
.suspend = fsl_udc_otg_suspend,
|
||||
.resume = fsl_udc_otg_resume,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -592,15 +592,16 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
|
|||
struct platform_device;
|
||||
#ifdef CONFIG_ARCH_MXC
|
||||
int fsl_udc_clk_init(struct platform_device *pdev);
|
||||
void fsl_udc_clk_finalize(struct platform_device *pdev);
|
||||
int fsl_udc_clk_finalize(struct platform_device *pdev);
|
||||
void fsl_udc_clk_release(void);
|
||||
#else
|
||||
static inline int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
static inline int fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void fsl_udc_clk_release(void)
|
||||
{
|
||||
|
|
|
|||
116
drivers/usb/gadget/functions.c
Normal file
116
drivers/usb/gadget/functions.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
static LIST_HEAD(func_list);
|
||||
static DEFINE_MUTEX(func_lock);
|
||||
|
||||
static struct usb_function_instance *try_get_usb_function_instance(const char *name)
|
||||
{
|
||||
struct usb_function_driver *fd;
|
||||
struct usb_function_instance *fi;
|
||||
|
||||
fi = ERR_PTR(-ENOENT);
|
||||
mutex_lock(&func_lock);
|
||||
list_for_each_entry(fd, &func_list, list) {
|
||||
|
||||
if (strcmp(name, fd->name))
|
||||
continue;
|
||||
|
||||
if (!try_module_get(fd->mod)) {
|
||||
fi = ERR_PTR(-EBUSY);
|
||||
break;
|
||||
}
|
||||
fi = fd->alloc_inst();
|
||||
if (IS_ERR(fi))
|
||||
module_put(fd->mod);
|
||||
else
|
||||
fi->fd = fd;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&func_lock);
|
||||
return fi;
|
||||
}
|
||||
|
||||
struct usb_function_instance *usb_get_function_instance(const char *name)
|
||||
{
|
||||
struct usb_function_instance *fi;
|
||||
int ret;
|
||||
|
||||
fi = try_get_usb_function_instance(name);
|
||||
if (!IS_ERR(fi))
|
||||
return fi;
|
||||
ret = PTR_ERR(fi);
|
||||
if (ret != -ENOENT)
|
||||
return fi;
|
||||
ret = request_module("usbfunc:%s", name);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
return try_get_usb_function_instance(name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_get_function_instance);
|
||||
|
||||
struct usb_function *usb_get_function(struct usb_function_instance *fi)
|
||||
{
|
||||
struct usb_function *f;
|
||||
|
||||
f = fi->fd->alloc_func(fi);
|
||||
if (IS_ERR(f))
|
||||
return f;
|
||||
f->fi = fi;
|
||||
return f;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_get_function);
|
||||
|
||||
void usb_put_function_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct module *mod;
|
||||
|
||||
if (!fi)
|
||||
return;
|
||||
|
||||
mod = fi->fd->mod;
|
||||
fi->free_func_inst(fi);
|
||||
module_put(mod);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_put_function_instance);
|
||||
|
||||
void usb_put_function(struct usb_function *f)
|
||||
{
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
f->free_func(f);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_put_function);
|
||||
|
||||
int usb_function_register(struct usb_function_driver *newf)
|
||||
{
|
||||
struct usb_function_driver *fd;
|
||||
int ret;
|
||||
|
||||
ret = -EEXIST;
|
||||
|
||||
mutex_lock(&func_lock);
|
||||
list_for_each_entry(fd, &func_list, list) {
|
||||
if (!strcmp(fd->name, newf->name))
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
list_add_tail(&newf->list, &func_list);
|
||||
out:
|
||||
mutex_unlock(&func_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_function_register);
|
||||
|
||||
void usb_function_unregister(struct usb_function_driver *fd)
|
||||
{
|
||||
mutex_lock(&func_lock);
|
||||
list_del(&fd->list);
|
||||
mutex_unlock(&func_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_function_unregister);
|
||||
|
|
@ -1308,65 +1308,28 @@ static void init_controller(struct fusb300 *fusb300)
|
|||
iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static struct fusb300 *the_controller;
|
||||
|
||||
static int fusb300_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int fusb300_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct fusb300 *fusb300 = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->max_speed < USB_SPEED_FULL
|
||||
|| !bind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fusb300)
|
||||
return -ENODEV;
|
||||
|
||||
if (fusb300->driver)
|
||||
return -EBUSY;
|
||||
struct fusb300 *fusb300 = to_fusb300(g);
|
||||
|
||||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
fusb300->driver = driver;
|
||||
fusb300->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = device_add(&fusb300->gadget.dev);
|
||||
if (retval) {
|
||||
pr_err("device_add error (%d)\n", retval);
|
||||
goto error;
|
||||
}
|
||||
|
||||
retval = bind(&fusb300->gadget, driver);
|
||||
if (retval) {
|
||||
pr_err("bind to driver error (%d)\n", retval);
|
||||
device_del(&fusb300->gadget.dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fusb300->driver = NULL;
|
||||
fusb300->gadget.dev.driver = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int fusb300_udc_stop(struct usb_gadget_driver *driver)
|
||||
static int fusb300_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct fusb300 *fusb300 = the_controller;
|
||||
|
||||
if (driver != fusb300->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
struct fusb300 *fusb300 = to_fusb300(g);
|
||||
|
||||
driver->unbind(&fusb300->gadget);
|
||||
fusb300->gadget.dev.driver = NULL;
|
||||
|
||||
init_controller(fusb300);
|
||||
device_del(&fusb300->gadget.dev);
|
||||
fusb300->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1378,10 +1341,10 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops fusb300_gadget_ops = {
|
||||
static const struct usb_gadget_ops fusb300_gadget_ops = {
|
||||
.pullup = fusb300_udc_pullup,
|
||||
.start = fusb300_udc_start,
|
||||
.stop = fusb300_udc_stop,
|
||||
.udc_start = fusb300_udc_start,
|
||||
.udc_stop = fusb300_udc_stop,
|
||||
};
|
||||
|
||||
static int __exit fusb300_remove(struct platform_device *pdev)
|
||||
|
|
@ -1505,8 +1468,6 @@ static int __init fusb300_probe(struct platform_device *pdev)
|
|||
fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
|
||||
INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
|
||||
|
||||
the_controller = fusb300;
|
||||
|
||||
fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
|
||||
GFP_KERNEL);
|
||||
if (fusb300->ep0_req == NULL)
|
||||
|
|
@ -1517,9 +1478,19 @@ static int __init fusb300_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
ret = device_add(&fusb300->gadget.dev);
|
||||
if (ret) {
|
||||
pr_err("device_add error (%d)\n", ret);
|
||||
goto err_add_device;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_device:
|
||||
usb_del_gadget_udc(&fusb300->gadget);
|
||||
|
||||
err_add_udc:
|
||||
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
|
||||
|
||||
|
|
@ -1547,15 +1518,4 @@ static struct platform_driver fusb300_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init fusb300_udc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&fusb300_driver, fusb300_probe);
|
||||
}
|
||||
|
||||
module_init(fusb300_udc_init);
|
||||
|
||||
static void __exit fusb300_udc_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&fusb300_driver);
|
||||
}
|
||||
module_exit(fusb300_udc_cleanup);
|
||||
module_platform_driver_probe(fusb300_driver, fusb300_probe);
|
||||
|
|
|
|||
|
|
@ -673,4 +673,6 @@ struct fusb300 {
|
|||
u8 reenum; /* if re-enumeration */
|
||||
};
|
||||
|
||||
#define to_fusb300(g) (container_of((g), struct fusb300, gadget))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,11 +6,34 @@
|
|||
#ifndef __G_ZERO_H
|
||||
#define __G_ZERO_H
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
struct usb_zero_options {
|
||||
unsigned pattern;
|
||||
unsigned isoc_interval;
|
||||
unsigned isoc_maxpacket;
|
||||
unsigned isoc_mult;
|
||||
unsigned isoc_maxburst;
|
||||
unsigned bulk_buflen;
|
||||
unsigned qlen;
|
||||
};
|
||||
|
||||
/* global state */
|
||||
extern unsigned buflen;
|
||||
extern const struct usb_descriptor_header *otg_desc[];
|
||||
struct f_ss_opts {
|
||||
struct usb_function_instance func_inst;
|
||||
unsigned pattern;
|
||||
unsigned isoc_interval;
|
||||
unsigned isoc_maxpacket;
|
||||
unsigned isoc_mult;
|
||||
unsigned isoc_maxburst;
|
||||
unsigned bulk_buflen;
|
||||
};
|
||||
|
||||
struct f_lb_opts {
|
||||
struct usb_function_instance func_inst;
|
||||
unsigned bulk_buflen;
|
||||
unsigned qlen;
|
||||
};
|
||||
|
||||
void lb_modexit(void);
|
||||
int lb_modinit(void);
|
||||
|
||||
/* common utilities */
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
|
||||
|
|
@ -19,8 +42,4 @@ void disable_endpoints(struct usb_composite_dev *cdev,
|
|||
struct usb_ep *in, struct usb_ep *out,
|
||||
struct usb_ep *iso_in, struct usb_ep *iso_out);
|
||||
|
||||
/* configuration-specific linkup */
|
||||
int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
|
||||
int loopback_add(struct usb_composite_dev *cdev, bool autoresume);
|
||||
|
||||
#endif /* __G_ZERO_H */
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ static struct usb_configuration midi_config = {
|
|||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE,
|
||||
.bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
|
||||
.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW,
|
||||
};
|
||||
|
||||
static int __init midi_bind_config(struct usb_configuration *c)
|
||||
|
|
|
|||
|
|
@ -993,14 +993,15 @@ static int goku_get_frame(struct usb_gadget *_gadget)
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int goku_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
|
||||
static int goku_stop(struct usb_gadget_driver *driver);
|
||||
static int goku_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
static int goku_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver);
|
||||
|
||||
static const struct usb_gadget_ops goku_ops = {
|
||||
.get_frame = goku_get_frame,
|
||||
.start = goku_start,
|
||||
.stop = goku_stop,
|
||||
.udc_start = goku_udc_start,
|
||||
.udc_stop = goku_udc_stop,
|
||||
// no remote wakeup
|
||||
// not selfpowered
|
||||
};
|
||||
|
|
@ -1339,50 +1340,28 @@ static void udc_enable(struct goku_udc *dev)
|
|||
* - one function driver, initted second
|
||||
*/
|
||||
|
||||
static struct goku_udc *the_controller;
|
||||
|
||||
/* when a driver is successfully registered, it will receive
|
||||
* control requests including set_configuration(), which enables
|
||||
* non-control requests. then usb traffic follows until a
|
||||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
static int goku_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int goku_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct goku_udc *dev = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->max_speed < USB_SPEED_FULL
|
||||
|| !bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
struct goku_udc *dev = to_goku_udc(g);
|
||||
|
||||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
retval = bind(&dev->gadget, driver);
|
||||
if (retval) {
|
||||
DBG(dev, "bind to driver %s --> error %d\n",
|
||||
driver->driver.name, retval);
|
||||
dev->driver = NULL;
|
||||
dev->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* then enable host detection and ep0; and we're ready
|
||||
/*
|
||||
* then enable host detection and ep0; and we're ready
|
||||
* for set_configuration as well as eventual disconnect.
|
||||
*/
|
||||
udc_enable(dev);
|
||||
|
||||
DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1400,35 +1379,23 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
|
|||
udc_reset (dev);
|
||||
for (i = 0; i < 4; i++)
|
||||
nuke(&dev->ep [i], -ESHUTDOWN);
|
||||
if (driver) {
|
||||
spin_unlock(&dev->lock);
|
||||
driver->disconnect(&dev->gadget);
|
||||
spin_lock(&dev->lock);
|
||||
}
|
||||
|
||||
if (dev->driver)
|
||||
udc_enable(dev);
|
||||
}
|
||||
|
||||
static int goku_stop(struct usb_gadget_driver *driver)
|
||||
static int goku_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct goku_udc *dev = the_controller;
|
||||
struct goku_udc *dev = to_goku_udc(g);
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!driver || driver != dev->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->driver = NULL;
|
||||
stop_activity(dev, driver);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
driver->unbind(&dev->gadget);
|
||||
dev->gadget.dev.driver = NULL;
|
||||
|
||||
DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1754,7 +1721,6 @@ static void goku_remove(struct pci_dev *pdev)
|
|||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
dev->regs = NULL;
|
||||
the_controller = NULL;
|
||||
|
||||
INFO(dev, "unbind\n");
|
||||
}
|
||||
|
|
@ -1770,13 +1736,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
void __iomem *base = NULL;
|
||||
int retval;
|
||||
|
||||
/* if you want to support more than one controller in a system,
|
||||
* usb_gadget_driver_{register,unregister}() must change.
|
||||
*/
|
||||
if (the_controller) {
|
||||
pr_warning("ignoring %s\n", pci_name(pdev));
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!pdev->irq) {
|
||||
printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
|
||||
retval = -ENODEV;
|
||||
|
|
@ -1851,7 +1810,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
|
||||
#endif
|
||||
|
||||
the_controller = dev;
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval) {
|
||||
put_device(&dev->gadget.dev);
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ struct goku_udc {
|
|||
/* statistics... */
|
||||
unsigned long irqs;
|
||||
};
|
||||
#define to_goku_udc(g) (container_of((g), struct goku_udc, gadget))
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ static int __init hidg_plat_driver_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
|
||||
static int hidg_plat_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hidg_func_node *e, *n;
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ static __refdata struct usb_composite_driver hidg_driver = {
|
|||
};
|
||||
|
||||
static struct platform_driver hidg_plat_driver = {
|
||||
.remove = __devexit_p(hidg_plat_driver_remove),
|
||||
.remove = hidg_plat_driver_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hidg",
|
||||
|
|
|
|||
|
|
@ -1334,27 +1334,18 @@ static int imx_udc_start(struct usb_gadget *gadget,
|
|||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct imx_udc_struct *imx_usb;
|
||||
int retval;
|
||||
|
||||
imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
|
||||
/* first hook up the driver ... */
|
||||
imx_usb->driver = driver;
|
||||
imx_usb->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = device_add(&imx_usb->gadget.dev);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
|
||||
__func__, driver->driver.name);
|
||||
|
||||
imx_udc_enable(imx_usb);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
imx_usb->driver = NULL;
|
||||
imx_usb->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int imx_udc_stop(struct usb_gadget *gadget,
|
||||
|
|
@ -1370,8 +1361,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
|
|||
imx_usb->gadget.dev.driver = NULL;
|
||||
imx_usb->driver = NULL;
|
||||
|
||||
device_del(&imx_usb->gadget.dev);
|
||||
|
||||
D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
|
||||
__func__, driver->driver.name);
|
||||
|
||||
|
|
@ -1477,6 +1466,10 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
imx_usb->gadget.dev.parent = &pdev->dev;
|
||||
imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
|
||||
ret = device_add(&imx_usb->gadget.dev);
|
||||
if (retval)
|
||||
goto fail4;
|
||||
|
||||
platform_set_drvdata(pdev, imx_usb);
|
||||
|
||||
usb_init_data(imx_usb);
|
||||
|
|
@ -1488,9 +1481,11 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
|
||||
if (ret)
|
||||
goto fail4;
|
||||
goto fail5;
|
||||
|
||||
return 0;
|
||||
fail5:
|
||||
device_unregister(&imx_usb->gadget.dev);
|
||||
fail4:
|
||||
for (i = 0; i < IMX_USB_NB_EP + 1; i++)
|
||||
free_irq(imx_usb->usbd_int[i], imx_usb);
|
||||
|
|
@ -1514,6 +1509,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
|
|||
int i;
|
||||
|
||||
usb_del_gadget_udc(&imx_usb->gadget);
|
||||
device_unregister(&imx_usb->gadget.dev);
|
||||
imx_udc_disable(imx_usb);
|
||||
del_timer(&imx_usb->timer);
|
||||
|
||||
|
|
@ -1556,17 +1552,7 @@ static struct platform_driver udc_driver = {
|
|||
.resume = imx_udc_resume,
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&udc_driver, imx_udc_probe);
|
||||
}
|
||||
module_init(udc_init);
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
}
|
||||
module_exit(udc_exit);
|
||||
module_platform_driver_probe(udc_driver, imx_udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("IMX USB Device Controller driver");
|
||||
MODULE_AUTHOR("Darius Augulis <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ MODULE_LICENSE ("GPL");
|
|||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#define GADGETFS_MAGIC 0xaee71ee7
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
/* /dev/gadget/$CHIP represents ep0 and the whole device */
|
||||
enum ep0_state {
|
||||
|
|
@ -918,7 +917,6 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
|
|||
if (req->buf != dev->rbuf) {
|
||||
kfree(req->buf);
|
||||
req->buf = dev->rbuf;
|
||||
req->dma = DMA_ADDR_INVALID;
|
||||
}
|
||||
req->complete = epio_complete;
|
||||
dev->setup_out_ready = 0;
|
||||
|
|
@ -1408,7 +1406,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
dev->setup_abort = 1;
|
||||
|
||||
req->buf = dev->rbuf;
|
||||
req->dma = DMA_ADDR_INVALID;
|
||||
req->context = NULL;
|
||||
value = -EOPNOTSUPP;
|
||||
switch (ctrl->bRequest) {
|
||||
|
|
@ -2108,6 +2105,7 @@ static struct file_system_type gadgetfs_type = {
|
|||
.mount = gadgetfs_mount,
|
||||
.kill_sb = gadgetfs_kill_sb,
|
||||
};
|
||||
MODULE_ALIAS_FS("gadgetfs");
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
|||
|
|
@ -2399,7 +2399,7 @@ static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
|
|||
|
||||
if (i < 0) {
|
||||
/* setup processing failed, force stall */
|
||||
dev_err(udc->dev,
|
||||
dev_dbg(udc->dev,
|
||||
"req %02x.%02x protocol STALL; stat %d\n",
|
||||
reqtype, req, i);
|
||||
udc->ep0state = WAIT_FOR_SETUP;
|
||||
|
|
@ -3352,7 +3352,7 @@ phy_fail:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
|
||||
static int lpc32xx_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -3447,7 +3447,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
|
|||
#endif
|
||||
|
||||
static struct platform_driver lpc32xx_udc_driver = {
|
||||
.remove = __devexit_p(lpc32xx_udc_remove),
|
||||
.remove = lpc32xx_udc_remove,
|
||||
.shutdown = lpc32xx_udc_shutdown,
|
||||
.suspend = lpc32xx_udc_suspend,
|
||||
.resume = lpc32xx_udc_resume,
|
||||
|
|
@ -3458,17 +3458,7 @@ static struct platform_driver lpc32xx_udc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init udc_init_module(void)
|
||||
{
|
||||
return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe);
|
||||
}
|
||||
module_init(udc_init_module);
|
||||
|
||||
static void __exit udc_exit_module(void)
|
||||
{
|
||||
platform_driver_unregister(&lpc32xx_udc_driver);
|
||||
}
|
||||
module_exit(udc_exit_module);
|
||||
module_platform_driver_probe(lpc32xx_udc_driver, lpc32xx_udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("LPC32XX udc driver");
|
||||
MODULE_AUTHOR("Kevin Wells <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -1463,42 +1463,16 @@ static struct usb_ep_ops m66592_ep_ops = {
|
|||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct m66592 *the_controller;
|
||||
|
||||
static int m66592_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int m66592_udc_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct m66592 *m66592 = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->max_speed < USB_SPEED_HIGH
|
||||
|| !bind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!m66592)
|
||||
return -ENODEV;
|
||||
if (m66592->driver)
|
||||
return -EBUSY;
|
||||
struct m66592 *m66592 = to_m66592(g);
|
||||
|
||||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
m66592->driver = driver;
|
||||
m66592->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = device_add(&m66592->gadget.dev);
|
||||
if (retval) {
|
||||
pr_err("device_add error (%d)\n", retval);
|
||||
goto error;
|
||||
}
|
||||
|
||||
retval = bind(&m66592->gadget, driver);
|
||||
if (retval) {
|
||||
pr_err("bind to driver error (%d)\n", retval);
|
||||
device_del(&m66592->gadget.dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
|
||||
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
|
||||
m66592_start_xclock(m66592);
|
||||
|
|
@ -1510,26 +1484,12 @@ static int m66592_start(struct usb_gadget_driver *driver,
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
m66592->driver = NULL;
|
||||
m66592->gadget.dev.driver = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int m66592_stop(struct usb_gadget_driver *driver)
|
||||
static int m66592_udc_stop(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct m66592 *m66592 = the_controller;
|
||||
unsigned long flags;
|
||||
|
||||
if (driver != m66592->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&m66592->lock, flags);
|
||||
if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
|
||||
m66592_usb_disconnect(m66592);
|
||||
spin_unlock_irqrestore(&m66592->lock, flags);
|
||||
struct m66592 *m66592 = to_m66592(g);
|
||||
|
||||
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
|
||||
|
||||
|
|
@ -1539,8 +1499,8 @@ static int m66592_stop(struct usb_gadget_driver *driver)
|
|||
init_controller(m66592);
|
||||
disable_controller(m66592);
|
||||
|
||||
device_del(&m66592->gadget.dev);
|
||||
m66592->driver = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1566,10 +1526,10 @@ static int m66592_pullup(struct usb_gadget *gadget, int is_on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops m66592_gadget_ops = {
|
||||
static const struct usb_gadget_ops m66592_gadget_ops = {
|
||||
.get_frame = m66592_get_frame,
|
||||
.start = m66592_start,
|
||||
.stop = m66592_stop,
|
||||
.udc_start = m66592_udc_start,
|
||||
.udc_stop = m66592_udc_stop,
|
||||
.pullup = m66592_pullup,
|
||||
};
|
||||
|
||||
|
|
@ -1578,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev)
|
|||
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
usb_del_gadget_udc(&m66592->gadget);
|
||||
device_del(&m66592->gadget.dev);
|
||||
|
||||
del_timer_sync(&m66592->timer);
|
||||
iounmap(m66592->reg);
|
||||
|
|
@ -1706,8 +1667,6 @@ static int __init m66592_probe(struct platform_device *pdev)
|
|||
m66592->pipenum2ep[0] = &m66592->ep[0];
|
||||
m66592->epaddr2ep[0] = &m66592->ep[0];
|
||||
|
||||
the_controller = m66592;
|
||||
|
||||
m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
|
||||
if (m66592->ep0_req == NULL)
|
||||
goto clean_up3;
|
||||
|
|
@ -1715,6 +1674,12 @@ static int __init m66592_probe(struct platform_device *pdev)
|
|||
|
||||
init_controller(m66592);
|
||||
|
||||
ret = device_add(&m66592->gadget.dev);
|
||||
if (ret) {
|
||||
pr_err("device_add error (%d)\n", ret);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
|
@ -1723,6 +1688,9 @@ static int __init m66592_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
device_del(&m66592->gadget.dev);
|
||||
|
||||
err_device_add:
|
||||
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
|
||||
|
||||
clean_up3:
|
||||
|
|
@ -1753,14 +1721,4 @@ static struct platform_driver m66592_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init m66592_udc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&m66592_driver, m66592_probe);
|
||||
}
|
||||
module_init(m66592_udc_init);
|
||||
|
||||
static void __exit m66592_udc_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&m66592_driver);
|
||||
}
|
||||
module_exit(m66592_udc_cleanup);
|
||||
module_platform_driver_probe(m66592_driver, m66592_probe);
|
||||
|
|
|
|||
|
|
@ -492,6 +492,7 @@ struct m66592 {
|
|||
int isochronous;
|
||||
int num_dma;
|
||||
};
|
||||
#define to_m66592(g) (container_of((g), struct m66592, gadget))
|
||||
|
||||
#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
|
||||
#define m66592_to_gadget(m66592) (&m66592->gadget)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#if defined USB_ETH_RNDIS
|
||||
# undef USB_ETH_RNDIS
|
||||
#endif
|
||||
|
|
@ -42,9 +43,6 @@ MODULE_LICENSE("GPL");
|
|||
*/
|
||||
#include "f_mass_storage.c"
|
||||
|
||||
#include "u_serial.c"
|
||||
#include "f_acm.c"
|
||||
|
||||
#include "f_ecm.c"
|
||||
#include "f_subset.c"
|
||||
#ifdef USB_ETH_RNDIS
|
||||
|
|
@ -137,10 +135,13 @@ static struct fsg_common fsg_common;
|
|||
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
static unsigned char tty_line;
|
||||
static struct usb_function_instance *fi_acm;
|
||||
|
||||
/********** RNDIS **********/
|
||||
|
||||
#ifdef USB_ETH_RNDIS
|
||||
static struct usb_function *f_acm_rndis;
|
||||
|
||||
static __init int rndis_do_config(struct usb_configuration *c)
|
||||
{
|
||||
|
|
@ -155,15 +156,25 @@ static __init int rndis_do_config(struct usb_configuration *c)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = acm_bind_config(c, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
f_acm_rndis = usb_get_function(fi_acm);
|
||||
if (IS_ERR(f_acm_rndis))
|
||||
goto err_func_acm;
|
||||
|
||||
ret = usb_add_function(c, f_acm_rndis);
|
||||
if (ret)
|
||||
goto err_conf;
|
||||
|
||||
ret = fsg_bind_config(c->cdev, c, &fsg_common);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_fsg;
|
||||
|
||||
return 0;
|
||||
err_fsg:
|
||||
usb_remove_function(c, f_acm_rndis);
|
||||
err_conf:
|
||||
usb_put_function(f_acm_rndis);
|
||||
err_func_acm:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rndis_config_register(struct usb_composite_dev *cdev)
|
||||
|
|
@ -192,6 +203,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
|
|||
/********** CDC ECM **********/
|
||||
|
||||
#ifdef CONFIG_USB_G_MULTI_CDC
|
||||
static struct usb_function *f_acm_multi;
|
||||
|
||||
static __init int cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
|
|
@ -206,15 +218,26 @@ static __init int cdc_do_config(struct usb_configuration *c)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = acm_bind_config(c, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* implicit port_num is zero */
|
||||
f_acm_multi = usb_get_function(fi_acm);
|
||||
if (IS_ERR(f_acm_multi))
|
||||
goto err_func_acm;
|
||||
|
||||
ret = usb_add_function(c, f_acm_multi);
|
||||
if (ret)
|
||||
goto err_conf;
|
||||
|
||||
ret = fsg_bind_config(c->cdev, c, &fsg_common);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_fsg;
|
||||
|
||||
return 0;
|
||||
err_fsg:
|
||||
usb_remove_function(c, f_acm_multi);
|
||||
err_conf:
|
||||
usb_put_function(f_acm_multi);
|
||||
err_func_acm:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cdc_config_register(struct usb_composite_dev *cdev)
|
||||
|
|
@ -243,10 +266,10 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
|
|||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
|
||||
static int __ref multi_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct f_serial_opts *opts;
|
||||
int status;
|
||||
|
||||
if (!can_support_ecm(cdev->gadget)) {
|
||||
|
|
@ -261,10 +284,19 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
|
|||
return status;
|
||||
|
||||
/* set up serial link layer */
|
||||
status = gserial_setup(cdev->gadget, 1);
|
||||
status = gserial_alloc_line(&tty_line);
|
||||
if (status < 0)
|
||||
goto fail0;
|
||||
|
||||
fi_acm = usb_get_function_instance("acm");
|
||||
if (IS_ERR(fi_acm)) {
|
||||
status = PTR_ERR(fi_acm);
|
||||
goto fail0dot5;
|
||||
}
|
||||
|
||||
opts = container_of(fi_acm, struct f_serial_opts, func_inst);
|
||||
opts->port_num = tty_line;
|
||||
|
||||
/* set up mass storage function */
|
||||
{
|
||||
void *retp;
|
||||
|
|
@ -301,7 +333,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
|
|||
fail2:
|
||||
fsg_common_put(&fsg_common);
|
||||
fail1:
|
||||
gserial_cleanup();
|
||||
usb_put_function_instance(fi_acm);
|
||||
fail0dot5:
|
||||
gserial_free_line(tty_line);
|
||||
fail0:
|
||||
gether_cleanup();
|
||||
return status;
|
||||
|
|
@ -309,7 +343,14 @@ fail0:
|
|||
|
||||
static int __exit multi_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
gserial_cleanup();
|
||||
#ifdef CONFIG_USB_G_MULTI_CDC
|
||||
usb_put_function(f_acm_multi);
|
||||
#endif
|
||||
#ifdef USB_ETH_RNDIS
|
||||
usb_put_function(f_acm_rndis);
|
||||
#endif
|
||||
usb_put_function_instance(fi_acm);
|
||||
gserial_free_line(tty_line);
|
||||
gether_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1763,7 +1763,7 @@ static void mv_u3d_gadget_release(struct device *dev)
|
|||
dev_dbg(dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static __devexit int mv_u3d_remove(struct platform_device *dev)
|
||||
static int mv_u3d_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mv_u3d *u3d = platform_get_drvdata(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -61,9 +61,6 @@ static DECLARE_COMPLETION(release_done);
|
|||
static const char driver_name[] = "mv_udc";
|
||||
static const char driver_desc[] = DRIVER_DESC;
|
||||
|
||||
/* controller device global variable */
|
||||
static struct mv_udc *the_controller;
|
||||
|
||||
static void nuke(struct mv_ep *ep, int status);
|
||||
static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
|
||||
|
||||
|
|
@ -1012,7 +1009,7 @@ static void udc_clock_enable(struct mv_udc *udc)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < udc->clknum; i++)
|
||||
clk_enable(udc->clk[i]);
|
||||
clk_prepare_enable(udc->clk[i]);
|
||||
}
|
||||
|
||||
static void udc_clock_disable(struct mv_udc *udc)
|
||||
|
|
@ -1020,7 +1017,7 @@ static void udc_clock_disable(struct mv_udc *udc)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < udc->clknum; i++)
|
||||
clk_disable(udc->clk[i]);
|
||||
clk_disable_unprepare(udc->clk[i]);
|
||||
}
|
||||
|
||||
static void udc_stop(struct mv_udc *udc)
|
||||
|
|
@ -1268,9 +1265,8 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int mv_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *));
|
||||
static int mv_udc_stop(struct usb_gadget_driver *driver);
|
||||
static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *);
|
||||
static int mv_udc_stop(struct usb_gadget *, struct usb_gadget_driver *);
|
||||
/* device controller usb_gadget_ops structure */
|
||||
static const struct usb_gadget_ops mv_ops = {
|
||||
|
||||
|
|
@ -1285,8 +1281,8 @@ static const struct usb_gadget_ops mv_ops = {
|
|||
|
||||
/* D+ pullup, software-controlled connect/disconnect to USB host */
|
||||
.pullup = mv_udc_pullup,
|
||||
.start = mv_udc_start,
|
||||
.stop = mv_udc_stop,
|
||||
.udc_start = mv_udc_start,
|
||||
.udc_stop = mv_udc_stop,
|
||||
};
|
||||
|
||||
static int eps_init(struct mv_udc *udc)
|
||||
|
|
@ -1373,15 +1369,14 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
|
|||
}
|
||||
}
|
||||
|
||||
static int mv_udc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *, struct usb_gadget_driver *))
|
||||
static int mv_udc_start(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
udc = container_of(gadget, struct mv_udc, gadget);
|
||||
|
||||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
|
@ -1399,26 +1394,14 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
|
|||
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
retval = bind(&udc->gadget, driver);
|
||||
if (retval) {
|
||||
dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
|
||||
driver->driver.name, retval);
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
if (udc->transceiver) {
|
||||
retval = otg_set_peripheral(udc->transceiver->otg,
|
||||
&udc->gadget);
|
||||
if (retval) {
|
||||
dev_err(&udc->dev->dev,
|
||||
"unable to register peripheral to otg\n");
|
||||
if (driver->unbind) {
|
||||
driver->unbind(&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
}
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
|
@ -1433,13 +1416,13 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mv_udc_stop(struct usb_gadget_driver *driver)
|
||||
static int mv_udc_stop(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
unsigned long flags;
|
||||
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
udc = container_of(gadget, struct mv_udc, gadget);
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
|
||||
|
|
@ -1454,7 +1437,6 @@ static int mv_udc_stop(struct usb_gadget_driver *driver)
|
|||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
/* unbind gadget driver */
|
||||
driver->unbind(&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
|
|
@ -1472,10 +1454,13 @@ static void mv_set_ptc(struct mv_udc *udc, u32 mode)
|
|||
|
||||
static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_ep *mvep = container_of(ep, struct mv_ep, ep);
|
||||
struct mv_req *req = container_of(_req, struct mv_req, req);
|
||||
struct mv_udc *udc;
|
||||
unsigned long flags;
|
||||
|
||||
udc = mvep->udc;
|
||||
|
||||
dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
|
|
@ -2123,15 +2108,18 @@ static void mv_udc_vbus_work(struct work_struct *work)
|
|||
/* release device structure */
|
||||
static void gadget_release(struct device *_dev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
|
||||
udc = dev_get_drvdata(_dev);
|
||||
|
||||
complete(udc->done);
|
||||
}
|
||||
|
||||
static int __devexit mv_udc_remove(struct platform_device *dev)
|
||||
static int mv_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
int clk_i;
|
||||
struct mv_udc *udc;
|
||||
|
||||
udc = platform_get_drvdata(pdev);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
|
|
@ -2140,57 +2128,27 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
|
|||
destroy_workqueue(udc->qwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have transceiver inited,
|
||||
* then vbus irq will not be requested in udc driver.
|
||||
*/
|
||||
if (udc->pdata && udc->pdata->vbus
|
||||
&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
|
||||
free_irq(udc->pdata->vbus->irq, &dev->dev);
|
||||
|
||||
/* free memory allocated in probe */
|
||||
if (udc->dtd_pool)
|
||||
dma_pool_destroy(udc->dtd_pool);
|
||||
|
||||
if (udc->ep_dqh)
|
||||
dma_free_coherent(&dev->dev, udc->ep_dqh_size,
|
||||
dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
|
||||
udc->ep_dqh, udc->ep_dqh_dma);
|
||||
|
||||
kfree(udc->eps);
|
||||
|
||||
if (udc->irq)
|
||||
free_irq(udc->irq, &dev->dev);
|
||||
|
||||
mv_udc_disable(udc);
|
||||
|
||||
if (udc->cap_regs)
|
||||
iounmap(udc->cap_regs);
|
||||
|
||||
if (udc->phy_regs)
|
||||
iounmap(udc->phy_regs);
|
||||
|
||||
if (udc->status_req) {
|
||||
kfree(udc->status_req->req.buf);
|
||||
kfree(udc->status_req);
|
||||
}
|
||||
|
||||
for (clk_i = 0; clk_i <= udc->clknum; clk_i++)
|
||||
clk_put(udc->clk[clk_i]);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
/* free dev, wait for the release() finished */
|
||||
wait_for_completion(udc->done);
|
||||
kfree(udc);
|
||||
|
||||
the_controller = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
static int mv_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mv_usb_platform_data *pdata = dev->dev.platform_data;
|
||||
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct mv_udc *udc;
|
||||
int retval = 0;
|
||||
int clk_i = 0;
|
||||
|
|
@ -2198,71 +2156,73 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
size_t size;
|
||||
|
||||
if (pdata == NULL) {
|
||||
dev_err(&dev->dev, "missing platform_data\n");
|
||||
dev_err(&pdev->dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
|
||||
udc = kzalloc(size, GFP_KERNEL);
|
||||
udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
if (udc == NULL) {
|
||||
dev_err(&dev->dev, "failed to allocate memory for udc\n");
|
||||
dev_err(&pdev->dev, "failed to allocate memory for udc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
the_controller = udc;
|
||||
udc->done = &release_done;
|
||||
udc->pdata = dev->dev.platform_data;
|
||||
udc->pdata = pdev->dev.platform_data;
|
||||
spin_lock_init(&udc->lock);
|
||||
|
||||
udc->dev = dev;
|
||||
udc->dev = pdev;
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (pdata->mode == MV_USB_MODE_OTG)
|
||||
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (pdata->mode == MV_USB_MODE_OTG) {
|
||||
udc->transceiver = devm_usb_get_phy(&pdev->dev,
|
||||
USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
udc->transceiver = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
udc->clknum = pdata->clknum;
|
||||
for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
|
||||
udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
|
||||
udc->clk[clk_i] = devm_clk_get(&pdev->dev,
|
||||
pdata->clkname[clk_i]);
|
||||
if (IS_ERR(udc->clk[clk_i])) {
|
||||
retval = PTR_ERR(udc->clk[clk_i]);
|
||||
goto err_put_clk;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
|
||||
if (r == NULL) {
|
||||
dev_err(&dev->dev, "no I/O memory resource defined\n");
|
||||
retval = -ENODEV;
|
||||
goto err_put_clk;
|
||||
dev_err(&pdev->dev, "no I/O memory resource defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
udc->cap_regs = (struct mv_cap_regs __iomem *)
|
||||
ioremap(r->start, resource_size(r));
|
||||
devm_ioremap(&pdev->dev, r->start, resource_size(r));
|
||||
if (udc->cap_regs == NULL) {
|
||||
dev_err(&dev->dev, "failed to map I/O memory\n");
|
||||
retval = -EBUSY;
|
||||
goto err_put_clk;
|
||||
dev_err(&pdev->dev, "failed to map I/O memory\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
|
||||
if (r == NULL) {
|
||||
dev_err(&dev->dev, "no phy I/O memory resource defined\n");
|
||||
retval = -ENODEV;
|
||||
goto err_iounmap_capreg;
|
||||
dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
udc->phy_regs = ioremap(r->start, resource_size(r));
|
||||
if (udc->phy_regs == NULL) {
|
||||
dev_err(&dev->dev, "failed to map phy I/O memory\n");
|
||||
retval = -EBUSY;
|
||||
goto err_iounmap_capreg;
|
||||
dev_err(&pdev->dev, "failed to map phy I/O memory\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* we will acces controller register, so enable the clk */
|
||||
retval = mv_udc_enable_internal(udc);
|
||||
if (retval)
|
||||
goto err_iounmap_phyreg;
|
||||
return retval;
|
||||
|
||||
udc->op_regs =
|
||||
(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
|
||||
|
|
@ -2279,11 +2239,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
|
||||
size = udc->max_eps * sizeof(struct mv_dqh) *2;
|
||||
size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
|
||||
udc->ep_dqh = dma_alloc_coherent(&dev->dev, size,
|
||||
udc->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
|
||||
&udc->ep_dqh_dma, GFP_KERNEL);
|
||||
|
||||
if (udc->ep_dqh == NULL) {
|
||||
dev_err(&dev->dev, "allocate dQH memory failed\n");
|
||||
dev_err(&pdev->dev, "allocate dQH memory failed\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_disable_clock;
|
||||
}
|
||||
|
|
@ -2291,7 +2251,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
|
||||
/* create dTD dma_pool resource */
|
||||
udc->dtd_pool = dma_pool_create("mv_dtd",
|
||||
&dev->dev,
|
||||
&pdev->dev,
|
||||
sizeof(struct mv_dtd),
|
||||
DTD_ALIGNMENT,
|
||||
DMA_BOUNDARY);
|
||||
|
|
@ -2302,19 +2262,20 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
}
|
||||
|
||||
size = udc->max_eps * sizeof(struct mv_ep) *2;
|
||||
udc->eps = kzalloc(size, GFP_KERNEL);
|
||||
udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
if (udc->eps == NULL) {
|
||||
dev_err(&dev->dev, "allocate ep memory failed\n");
|
||||
dev_err(&pdev->dev, "allocate ep memory failed\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
|
||||
/* initialize ep0 status request structure */
|
||||
udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL);
|
||||
udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req),
|
||||
GFP_KERNEL);
|
||||
if (!udc->status_req) {
|
||||
dev_err(&dev->dev, "allocate status_req memory failed\n");
|
||||
dev_err(&pdev->dev, "allocate status_req memory failed\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_free_eps;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
INIT_LIST_HEAD(&udc->status_req->queue);
|
||||
|
||||
|
|
@ -2329,17 +2290,17 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
|
||||
r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
|
||||
if (r == NULL) {
|
||||
dev_err(&dev->dev, "no IRQ resource defined\n");
|
||||
dev_err(&pdev->dev, "no IRQ resource defined\n");
|
||||
retval = -ENODEV;
|
||||
goto err_free_status_req;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
udc->irq = r->start;
|
||||
if (request_irq(udc->irq, mv_udc_irq,
|
||||
if (devm_request_irq(&pdev->dev, udc->irq, mv_udc_irq,
|
||||
IRQF_SHARED, driver_name, udc)) {
|
||||
dev_err(&dev->dev, "Request irq %d for UDC failed\n",
|
||||
dev_err(&pdev->dev, "Request irq %d for UDC failed\n",
|
||||
udc->irq);
|
||||
retval = -ENODEV;
|
||||
goto err_free_status_req;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
|
||||
/* initialize gadget structure */
|
||||
|
|
@ -2351,26 +2312,27 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&udc->gadget.dev, "gadget");
|
||||
udc->gadget.dev.parent = &dev->dev;
|
||||
udc->gadget.dev.dma_mask = dev->dev.dma_mask;
|
||||
udc->gadget.dev.parent = &pdev->dev;
|
||||
udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
udc->gadget.dev.release = gadget_release;
|
||||
udc->gadget.name = driver_name; /* gadget name */
|
||||
|
||||
retval = device_register(&udc->gadget.dev);
|
||||
if (retval)
|
||||
goto err_free_irq;
|
||||
goto err_destroy_dma;
|
||||
|
||||
eps_init(udc);
|
||||
|
||||
/* VBUS detect: we can disable/enable clock on demand.*/
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
if (udc->transceiver)
|
||||
udc->clock_gating = 1;
|
||||
else if (pdata->vbus) {
|
||||
udc->clock_gating = 1;
|
||||
retval = request_threaded_irq(pdata->vbus->irq, NULL,
|
||||
retval = devm_request_threaded_irq(&pdev->dev,
|
||||
pdata->vbus->irq, NULL,
|
||||
mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
|
||||
if (retval) {
|
||||
dev_info(&dev->dev,
|
||||
dev_info(&pdev->dev,
|
||||
"Can not request irq for VBUS, "
|
||||
"disable clock gating\n");
|
||||
udc->clock_gating = 0;
|
||||
|
|
@ -2378,7 +2340,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
|
||||
udc->qwork = create_singlethread_workqueue("mv_udc_queue");
|
||||
if (!udc->qwork) {
|
||||
dev_err(&dev->dev, "cannot create workqueue\n");
|
||||
dev_err(&pdev->dev, "cannot create workqueue\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
|
|
@ -2396,53 +2358,40 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
|||
else
|
||||
udc->vbus_active = 1;
|
||||
|
||||
retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (retval)
|
||||
goto err_unregister;
|
||||
goto err_create_workqueue;
|
||||
|
||||
dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n",
|
||||
platform_set_drvdata(pdev, udc);
|
||||
dev_info(&pdev->dev, "successful probe UDC device %s clock gating.\n",
|
||||
udc->clock_gating ? "with" : "without");
|
||||
|
||||
return 0;
|
||||
|
||||
err_create_workqueue:
|
||||
destroy_workqueue(udc->qwork);
|
||||
err_unregister:
|
||||
if (udc->pdata && udc->pdata->vbus
|
||||
&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
|
||||
free_irq(pdata->vbus->irq, &dev->dev);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err_free_irq:
|
||||
free_irq(udc->irq, &dev->dev);
|
||||
err_free_status_req:
|
||||
kfree(udc->status_req->req.buf);
|
||||
kfree(udc->status_req);
|
||||
err_free_eps:
|
||||
kfree(udc->eps);
|
||||
err_destroy_dma:
|
||||
dma_pool_destroy(udc->dtd_pool);
|
||||
err_free_dma:
|
||||
dma_free_coherent(&dev->dev, udc->ep_dqh_size,
|
||||
dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
|
||||
udc->ep_dqh, udc->ep_dqh_dma);
|
||||
err_disable_clock:
|
||||
mv_udc_disable_internal(udc);
|
||||
err_iounmap_phyreg:
|
||||
iounmap(udc->phy_regs);
|
||||
err_iounmap_capreg:
|
||||
iounmap(udc->cap_regs);
|
||||
err_put_clk:
|
||||
for (clk_i--; clk_i >= 0; clk_i--)
|
||||
clk_put(udc->clk[clk_i]);
|
||||
the_controller = NULL;
|
||||
kfree(udc);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mv_udc_suspend(struct device *_dev)
|
||||
static int mv_udc_suspend(struct device *dev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
|
||||
udc = dev_get_drvdata(dev);
|
||||
|
||||
/* if OTG is enabled, the following will be done in OTG driver*/
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
if (udc->transceiver)
|
||||
return 0;
|
||||
|
||||
if (udc->pdata->vbus && udc->pdata->vbus->poll)
|
||||
|
|
@ -2469,13 +2418,15 @@ static int mv_udc_suspend(struct device *_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mv_udc_resume(struct device *_dev)
|
||||
static int mv_udc_resume(struct device *dev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
int retval;
|
||||
|
||||
udc = dev_get_drvdata(dev);
|
||||
|
||||
/* if OTG is enabled, the following will be done in OTG driver*/
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
if (udc->transceiver)
|
||||
return 0;
|
||||
|
||||
if (!udc->clock_gating) {
|
||||
|
|
@ -2499,11 +2450,12 @@ static const struct dev_pm_ops mv_udc_pm_ops = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static void mv_udc_shutdown(struct platform_device *dev)
|
||||
static void mv_udc_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct mv_udc *udc = the_controller;
|
||||
struct mv_udc *udc;
|
||||
u32 mode;
|
||||
|
||||
udc = platform_get_drvdata(pdev);
|
||||
/* reset controller mode to IDLE */
|
||||
mv_udc_enable(udc);
|
||||
mode = readl(&udc->op_regs->usbmode);
|
||||
|
|
@ -2514,7 +2466,7 @@ static void mv_udc_shutdown(struct platform_device *dev)
|
|||
|
||||
static struct platform_driver udc_driver = {
|
||||
.probe = mv_udc_probe,
|
||||
.remove = __exit_p(mv_udc_remove),
|
||||
.remove = mv_udc_remove,
|
||||
.shutdown = mv_udc_shutdown,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -2193,7 +2193,7 @@ net2272_gadget_release(struct device *_dev)
|
|||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static void __devexit
|
||||
static void
|
||||
net2272_remove(struct net2272 *dev)
|
||||
{
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
|
|
@ -2215,8 +2215,7 @@ net2272_remove(struct net2272 *dev)
|
|||
dev_info(dev->dev, "unbind\n");
|
||||
}
|
||||
|
||||
static struct net2272 * __devinit
|
||||
net2272_probe_init(struct device *dev, unsigned int irq)
|
||||
static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
|
||||
{
|
||||
struct net2272 *ret;
|
||||
|
||||
|
|
@ -2246,7 +2245,7 @@ net2272_probe_init(struct device *dev, unsigned int irq)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
static int
|
||||
net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -2306,7 +2305,7 @@ err_add_udc:
|
|||
* don't respond over USB until a gadget driver binds to us
|
||||
*/
|
||||
|
||||
static int __devinit
|
||||
static int
|
||||
net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev)
|
||||
{
|
||||
unsigned long resource, len, tmp;
|
||||
|
|
@ -2389,7 +2388,7 @@ net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
static int
|
||||
net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev)
|
||||
{
|
||||
unsigned long resource, len;
|
||||
|
|
@ -2447,7 +2446,7 @@ net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
static int
|
||||
net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct net2272 *dev;
|
||||
|
|
@ -2489,7 +2488,7 @@ net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit
|
||||
static void
|
||||
net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -2511,7 +2510,7 @@ net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void __devexit
|
||||
static void
|
||||
net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -2530,7 +2529,7 @@ net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev)
|
|||
pci_resource_len(pdev, i));
|
||||
}
|
||||
|
||||
static void __devexit
|
||||
static void
|
||||
net2272_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net2272 *dev = pci_get_drvdata(pdev);
|
||||
|
|
@ -2549,7 +2548,7 @@ net2272_pci_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
/* Table of matching PCI IDs */
|
||||
static struct pci_device_id __devinitdata pci_ids[] = {
|
||||
static struct pci_device_id pci_ids[] = {
|
||||
{ /* RDK 1 card */
|
||||
.class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe),
|
||||
.class_mask = 0,
|
||||
|
|
@ -2575,7 +2574,7 @@ static struct pci_driver net2272_pci_driver = {
|
|||
.id_table = pci_ids,
|
||||
|
||||
.probe = net2272_pci_probe,
|
||||
.remove = __devexit_p(net2272_pci_remove),
|
||||
.remove = net2272_pci_remove,
|
||||
};
|
||||
|
||||
static int net2272_pci_register(void)
|
||||
|
|
@ -2595,7 +2594,7 @@ static inline void net2272_pci_unregister(void) { }
|
|||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit
|
||||
static int
|
||||
net2272_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct net2272 *dev;
|
||||
|
|
@ -2661,7 +2660,7 @@ net2272_plat_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit
|
||||
static int
|
||||
net2272_plat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net2272 *dev = platform_get_drvdata(pdev);
|
||||
|
|
@ -2678,7 +2677,7 @@ net2272_plat_remove(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver net2272_plat_driver = {
|
||||
.probe = net2272_plat_probe,
|
||||
.remove = __devexit_p(net2272_plat_remove),
|
||||
.remove = net2272_plat_remove,
|
||||
.driver = {
|
||||
.name = driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* CODE STATUS HIGHLIGHTS
|
||||
*
|
||||
* This driver should work well with most "gadget" drivers, including
|
||||
* the File Storage, Serial, and Ethernet/RNDIS gadget drivers
|
||||
* the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
|
||||
* as well as Gadget Zero and Gadgetfs.
|
||||
*
|
||||
* DMA is enabled by default. Drivers using transfer queues might use
|
||||
|
|
@ -116,6 +116,10 @@ static bool enable_suspend = 0;
|
|||
/* "modprobe net2280 enable_suspend=1" etc */
|
||||
module_param (enable_suspend, bool, S_IRUGO);
|
||||
|
||||
/* force full-speed operation */
|
||||
static bool full_speed;
|
||||
module_param(full_speed, bool, 0444);
|
||||
MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
|
||||
|
||||
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
|
||||
|
||||
|
|
@ -1899,6 +1903,10 @@ static int net2280_start(struct usb_gadget *_gadget,
|
|||
retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
|
||||
if (retval) goto err_func;
|
||||
|
||||
/* Enable force-full-speed testing mode, if desired */
|
||||
if (full_speed)
|
||||
writel(1 << FORCE_FULL_SPEED_MODE, &dev->usb->xcvrdiag);
|
||||
|
||||
/* ... then enable host detection and ep0; and we're ready
|
||||
* for set_configuration as well as eventual disconnect.
|
||||
*/
|
||||
|
|
@ -1957,6 +1965,10 @@ static int net2280_stop(struct usb_gadget *_gadget,
|
|||
dev->driver = NULL;
|
||||
|
||||
net2280_led_active (dev, 0);
|
||||
|
||||
/* Disable full-speed test mode */
|
||||
writel(0, &dev->usb->xcvrdiag);
|
||||
|
||||
device_remove_file (&dev->pdev->dev, &dev_attr_function);
|
||||
device_remove_file (&dev->pdev->dev, &dev_attr_queues);
|
||||
|
||||
|
|
@ -2841,6 +2853,9 @@ static void net2280_shutdown (struct pci_dev *pdev)
|
|||
|
||||
/* disable the pullup so the host will think we're gone */
|
||||
writel (0, &dev->usb->usbctl);
|
||||
|
||||
/* Disable full-speed test mode */
|
||||
writel(0, &dev->usb->xcvrdiag);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue