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:
Dmitry Torokhov 2013-03-17 19:40:50 -07:00
commit 688d794c4c
17348 changed files with 1080737 additions and 591285 deletions

View file

@ -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

View file

@ -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/

View file

@ -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",

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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", },
};

View file

@ -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);

View file

@ -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",
},

View file

@ -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)
};
/**

View file

@ -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;
}

View file

@ -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));

View file

@ -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,

View file

@ -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.

View file

@ -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 */
},

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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
View 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);
}

View file

@ -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
View 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);
}

View file

@ -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 },

View file

@ -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,

View file

@ -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;

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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),
},
};

View file

@ -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 */

View file

@ -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;

View file

@ -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),
},
};

View file

@ -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,
},
};

View file

@ -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]>");

View file

@ -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;

View file

@ -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(&params, 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, &params);
@ -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(&params, 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);
}

View file

@ -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;

View file

@ -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];

View file

@ -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.

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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];

View file

@ -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");

View file

@ -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)");

View file

@ -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,

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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
}

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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,

View file

@ -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);

View file

@ -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");

View file

@ -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[] = {

View file

@ -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)

View file

@ -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;
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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)
{

View file

@ -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");

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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,

View file

@ -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,
},
};

View file

@ -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)
{

View 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);

View file

@ -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);

View file

@ -673,4 +673,6 @@ struct fusb300 {
u8 reenum; /* if re-enumeration */
};
#define to_fusb300(g) (container_of((g), struct fusb300, gadget))
#endif

View file

@ -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 */

View file

@ -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)

View file

@ -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);

View file

@ -261,6 +261,7 @@ struct goku_udc {
/* statistics... */
unsigned long irqs;
};
#define to_goku_udc(g) (container_of((g), struct goku_udc, gadget))
/*-------------------------------------------------------------------------*/

View file

@ -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",

View file

@ -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]>");

View file

@ -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");
/*----------------------------------------------------------------------*/

View file

@ -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]>");

View file

@ -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);

View file

@ -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)

View file

@ -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;
}

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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