mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
USB patches for 3.10-rc1
Here's the big USB pull request for 3.10-rc1. Lots of USB patches here, the majority being USB gadget changes and USB-serial driver cleanups, the rest being ARM build fixes / cleanups, and individual driver updates. We also finally got some chipidea fixes, which have been delayed for a number of kernel releases, as the maintainer has now reappeared. All of these have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iEYEABECAAYFAlF+md4ACgkQMUfUDdst+ymkSgCfZWIiCtiX/li0yJqSiRB4yYJx Ex0AoNemOOf6ywvSOHPbILTbJ1G+c/PX =JmvB -----END PGP SIGNATURE----- Merge tag 'usb-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg Kroah-Hartman: "Here's the big USB pull request for 3.10-rc1. Lots of USB patches here, the majority being USB gadget changes and USB-serial driver cleanups, the rest being ARM build fixes / cleanups, and individual driver updates. We also finally got some chipidea fixes, which have been delayed for a number of kernel releases, as the maintainer has now reappeared. All of these have been in linux-next for a while" * tag 'usb-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (568 commits) USB: ehci-msm: USB_MSM_OTG needs USB_PHY USB: OHCI: avoid conflicting platform drivers USB: OMAP: ISP1301 needs USB_PHY USB: lpc32xx: ISP1301 needs USB_PHY USB: ftdi_sio: enable two UART ports on ST Microconnect Lite usb: phy: tegra: don't call into tegra-ehci directly usb: phy: phy core cannot yet be a module USB: Fix initconst in ehci driver usb-storage: CY7C68300A chips do not support Cypress ATACB USB: serial: option: Added support Olivetti Olicard 145 USB: ftdi_sio: correct ST Micro Connect Lite PIDs ARM: mxs_defconfig: add CONFIG_USB_PHY ARM: imx_v6_v7_defconfig: add CONFIG_USB_PHY usb: phy: remove exported function from __init section usb: gadget: zero: put function instances on unbind usb: gadget: f_sourcesink.c: correct a copy-paste misnomer usb: gadget: cdc2: fix error return code in cdc_do_config() usb: gadget: multi: fix error return code in rndis_do_config() usb: gadget: f_obex: fix error return code in obex_bind() USB: storage: convert to use module_usb_driver() ...
This commit is contained in:
commit
ec25e246b9
323 changed files with 10495 additions and 9849 deletions
|
|
@ -122,9 +122,9 @@ config USB
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called usbcore.
|
||||
|
||||
source "drivers/usb/core/Kconfig"
|
||||
if USB
|
||||
|
||||
source "drivers/usb/dwc3/Kconfig"
|
||||
source "drivers/usb/core/Kconfig"
|
||||
|
||||
source "drivers/usb/mon/Kconfig"
|
||||
|
||||
|
|
@ -134,8 +134,6 @@ source "drivers/usb/host/Kconfig"
|
|||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/chipidea/Kconfig"
|
||||
|
||||
source "drivers/usb/renesas_usbhs/Kconfig"
|
||||
|
||||
source "drivers/usb/class/Kconfig"
|
||||
|
|
@ -144,12 +142,19 @@ source "drivers/usb/storage/Kconfig"
|
|||
|
||||
source "drivers/usb/image/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
source "drivers/usb/dwc3/Kconfig"
|
||||
|
||||
source "drivers/usb/chipidea/Kconfig"
|
||||
|
||||
comment "USB port drivers"
|
||||
depends on USB
|
||||
|
||||
if USB
|
||||
|
||||
config USB_USS720
|
||||
tristate "USS720 parport driver"
|
||||
depends on USB && PARPORT
|
||||
depends on PARPORT
|
||||
select PARPORT_NOT_PC
|
||||
---help---
|
||||
This driver is for USB parallel port adapters that use the Lucent
|
||||
|
|
@ -180,12 +185,12 @@ source "drivers/usb/serial/Kconfig"
|
|||
|
||||
source "drivers/usb/misc/Kconfig"
|
||||
|
||||
source "drivers/usb/phy/Kconfig"
|
||||
|
||||
source "drivers/usb/atm/Kconfig"
|
||||
|
||||
endif # USB
|
||||
|
||||
source "drivers/usb/phy/Kconfig"
|
||||
|
||||
source "drivers/usb/gadget/Kconfig"
|
||||
|
||||
source "drivers/usb/otg/Kconfig"
|
||||
|
||||
endif # USB_SUPPORT
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
obj-$(CONFIG_USB) += core/
|
||||
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += otg/
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3/
|
||||
|
||||
obj-$(CONFIG_USB_MON) += mon/
|
||||
|
|
@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
|
|||
obj-$(CONFIG_USB_SERIAL) += serial/
|
||||
|
||||
obj-$(CONFIG_USB) += misc/
|
||||
obj-$(CONFIG_USB_OTG_UTILS) += phy/
|
||||
obj-$(CONFIG_USB_PHY) += phy/
|
||||
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
|
||||
|
||||
obj-$(CONFIG_USB_ATM) += atm/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
menuconfig USB_ATM
|
||||
tristate "USB DSL modem support"
|
||||
depends on USB && ATM
|
||||
depends on ATM
|
||||
select CRC32
|
||||
default n
|
||||
help
|
||||
|
|
|
|||
|
|
@ -672,9 +672,6 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|||
struct usbatm_control *ctrl = UDSL_SKB(skb);
|
||||
int err;
|
||||
|
||||
vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
|
||||
skb, skb->len);
|
||||
|
||||
/* racy disconnection check - fine */
|
||||
if (!instance || instance->disconnected) {
|
||||
#ifdef DEBUG
|
||||
|
|
@ -684,6 +681,9 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
|
||||
skb, skb->len);
|
||||
|
||||
if (vcc->qos.aal != ATM_AAL5) {
|
||||
atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
|
||||
err = -EINVAL;
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)
|
|||
endif
|
||||
|
||||
ifneq ($(CONFIG_OF_DEVICE),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
/******************************************************************************
|
||||
* DEFINE
|
||||
*****************************************************************************/
|
||||
#define TD_PAGE_COUNT 5
|
||||
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
|
||||
#define ENDPT_MAX 32
|
||||
|
||||
|
|
@ -129,6 +130,7 @@ struct hw_bank {
|
|||
* @vbus_active: is VBUS active
|
||||
* @transceiver: pointer to USB PHY, if any
|
||||
* @hcd: pointer to usb_hcd for ehci host driver
|
||||
* @debugfs: root dentry for this controller in debugfs
|
||||
*/
|
||||
struct ci13xxx {
|
||||
struct device *dev;
|
||||
|
|
@ -139,7 +141,6 @@ struct ci13xxx {
|
|||
enum ci_role role;
|
||||
bool is_otg;
|
||||
struct work_struct work;
|
||||
struct work_struct vbus_work;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
struct dma_pool *qh_pool;
|
||||
|
|
@ -165,6 +166,7 @@ struct ci13xxx {
|
|||
bool global_phy;
|
||||
struct usb_phy *transceiver;
|
||||
struct usb_hcd *hcd;
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
|
||||
|
|
@ -233,19 +235,6 @@ enum ci13xxx_regs {
|
|||
OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* ffs_nr: find first (least significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This function returns bit number (instead of position)
|
||||
*/
|
||||
static inline int ffs_nr(u32 x)
|
||||
{
|
||||
int n = ffs(x);
|
||||
|
||||
return n ? n-1 : 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_read: reads from a hw register
|
||||
* @reg: register index
|
||||
|
|
@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
|||
u32 val = hw_read(ci, reg, ~0);
|
||||
|
||||
hw_write(ci, reg, mask, data);
|
||||
return (val & mask) >> ffs_nr(mask);
|
||||
return (val & mask) >> __ffs(mask);
|
||||
}
|
||||
|
||||
int hw_device_reset(struct ci13xxx *ci, u32 mode);
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
|
|||
if (of_find_property(np, "disable-over-current", NULL))
|
||||
usbdev->disable_oc = 1;
|
||||
|
||||
if (of_find_property(np, "external-vbus-divider", NULL))
|
||||
usbdev->evdo = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
|
||||
|
|
@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (usbmisc_ops && usbmisc_ops->post) {
|
||||
ret = usbmisc_ops->post(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"usbmisc post failed, ret=%d\n", ret);
|
||||
goto put_np;
|
||||
}
|
||||
}
|
||||
|
||||
data->ci_pdev = plat_ci;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
struct usbmisc_ops {
|
||||
/* It's called once when probe a usb device */
|
||||
int (*init)(struct device *dev);
|
||||
/* It's called once after adding a usb device */
|
||||
int (*post)(struct device *dev);
|
||||
};
|
||||
|
||||
struct usbmisc_usb_device {
|
||||
|
|
@ -20,6 +22,7 @@ struct usbmisc_usb_device {
|
|||
int index;
|
||||
|
||||
unsigned int disable_oc:1; /* over current detect disabled */
|
||||
unsigned int evdo:1; /* set external vbus divider option */
|
||||
};
|
||||
|
||||
int usbmisc_set_ops(const struct usbmisc_ops *ops);
|
||||
|
|
|
|||
|
|
@ -23,17 +23,17 @@
|
|||
/******************************************************************************
|
||||
* PCI block
|
||||
*****************************************************************************/
|
||||
struct ci13xxx_platform_data pci_platdata = {
|
||||
static struct ci13xxx_platform_data pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
struct ci13xxx_platform_data langwell_pci_platdata = {
|
||||
static struct ci13xxx_platform_data langwell_pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = 0,
|
||||
};
|
||||
|
||||
struct ci13xxx_platform_data penwell_pci_platdata = {
|
||||
static struct ci13xxx_platform_data penwell_pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = 0,
|
||||
.power_budget = 200,
|
||||
|
|
|
|||
|
|
@ -51,15 +51,12 @@
|
|||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
|
@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
|
|||
if (mode > TEST_MODE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
|
||||
hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
|
|||
*/
|
||||
u8 hw_port_test_get(struct ci13xxx *ci)
|
||||
{
|
||||
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
|
||||
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
|
||||
}
|
||||
|
||||
static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
|
||||
|
|
@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
|
|||
|
||||
ci->hw_bank.cap = ci->hw_bank.abs;
|
||||
ci->hw_bank.cap += ci->platdata->capoffset;
|
||||
ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
|
||||
ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);
|
||||
|
||||
hw_alloc_regmap(ci, false);
|
||||
reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
|
||||
ffs_nr(HCCPARAMS_LEN);
|
||||
__ffs(HCCPARAMS_LEN);
|
||||
ci->hw_bank.lpm = reg;
|
||||
hw_alloc_regmap(ci, !!reg);
|
||||
ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
|
||||
|
|
@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
|
|||
ci->hw_bank.size /= sizeof(u32);
|
||||
|
||||
reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
|
||||
ffs_nr(DCCPARAMS_DEN);
|
||||
__ffs(DCCPARAMS_DEN);
|
||||
ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
|
||||
|
||||
if (ci->hw_ep_max > ENDPT_MAX)
|
||||
|
|
@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t show_role(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *ci = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", ci_role(ci)->name);
|
||||
}
|
||||
|
||||
static ssize_t store_role(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ci13xxx *ci = dev_get_drvdata(dev);
|
||||
enum ci_role role;
|
||||
int ret;
|
||||
|
||||
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
|
||||
if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
|
||||
break;
|
||||
|
||||
if (role == CI_ROLE_END || role == ci->role)
|
||||
return -EINVAL;
|
||||
|
||||
ci_role_stop(ci);
|
||||
ret = ci_role_start(ci, role);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
|
||||
|
||||
static irqreturn_t ci_irq(int irq, void *data)
|
||||
{
|
||||
struct ci13xxx *ci = data;
|
||||
|
|
@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
base = devm_request_and_ioremap(dev, res);
|
||||
if (!base) {
|
||||
dev_err(dev, "can't request and ioremap resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
|
||||
if (!ci) {
|
||||
|
|
@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto stop;
|
||||
|
||||
ret = device_create_file(dev, &dev_attr_role);
|
||||
if (ret)
|
||||
goto rm_attr;
|
||||
|
||||
if (ci->is_otg)
|
||||
hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
|
||||
|
||||
return ret;
|
||||
ret = dbg_create_files(ci);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
rm_attr:
|
||||
device_remove_file(dev, &dev_attr_role);
|
||||
free_irq(ci->irq, ci);
|
||||
stop:
|
||||
ci_role_stop(ci);
|
||||
rm_wq:
|
||||
|
|
@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ci13xxx *ci = platform_get_drvdata(pdev);
|
||||
|
||||
dbg_remove_files(ci);
|
||||
flush_workqueue(ci->wq);
|
||||
destroy_workqueue(ci->wq);
|
||||
device_remove_file(ci->dev, &dev_attr_role);
|
||||
free_irq(ci->irq, ci);
|
||||
ci_role_stop(ci);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,590 +1,126 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
|
||||
#include "ci.h"
|
||||
#include "udc.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Interrupt statistics */
|
||||
#define ISR_MASK 0x1F
|
||||
static struct isr_statistics {
|
||||
u32 test;
|
||||
u32 ui;
|
||||
u32 uei;
|
||||
u32 pci;
|
||||
u32 uri;
|
||||
u32 sli;
|
||||
u32 none;
|
||||
struct {
|
||||
u32 cnt;
|
||||
u32 buf[ISR_MASK+1];
|
||||
u32 idx;
|
||||
} hndl;
|
||||
} isr_statistics;
|
||||
|
||||
void dbg_interrupt(u32 intmask)
|
||||
{
|
||||
if (!intmask) {
|
||||
isr_statistics.none++;
|
||||
return;
|
||||
}
|
||||
|
||||
isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
|
||||
isr_statistics.hndl.idx &= ISR_MASK;
|
||||
isr_statistics.hndl.cnt++;
|
||||
|
||||
if (USBi_URI & intmask)
|
||||
isr_statistics.uri++;
|
||||
if (USBi_PCI & intmask)
|
||||
isr_statistics.pci++;
|
||||
if (USBi_UEI & intmask)
|
||||
isr_statistics.uei++;
|
||||
if (USBi_UI & intmask)
|
||||
isr_statistics.ui++;
|
||||
if (USBi_SLI & intmask)
|
||||
isr_statistics.sli++;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_register_read: reads all device registers (execute without interruption)
|
||||
* @buf: destination buffer
|
||||
* @size: buffer size
|
||||
*
|
||||
* This function returns number of registers read
|
||||
* ci_device_show: prints information about device capabilities and status
|
||||
*/
|
||||
static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
|
||||
static int ci_device_show(struct seq_file *s, void *data)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (size > ci->hw_bank.size)
|
||||
size = ci->hw_bank.size;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
buf[i] = hw_read(ci, i * sizeof(u32), ~0);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_register_write: writes to register
|
||||
* @addr: register address
|
||||
* @data: register value
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
|
||||
{
|
||||
/* align */
|
||||
addr /= sizeof(u32);
|
||||
|
||||
if (addr >= ci->hw_bank.size)
|
||||
return -EINVAL;
|
||||
|
||||
/* align */
|
||||
addr *= sizeof(u32);
|
||||
|
||||
hw_write(ci, addr, ~0, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_intr_clear: disables interrupt & clears interrupt status (execute without
|
||||
* interruption)
|
||||
* @n: interrupt bit
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_intr_clear(struct ci13xxx *ci, int n)
|
||||
{
|
||||
if (n >= REG_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
hw_write(ci, OP_USBINTR, BIT(n), 0);
|
||||
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_intr_force: enables interrupt & forces interrupt status (execute without
|
||||
* interruption)
|
||||
* @n: interrupt bit
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_intr_force(struct ci13xxx *ci, int n)
|
||||
{
|
||||
if (n >= REG_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
|
||||
hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
|
||||
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
|
||||
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* show_device: prints information about device capabilities and status
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t show_device(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = s->private;
|
||||
struct usb_gadget *gadget = &ci->gadget;
|
||||
int n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
seq_printf(s, "speed = %d\n", gadget->speed);
|
||||
seq_printf(s, "max_speed = %d\n", gadget->max_speed);
|
||||
seq_printf(s, "is_otg = %d\n", gadget->is_otg);
|
||||
seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral);
|
||||
seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable);
|
||||
seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support);
|
||||
seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
|
||||
seq_printf(s, "name = %s\n",
|
||||
(gadget->name ? gadget->name : ""));
|
||||
|
||||
if (!ci->driver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
|
||||
gadget->speed);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
|
||||
gadget->max_speed);
|
||||
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",
|
||||
gadget->is_a_peripheral);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
|
||||
gadget->b_hnp_enable);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
|
||||
gadget->a_hnp_support);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
|
||||
gadget->a_alt_hnp_support);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
|
||||
(gadget->name ? gadget->name : ""));
|
||||
seq_printf(s, "gadget function = %s\n",
|
||||
(ci->driver->function ? ci->driver->function : ""));
|
||||
seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed);
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
|
||||
|
||||
/**
|
||||
* show_driver: prints information about attached gadget (if any)
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
static int ci_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct usb_gadget_driver *driver = ci->driver;
|
||||
int n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (driver == NULL)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"There is no gadget attached!\n");
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
|
||||
(driver->function ? driver->function : ""));
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
|
||||
driver->max_speed);
|
||||
|
||||
return n;
|
||||
return single_open(file, ci_device_show, inode->i_private);
|
||||
}
|
||||
static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
|
||||
|
||||
/* Maximum event message length */
|
||||
#define DBG_DATA_MSG 64UL
|
||||
|
||||
/* Maximum event messages */
|
||||
#define DBG_DATA_MAX 128UL
|
||||
|
||||
/* Event buffer descriptor */
|
||||
static struct {
|
||||
char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
|
||||
unsigned idx; /* index */
|
||||
unsigned tty; /* print to console? */
|
||||
rwlock_t lck; /* lock */
|
||||
} dbg_data = {
|
||||
.idx = 0,
|
||||
.tty = 0,
|
||||
.lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
|
||||
static const struct file_operations ci_device_fops = {
|
||||
.open = ci_device_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* dbg_dec: decrements debug event index
|
||||
* @idx: buffer index
|
||||
* ci_port_test_show: reads port test mode
|
||||
*/
|
||||
static void dbg_dec(unsigned *idx)
|
||||
static int ci_port_test_show(struct seq_file *s, void *data)
|
||||
{
|
||||
*idx = (*idx - 1) & (DBG_DATA_MAX-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_inc: increments debug event index
|
||||
* @idx: buffer index
|
||||
*/
|
||||
static void dbg_inc(unsigned *idx)
|
||||
{
|
||||
*idx = (*idx + 1) & (DBG_DATA_MAX-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_print: prints the common part of the event
|
||||
* @addr: endpoint address
|
||||
* @name: event name
|
||||
* @status: status
|
||||
* @extra: extra information
|
||||
*/
|
||||
static void dbg_print(u8 addr, const char *name, int status, const char *extra)
|
||||
{
|
||||
struct timeval tval;
|
||||
unsigned int stamp;
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&dbg_data.lck, flags);
|
||||
|
||||
do_gettimeofday(&tval);
|
||||
stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
|
||||
stamp = stamp * 1000000 + tval.tv_usec;
|
||||
|
||||
scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
|
||||
"%04X\t? %02X %-7.7s %4i ?\t%s\n",
|
||||
stamp, addr, name, status, extra);
|
||||
|
||||
dbg_inc(&dbg_data.idx);
|
||||
|
||||
write_unlock_irqrestore(&dbg_data.lck, flags);
|
||||
|
||||
if (dbg_data.tty != 0)
|
||||
pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
|
||||
stamp, addr, name, status, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_done: prints a DONE event
|
||||
* @addr: endpoint address
|
||||
* @td: transfer descriptor
|
||||
* @status: status
|
||||
*/
|
||||
void dbg_done(u8 addr, const u32 token, int status)
|
||||
{
|
||||
char msg[DBG_DATA_MSG];
|
||||
|
||||
scnprintf(msg, sizeof(msg), "%d %02X",
|
||||
(int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
|
||||
(int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
|
||||
dbg_print(addr, "DONE", status, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_event: prints a generic event
|
||||
* @addr: endpoint address
|
||||
* @name: event name
|
||||
* @status: status
|
||||
*/
|
||||
void dbg_event(u8 addr, const char *name, int status)
|
||||
{
|
||||
if (name != NULL)
|
||||
dbg_print(addr, name, status, "");
|
||||
}
|
||||
|
||||
/*
|
||||
* dbg_queue: prints a QUEUE event
|
||||
* @addr: endpoint address
|
||||
* @req: USB request
|
||||
* @status: status
|
||||
*/
|
||||
void dbg_queue(u8 addr, const struct usb_request *req, int status)
|
||||
{
|
||||
char msg[DBG_DATA_MSG];
|
||||
|
||||
if (req != NULL) {
|
||||
scnprintf(msg, sizeof(msg),
|
||||
"%d %d", !req->no_interrupt, req->length);
|
||||
dbg_print(addr, "QUEUE", status, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_setup: prints a SETUP event
|
||||
* @addr: endpoint address
|
||||
* @req: setup request
|
||||
*/
|
||||
void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
|
||||
{
|
||||
char msg[DBG_DATA_MSG];
|
||||
|
||||
if (req != NULL) {
|
||||
scnprintf(msg, sizeof(msg),
|
||||
"%02X %02X %04X %04X %d", req->bRequestType,
|
||||
req->bRequest, le16_to_cpu(req->wValue),
|
||||
le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
|
||||
dbg_print(addr, "SETUP", 0, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show_events: displays the event buffer
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t show_events(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned i, j, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(dev->parent, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_lock_irqsave(&dbg_data.lck, flags);
|
||||
|
||||
i = dbg_data.idx;
|
||||
for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
|
||||
n += strlen(dbg_data.buf[i]);
|
||||
if (n >= PAGE_SIZE) {
|
||||
n -= strlen(dbg_data.buf[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
|
||||
j += scnprintf(buf + j, PAGE_SIZE - j,
|
||||
"%s", dbg_data.buf[i]);
|
||||
|
||||
read_unlock_irqrestore(&dbg_data.lck, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* store_events: configure if events are going to be also printed to console
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t store_events(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned tty;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(dev, "[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
|
||||
dev_err(dev, "<1|0>: enable|disable console log\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
dbg_data.tty = tty;
|
||||
dev_info(dev, "tty = %u", dbg_data.tty);
|
||||
|
||||
done:
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
|
||||
|
||||
/**
|
||||
* show_inters: interrupt status, enable status and historic
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
u32 intr;
|
||||
unsigned i, j, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
|
||||
/*n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"status = %08x\n", hw_read_intr_status(ci));
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"enable = %08x\n", hw_read_intr_enable(ci));*/
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
|
||||
isr_statistics.test);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
|
||||
isr_statistics.ui);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
|
||||
isr_statistics.uei);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
|
||||
isr_statistics.pci);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
|
||||
isr_statistics.uri);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
|
||||
isr_statistics.sli);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
|
||||
isr_statistics.none);
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
|
||||
isr_statistics.hndl.cnt);
|
||||
|
||||
for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
|
||||
i &= ISR_MASK;
|
||||
intr = isr_statistics.hndl.buf[i];
|
||||
|
||||
if (USBi_UI & intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
|
||||
intr &= ~USBi_UI;
|
||||
if (USBi_UEI & intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
|
||||
intr &= ~USBi_UEI;
|
||||
if (USBi_PCI & intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
|
||||
intr &= ~USBi_PCI;
|
||||
if (USBi_URI & intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
|
||||
intr &= ~USBi_URI;
|
||||
if (USBi_SLI & intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
|
||||
intr &= ~USBi_SLI;
|
||||
if (intr)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
|
||||
if (isr_statistics.hndl.buf[i])
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* store_inters: enable & force or disable an individual interrutps
|
||||
* (to be used for test purposes only)
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
unsigned en, bit;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "EINVAL\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
|
||||
dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (en) {
|
||||
if (hw_intr_force(ci, bit))
|
||||
dev_err(dev, "invalid bit number\n");
|
||||
else
|
||||
isr_statistics.test++;
|
||||
} else {
|
||||
if (hw_intr_clear(ci, bit))
|
||||
dev_err(dev, "invalid bit number\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
|
||||
|
||||
/**
|
||||
* show_port_test: reads port test mode
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t show_port_test(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = s->private;
|
||||
unsigned long flags;
|
||||
unsigned mode;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "EINVAL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
mode = hw_port_test_get(ci);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
|
||||
seq_printf(s, "mode = %u\n", mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* store_port_test: writes port test mode
|
||||
*
|
||||
* Check "device.h" for details
|
||||
* ci_port_test_write: writes port test mode
|
||||
*/
|
||||
static ssize_t store_port_test(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct seq_file *s = file->private_data;
|
||||
struct ci13xxx *ci = s->private;
|
||||
unsigned long flags;
|
||||
unsigned mode;
|
||||
char buf[32];
|
||||
int ret;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
if (sscanf(buf, "%u", &mode) != 1) {
|
||||
dev_err(ci->dev, "<mode>: set port test mode");
|
||||
goto done;
|
||||
}
|
||||
if (sscanf(buf, "%u", &mode) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (hw_port_test_set(ci, mode))
|
||||
dev_err(ci->dev, "invalid mode\n");
|
||||
ret = hw_port_test_set(ci, mode);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
return ret ? ret : count;
|
||||
}
|
||||
static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
|
||||
show_port_test, store_port_test);
|
||||
|
||||
static int ci_port_test_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ci_port_test_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ci_port_test_fops = {
|
||||
.open = ci_port_test_open,
|
||||
.write = ci_port_test_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* show_qheads: DMA contents of all queue heads
|
||||
*
|
||||
* Check "device.h" for details
|
||||
* ci_qheads_show: DMA contents of all queue heads
|
||||
*/
|
||||
static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
static int ci_qheads_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = s->private;
|
||||
unsigned long flags;
|
||||
unsigned i, j, n = 0;
|
||||
unsigned i, j;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
if (ci->role != CI_ROLE_GADGET) {
|
||||
seq_printf(s, "not in gadget mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
|
|||
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
|
||||
struct ci13xxx_ep *mEpTx =
|
||||
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"EP=%02i: RX=%08X TX=%08X\n",
|
||||
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
|
||||
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
" %04X: %08X %08X\n", j,
|
||||
*((u32 *)mEpRx->qh.ptr + j),
|
||||
*((u32 *)mEpTx->qh.ptr + j));
|
||||
}
|
||||
seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
|
||||
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
|
||||
for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
|
||||
seq_printf(s, " %04X: %08X %08X\n", j,
|
||||
*((u32 *)mEpRx->qh.ptr + j),
|
||||
*((u32 *)mEpTx->qh.ptr + j));
|
||||
}
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
|
||||
|
||||
/**
|
||||
* show_registers: dumps all registers
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
#define DUMP_ENTRIES 512
|
||||
static ssize_t show_registers(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
u32 *dump;
|
||||
unsigned i, k, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
|
||||
if (!dump) {
|
||||
dev_err(ci->dev, "%s: out of memory\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
k = hw_register_read(ci, dump, DUMP_ENTRIES);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
for (i = 0; i < k; i++) {
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"reg[0x%04X] = 0x%08X\n",
|
||||
i * (unsigned)sizeof(u32), dump[i]);
|
||||
}
|
||||
kfree(dump);
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* store_registers: writes value to register address
|
||||
*
|
||||
* Check "device.h" for details
|
||||
*/
|
||||
static ssize_t store_registers(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int ci_qheads_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long addr, data, flags;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%li %li", &addr, &data) != 2) {
|
||||
dev_err(ci->dev,
|
||||
"<addr> <data>: write data to register address\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (hw_register_write(ci, addr, data))
|
||||
dev_err(ci->dev, "invalid address range\n");
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
return single_open(file, ci_qheads_show, inode->i_private);
|
||||
}
|
||||
static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
|
||||
show_registers, store_registers);
|
||||
|
||||
static const struct file_operations ci_qheads_fops = {
|
||||
.open = ci_qheads_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* show_requests: DMA contents of all requests currently queued (all endpts)
|
||||
*
|
||||
* Check "device.h" for details
|
||||
* ci_requests_show: DMA contents of all requests currently queued (all endpts)
|
||||
*/
|
||||
static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
static int ci_requests_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = s->private;
|
||||
unsigned long flags;
|
||||
struct list_head *ptr = NULL;
|
||||
struct ci13xxx_req *req = NULL;
|
||||
unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
|
||||
unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
if (ci->role != CI_ROLE_GADGET) {
|
||||
seq_printf(s, "not in gadget mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
for (i = 0; i < ci->hw_ep_max; i++)
|
||||
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
|
||||
{
|
||||
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
|
||||
req = list_entry(ptr, struct ci13xxx_req, queue);
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"EP=%02i: TD=%08X %s\n",
|
||||
i % ci->hw_ep_max/2, (u32)req->dma,
|
||||
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
|
||||
seq_printf(s, "EP=%02i: TD=%08X %s\n",
|
||||
i % (ci->hw_ep_max / 2), (u32)req->dma,
|
||||
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
|
||||
|
||||
for (j = 0; j < qSize; j++)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
" %04X: %08X\n", j,
|
||||
*((u32 *)req->ptr + j));
|
||||
for (j = 0; j < qsize; j++)
|
||||
seq_printf(s, " %04X: %08X\n", j,
|
||||
*((u32 *)req->ptr + j));
|
||||
}
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
return 0;
|
||||
}
|
||||
static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
|
||||
|
||||
static int ci_requests_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ci_requests_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ci_requests_fops = {
|
||||
.open = ci_requests_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int ci_role_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct ci13xxx *ci = s->private;
|
||||
|
||||
seq_printf(s, "%s\n", ci_role(ci)->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct ci13xxx *ci = s->private;
|
||||
enum ci_role role;
|
||||
char buf[8];
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
|
||||
return -EFAULT;
|
||||
|
||||
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
|
||||
if (ci->roles[role] &&
|
||||
!strncmp(buf, ci->roles[role]->name,
|
||||
strlen(ci->roles[role]->name)))
|
||||
break;
|
||||
|
||||
if (role == CI_ROLE_END || role == ci->role)
|
||||
return -EINVAL;
|
||||
|
||||
ci_role_stop(ci);
|
||||
ret = ci_role_start(ci, role);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static int ci_role_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ci_role_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ci_role_fops = {
|
||||
.open = ci_role_open,
|
||||
.write = ci_role_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* dbg_create_files: initializes the attribute interface
|
||||
* @dev: device
|
||||
* @ci: device
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
int dbg_create_files(struct device *dev)
|
||||
int dbg_create_files(struct ci13xxx *ci)
|
||||
{
|
||||
int retval = 0;
|
||||
struct dentry *dent;
|
||||
|
||||
if (dev == NULL)
|
||||
return -EINVAL;
|
||||
retval = device_create_file(dev, &dev_attr_device);
|
||||
if (retval)
|
||||
goto done;
|
||||
retval = device_create_file(dev, &dev_attr_driver);
|
||||
if (retval)
|
||||
goto rm_device;
|
||||
retval = device_create_file(dev, &dev_attr_events);
|
||||
if (retval)
|
||||
goto rm_driver;
|
||||
retval = device_create_file(dev, &dev_attr_inters);
|
||||
if (retval)
|
||||
goto rm_events;
|
||||
retval = device_create_file(dev, &dev_attr_port_test);
|
||||
if (retval)
|
||||
goto rm_inters;
|
||||
retval = device_create_file(dev, &dev_attr_qheads);
|
||||
if (retval)
|
||||
goto rm_port_test;
|
||||
retval = device_create_file(dev, &dev_attr_registers);
|
||||
if (retval)
|
||||
goto rm_qheads;
|
||||
retval = device_create_file(dev, &dev_attr_requests);
|
||||
if (retval)
|
||||
goto rm_registers;
|
||||
return 0;
|
||||
ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
|
||||
if (!ci->debugfs)
|
||||
return -ENOMEM;
|
||||
|
||||
rm_registers:
|
||||
device_remove_file(dev, &dev_attr_registers);
|
||||
rm_qheads:
|
||||
device_remove_file(dev, &dev_attr_qheads);
|
||||
rm_port_test:
|
||||
device_remove_file(dev, &dev_attr_port_test);
|
||||
rm_inters:
|
||||
device_remove_file(dev, &dev_attr_inters);
|
||||
rm_events:
|
||||
device_remove_file(dev, &dev_attr_events);
|
||||
rm_driver:
|
||||
device_remove_file(dev, &dev_attr_driver);
|
||||
rm_device:
|
||||
device_remove_file(dev, &dev_attr_device);
|
||||
done:
|
||||
return retval;
|
||||
dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
|
||||
&ci_device_fops);
|
||||
if (!dent)
|
||||
goto err;
|
||||
|
||||
dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
|
||||
ci, &ci_port_test_fops);
|
||||
if (!dent)
|
||||
goto err;
|
||||
|
||||
dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
|
||||
&ci_qheads_fops);
|
||||
if (!dent)
|
||||
goto err;
|
||||
|
||||
dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
|
||||
&ci_requests_fops);
|
||||
if (!dent)
|
||||
goto err;
|
||||
|
||||
dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
|
||||
&ci_role_fops);
|
||||
if (dent)
|
||||
return 0;
|
||||
err:
|
||||
debugfs_remove_recursive(ci->debugfs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* dbg_remove_files: destroys the attribute interface
|
||||
* @dev: device
|
||||
*
|
||||
* This function returns an error code
|
||||
* @ci: device
|
||||
*/
|
||||
int dbg_remove_files(struct device *dev)
|
||||
void dbg_remove_files(struct ci13xxx *ci)
|
||||
{
|
||||
if (dev == NULL)
|
||||
return -EINVAL;
|
||||
device_remove_file(dev, &dev_attr_requests);
|
||||
device_remove_file(dev, &dev_attr_registers);
|
||||
device_remove_file(dev, &dev_attr_qheads);
|
||||
device_remove_file(dev, &dev_attr_port_test);
|
||||
device_remove_file(dev, &dev_attr_inters);
|
||||
device_remove_file(dev, &dev_attr_events);
|
||||
device_remove_file(dev, &dev_attr_driver);
|
||||
device_remove_file(dev, &dev_attr_device);
|
||||
return 0;
|
||||
debugfs_remove_recursive(ci->debugfs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,42 +14,16 @@
|
|||
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
|
||||
|
||||
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
|
||||
void dbg_interrupt(u32 intmask);
|
||||
void dbg_done(u8 addr, const u32 token, int status);
|
||||
void dbg_event(u8 addr, const char *name, int status);
|
||||
void dbg_queue(u8 addr, const struct usb_request *req, int status);
|
||||
void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
|
||||
int dbg_create_files(struct device *dev);
|
||||
int dbg_remove_files(struct device *dev);
|
||||
int dbg_create_files(struct ci13xxx *ci);
|
||||
void dbg_remove_files(struct ci13xxx *ci);
|
||||
#else
|
||||
static inline void dbg_interrupt(u32 intmask)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dbg_done(u8 addr, const u32 token, int status)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dbg_event(u8 addr, const char *name, int status)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dbg_create_files(struct device *dev)
|
||||
static inline int dbg_create_files(struct ci13xxx *ci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dbg_remove_files(struct device *dev)
|
||||
static inline void dbg_remove_files(struct ci13xxx *ci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,8 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
|
@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
|
|||
|
||||
if (dir) {
|
||||
mask = ENDPTCTRL_TXT; /* type */
|
||||
data = type << ffs_nr(mask);
|
||||
data = type << __ffs(mask);
|
||||
|
||||
mask |= ENDPTCTRL_TXS; /* unstall */
|
||||
mask |= ENDPTCTRL_TXR; /* reset data toggle */
|
||||
|
|
@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
|
|||
data |= ENDPTCTRL_TXE;
|
||||
} else {
|
||||
mask = ENDPTCTRL_RXT; /* type */
|
||||
data = type << ffs_nr(mask);
|
||||
data = type << __ffs(mask);
|
||||
|
||||
mask |= ENDPTCTRL_RXS; /* unstall */
|
||||
mask |= ENDPTCTRL_RXR; /* reset data toggle */
|
||||
|
|
@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
|
|||
return reg;
|
||||
}
|
||||
|
||||
static void hw_enable_vbus_intr(struct ci13xxx *ci)
|
||||
{
|
||||
hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
|
||||
hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
|
||||
queue_work(ci->wq, &ci->vbus_work);
|
||||
}
|
||||
|
||||
static void hw_disable_vbus_intr(struct ci13xxx *ci)
|
||||
{
|
||||
hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_test_and_clear_setup_guard: test & clear setup guard (execute without
|
||||
* interruption)
|
||||
|
|
@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
|
|||
static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
|
||||
{
|
||||
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
|
||||
value << ffs_nr(DEVICEADDR_USBADR));
|
||||
value << __ffs(DEVICEADDR_USBADR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void vbus_work(struct work_struct *work)
|
||||
{
|
||||
struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
|
||||
|
||||
if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
|
||||
usb_gadget_vbus_connect(&ci->gadget);
|
||||
else
|
||||
usb_gadget_vbus_disconnect(&ci->gadget);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* UTIL block
|
||||
*****************************************************************************/
|
||||
|
|
@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
|||
return -ENOMEM;
|
||||
|
||||
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
|
||||
mReq->zptr->next = TD_TERMINATE;
|
||||
mReq->zptr->token = TD_STATUS_ACTIVE;
|
||||
mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
|
||||
mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
|
||||
if (!mReq->req.no_interrupt)
|
||||
mReq->zptr->token |= TD_IOC;
|
||||
mReq->zptr->token |= cpu_to_le32(TD_IOC);
|
||||
}
|
||||
ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
|
||||
if (ret)
|
||||
|
|
@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
|||
* TODO - handle requests which spawns into several TDs
|
||||
*/
|
||||
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
|
||||
mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
|
||||
mReq->ptr->token &= TD_TOTAL_BYTES;
|
||||
mReq->ptr->token |= TD_STATUS_ACTIVE;
|
||||
mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
|
||||
mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
|
||||
mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
|
||||
if (mReq->zptr) {
|
||||
mReq->ptr->next = mReq->zdma;
|
||||
mReq->ptr->next = cpu_to_le32(mReq->zdma);
|
||||
} else {
|
||||
mReq->ptr->next = TD_TERMINATE;
|
||||
mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
|
||||
if (!mReq->req.no_interrupt)
|
||||
mReq->ptr->token |= TD_IOC;
|
||||
mReq->ptr->token |= cpu_to_le32(TD_IOC);
|
||||
}
|
||||
mReq->ptr->page[0] = mReq->req.dma;
|
||||
for (i = 1; i < 5; i++)
|
||||
mReq->ptr->page[i] =
|
||||
(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
|
||||
mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
|
||||
for (i = 1; i < TD_PAGE_COUNT; i++) {
|
||||
u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
|
||||
page &= ~TD_RESERVED_MASK;
|
||||
mReq->ptr->page[i] = cpu_to_le32(page);
|
||||
}
|
||||
|
||||
wmb();
|
||||
|
||||
if (!list_empty(&mEp->qh.queue)) {
|
||||
struct ci13xxx_req *mReqPrev;
|
||||
int n = hw_ep_bit(mEp->num, mEp->dir);
|
||||
int tmp_stat;
|
||||
u32 next = mReq->dma & TD_ADDR_MASK;
|
||||
|
||||
mReqPrev = list_entry(mEp->qh.queue.prev,
|
||||
struct ci13xxx_req, queue);
|
||||
if (mReqPrev->zptr)
|
||||
mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
|
||||
mReqPrev->zptr->next = cpu_to_le32(next);
|
||||
else
|
||||
mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
|
||||
mReqPrev->ptr->next = cpu_to_le32(next);
|
||||
wmb();
|
||||
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
|
||||
goto done;
|
||||
|
|
@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
|||
}
|
||||
|
||||
/* QH configuration */
|
||||
mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
|
||||
mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
|
||||
mEp->qh.ptr->cap |= QH_ZLT;
|
||||
mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
|
||||
mEp->qh.ptr->td.token &=
|
||||
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
|
||||
|
||||
wmb(); /* synchronize before ep prime */
|
||||
|
||||
|
|
@ -506,14 +483,16 @@ done:
|
|||
*/
|
||||
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
||||
{
|
||||
u32 tmptoken = le32_to_cpu(mReq->ptr->token);
|
||||
|
||||
if (mReq->req.status != -EALREADY)
|
||||
return -EINVAL;
|
||||
|
||||
if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
|
||||
if ((TD_STATUS_ACTIVE & tmptoken) != 0)
|
||||
return -EBUSY;
|
||||
|
||||
if (mReq->zptr) {
|
||||
if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
|
||||
if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
|
||||
return -EBUSY;
|
||||
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
|
||||
mReq->zptr = NULL;
|
||||
|
|
@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
|||
|
||||
usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
|
||||
|
||||
mReq->req.status = mReq->ptr->token & TD_STATUS;
|
||||
mReq->req.status = tmptoken & TD_STATUS;
|
||||
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
|
||||
mReq->req.status = -1;
|
||||
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
|
||||
|
|
@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
|
|||
else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
|
||||
mReq->req.status = -1;
|
||||
|
||||
mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
|
||||
mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
|
||||
mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
|
||||
mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
|
||||
mReq->req.actual = mReq->req.length - mReq->req.actual;
|
||||
mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
|
||||
|
||||
|
|
@ -561,6 +540,12 @@ __acquires(mEp->lock)
|
|||
struct ci13xxx_req *mReq = \
|
||||
list_entry(mEp->qh.queue.next,
|
||||
struct ci13xxx_req, queue);
|
||||
|
||||
if (mReq->zptr) {
|
||||
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
|
||||
mReq->zptr = NULL;
|
||||
}
|
||||
|
||||
list_del_init(&mReq->queue);
|
||||
mReq->req.status = -ESHUTDOWN;
|
||||
|
||||
|
|
@ -629,8 +614,6 @@ __acquires(ci->lock)
|
|||
{
|
||||
int retval;
|
||||
|
||||
dbg_event(0xFF, "BUS RST", 0);
|
||||
|
||||
spin_unlock(&ci->lock);
|
||||
retval = _gadget_stop_activity(&ci->gadget);
|
||||
if (retval)
|
||||
|
|
@ -667,6 +650,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
usb_ep_free_request(ep, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* _ep_queue: queues (submits) an I/O request to an endpoint
|
||||
*
|
||||
* Caller must hold lock
|
||||
*/
|
||||
static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
|
||||
gfp_t __maybe_unused gfp_flags)
|
||||
{
|
||||
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
|
||||
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
|
||||
struct ci13xxx *ci = mEp->ci;
|
||||
int retval = 0;
|
||||
|
||||
if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
|
||||
if (req->length)
|
||||
mEp = (ci->ep0_dir == RX) ?
|
||||
ci->ep0out : ci->ep0in;
|
||||
if (!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
|
||||
_usb_addr(mEp));
|
||||
}
|
||||
}
|
||||
|
||||
/* first nuke then test link, e.g. previous status has not sent */
|
||||
if (!list_empty(&mReq->queue)) {
|
||||
dev_err(mEp->ci->dev, "request already in queue\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
|
||||
dev_err(mEp->ci->dev, "request bigger than one td\n");
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* push request */
|
||||
mReq->req.status = -EINPROGRESS;
|
||||
mReq->req.actual = 0;
|
||||
|
||||
retval = _hardware_enqueue(mEp, mReq);
|
||||
|
||||
if (retval == -EALREADY)
|
||||
retval = 0;
|
||||
if (!retval)
|
||||
list_add_tail(&mReq->queue, &mEp->qh.queue);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* isr_get_status_response: get_status request response
|
||||
* @ci: ci struct
|
||||
|
|
@ -714,9 +750,7 @@ __acquires(mEp->lock)
|
|||
}
|
||||
/* else do nothing; reserved for future use */
|
||||
|
||||
spin_unlock(mEp->lock);
|
||||
retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
|
||||
spin_lock(mEp->lock);
|
||||
retval = _ep_queue(&mEp->ep, req, gfp_flags);
|
||||
if (retval)
|
||||
goto err_free_buf;
|
||||
|
||||
|
|
@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
* This function returns an error code
|
||||
*/
|
||||
static int isr_setup_status_phase(struct ci13xxx *ci)
|
||||
__releases(mEp->lock)
|
||||
__acquires(mEp->lock)
|
||||
{
|
||||
int retval;
|
||||
struct ci13xxx_ep *mEp;
|
||||
|
|
@ -773,9 +805,7 @@ __acquires(mEp->lock)
|
|||
ci->status->context = ci;
|
||||
ci->status->complete = isr_setup_status_complete;
|
||||
|
||||
spin_unlock(mEp->lock);
|
||||
retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
|
||||
spin_lock(mEp->lock);
|
||||
retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -801,7 +831,6 @@ __acquires(mEp->lock)
|
|||
if (retval < 0)
|
||||
break;
|
||||
list_del_init(&mReq->queue);
|
||||
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
|
||||
if (mReq->req.complete != NULL) {
|
||||
spin_unlock(mEp->lock);
|
||||
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
|
||||
|
|
@ -814,8 +843,6 @@ __acquires(mEp->lock)
|
|||
|
||||
if (retval == -EBUSY)
|
||||
retval = 0;
|
||||
if (retval < 0)
|
||||
dbg_event(_usb_addr(mEp), "DONE", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -847,8 +874,6 @@ __acquires(ci->lock)
|
|||
if (err > 0) /* needs status phase */
|
||||
err = isr_setup_status_phase(ci);
|
||||
if (err < 0) {
|
||||
dbg_event(_usb_addr(mEp),
|
||||
"ERROR", err);
|
||||
spin_unlock(&ci->lock);
|
||||
if (usb_ep_set_halt(&mEp->ep))
|
||||
dev_err(ci->dev,
|
||||
|
|
@ -884,8 +909,6 @@ __acquires(ci->lock)
|
|||
|
||||
ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
|
||||
|
||||
dbg_setup(_usb_addr(mEp), &req);
|
||||
|
||||
switch (req.bRequest) {
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
|
||||
|
|
@ -997,8 +1020,6 @@ delegate:
|
|||
}
|
||||
|
||||
if (err < 0) {
|
||||
dbg_event(_usb_addr(mEp), "ERROR", err);
|
||||
|
||||
spin_unlock(&ci->lock);
|
||||
if (usb_ep_set_halt(&mEp->ep))
|
||||
dev_err(ci->dev, "error: ep_set_halt\n");
|
||||
|
|
@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep,
|
|||
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
u32 cap = 0;
|
||||
|
||||
if (ep == NULL || desc == NULL)
|
||||
return -EINVAL;
|
||||
|
|
@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep,
|
|||
|
||||
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "ENABLE", 0);
|
||||
|
||||
mEp->qh.ptr->cap = 0;
|
||||
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
|
||||
mEp->qh.ptr->cap |= QH_IOS;
|
||||
else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
|
||||
mEp->qh.ptr->cap &= ~QH_MULT;
|
||||
else
|
||||
mEp->qh.ptr->cap &= ~QH_ZLT;
|
||||
cap |= QH_IOS;
|
||||
if (mEp->num)
|
||||
cap |= QH_ZLT;
|
||||
cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
|
||||
|
||||
mEp->qh.ptr->cap |=
|
||||
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
|
||||
mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
|
||||
mEp->qh.ptr->cap = cpu_to_le32(cap);
|
||||
|
||||
mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
|
||||
|
||||
/*
|
||||
* Enable endpoints in the HW other than ep0 as ep0
|
||||
|
|
@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep)
|
|||
|
||||
direction = mEp->dir;
|
||||
do {
|
||||
dbg_event(_usb_addr(mEp), "DISABLE", 0);
|
||||
|
||||
retval |= _ep_nuke(mEp);
|
||||
retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
|
||||
|
||||
|
|
@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
|
|||
}
|
||||
}
|
||||
|
||||
dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
|
||||
|
||||
return (mReq == NULL) ? NULL : &mReq->req;
|
||||
}
|
||||
|
||||
|
|
@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
|
|||
dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
|
||||
kfree(mReq);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "FREE", 0);
|
||||
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|||
gfp_t __maybe_unused gfp_flags)
|
||||
{
|
||||
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
|
||||
struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
|
||||
struct ci13xxx *ci = mEp->ci;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
|
||||
if (req->length)
|
||||
mEp = (ci->ep0_dir == RX) ?
|
||||
ci->ep0out : ci->ep0in;
|
||||
if (!list_empty(&mEp->qh.queue)) {
|
||||
_ep_nuke(mEp);
|
||||
retval = -EOVERFLOW;
|
||||
dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
|
||||
_usb_addr(mEp));
|
||||
}
|
||||
}
|
||||
|
||||
/* first nuke then test link, e.g. previous status has not sent */
|
||||
if (!list_empty(&mReq->queue)) {
|
||||
retval = -EBUSY;
|
||||
dev_err(mEp->ci->dev, "request already in queue\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (req->length > 4 * CI13XXX_PAGE_SIZE) {
|
||||
req->length = 4 * CI13XXX_PAGE_SIZE;
|
||||
retval = -EMSGSIZE;
|
||||
dev_warn(mEp->ci->dev, "request length truncated\n");
|
||||
}
|
||||
|
||||
dbg_queue(_usb_addr(mEp), req, retval);
|
||||
|
||||
/* push request */
|
||||
mReq->req.status = -EINPROGRESS;
|
||||
mReq->req.actual = 0;
|
||||
|
||||
retval = _hardware_enqueue(mEp, mReq);
|
||||
|
||||
if (retval == -EALREADY) {
|
||||
dbg_event(_usb_addr(mEp), "QUEUE", retval);
|
||||
retval = 0;
|
||||
}
|
||||
if (!retval)
|
||||
list_add_tail(&mReq->queue, &mEp->qh.queue);
|
||||
|
||||
done:
|
||||
retval = _ep_queue(ep, req, gfp_flags);
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
|||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
|
||||
|
||||
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
|
||||
|
||||
/* pop request */
|
||||
|
|
@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)
|
|||
|
||||
direction = mEp->dir;
|
||||
do {
|
||||
dbg_event(_usb_addr(mEp), "HALT", value);
|
||||
retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
|
||||
|
||||
if (!value)
|
||||
|
|
@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep)
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "WEDGE", 0);
|
||||
mEp->wedge = 1;
|
||||
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
|
||||
return usb_ep_set_halt(ep);
|
||||
|
|
@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep)
|
|||
|
||||
spin_lock_irqsave(mEp->lock, flags);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
|
||||
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
|
||||
|
||||
spin_unlock_irqrestore(mEp->lock, flags);
|
||||
|
|
@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
|
|||
if (is_active) {
|
||||
pm_runtime_get_sync(&_gadget->dev);
|
||||
hw_device_reset(ci, USBMODE_CM_DC);
|
||||
hw_enable_vbus_intr(ci);
|
||||
hw_device_state(ci, ci->ep0out->qh.dma);
|
||||
} else {
|
||||
hw_device_state(ci, 0);
|
||||
|
|
@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
|
|||
pm_runtime_get_sync(&ci->gadget.dev);
|
||||
if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
|
||||
if (ci->vbus_active) {
|
||||
if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
|
||||
if (ci->platdata->flags & CI13XXX_REGS_SHARED)
|
||||
hw_device_reset(ci, USBMODE_CM_DC);
|
||||
hw_enable_vbus_intr(ci);
|
||||
}
|
||||
} else {
|
||||
pm_runtime_put_sync(&ci->gadget.dev);
|
||||
goto done;
|
||||
|
|
@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
|
|||
}
|
||||
}
|
||||
intr = hw_test_and_clear_intr_active(ci);
|
||||
dbg_interrupt(intr);
|
||||
|
||||
if (intr) {
|
||||
/* order defines priority - do NOT change it */
|
||||
|
|
@ -1676,28 +1633,11 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
|
|||
} else {
|
||||
retval = IRQ_NONE;
|
||||
}
|
||||
|
||||
intr = hw_read(ci, OP_OTGSC, ~0);
|
||||
hw_write(ci, OP_OTGSC, ~0, intr);
|
||||
|
||||
if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
|
||||
queue_work(ci->wq, &ci->vbus_work);
|
||||
|
||||
spin_unlock(&ci->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* udc_release: driver release function
|
||||
* @dev: device
|
||||
*
|
||||
* Currently does nothing
|
||||
*/
|
||||
static void udc_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* udc_start: initialize gadget role
|
||||
* @ci: chipidea controller
|
||||
|
|
@ -1717,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
|
|||
|
||||
INIT_LIST_HEAD(&ci->gadget.ep_list);
|
||||
|
||||
dev_set_name(&ci->gadget.dev, "gadget");
|
||||
ci->gadget.dev.dma_mask = dev->dma_mask;
|
||||
ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
|
||||
ci->gadget.dev.parent = dev;
|
||||
ci->gadget.dev.release = udc_release;
|
||||
|
||||
/* alloc resources */
|
||||
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
|
||||
sizeof(struct ci13xxx_qh),
|
||||
|
|
@ -1758,24 +1692,13 @@ static int udc_start(struct ci13xxx *ci)
|
|||
retval = hw_device_reset(ci, USBMODE_CM_DC);
|
||||
if (retval)
|
||||
goto put_transceiver;
|
||||
hw_enable_vbus_intr(ci);
|
||||
}
|
||||
|
||||
retval = device_register(&ci->gadget.dev);
|
||||
if (retval) {
|
||||
put_device(&ci->gadget.dev);
|
||||
goto put_transceiver;
|
||||
}
|
||||
|
||||
retval = dbg_create_files(ci->dev);
|
||||
if (retval)
|
||||
goto unreg_device;
|
||||
|
||||
if (!IS_ERR_OR_NULL(ci->transceiver)) {
|
||||
retval = otg_set_peripheral(ci->transceiver->otg,
|
||||
&ci->gadget);
|
||||
if (retval)
|
||||
goto remove_dbg;
|
||||
goto put_transceiver;
|
||||
}
|
||||
|
||||
retval = usb_add_gadget_udc(dev, &ci->gadget);
|
||||
|
|
@ -1795,10 +1718,6 @@ remove_trans:
|
|||
}
|
||||
|
||||
dev_err(dev, "error = %i\n", retval);
|
||||
remove_dbg:
|
||||
dbg_remove_files(ci->dev);
|
||||
unreg_device:
|
||||
device_unregister(&ci->gadget.dev);
|
||||
put_transceiver:
|
||||
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
|
||||
usb_put_phy(ci->transceiver);
|
||||
|
|
@ -1821,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci)
|
|||
if (ci == NULL)
|
||||
return;
|
||||
|
||||
hw_disable_vbus_intr(ci);
|
||||
cancel_work_sync(&ci->vbus_work);
|
||||
|
||||
usb_del_gadget_udc(&ci->gadget);
|
||||
|
||||
destroy_eps(ci);
|
||||
|
|
@ -1836,8 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
|
|||
if (ci->global_phy)
|
||||
usb_put_phy(ci->transceiver);
|
||||
}
|
||||
dbg_remove_files(ci->dev);
|
||||
device_unregister(&ci->gadget.dev);
|
||||
/* my kobject is dynamic, I swear! */
|
||||
memset(&ci->gadget, 0, sizeof(ci->gadget));
|
||||
}
|
||||
|
|
@ -1864,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
|
|||
rdrv->irq = udc_irq;
|
||||
rdrv->name = "gadget";
|
||||
ci->roles[CI_ROLE_GADGET] = rdrv;
|
||||
INIT_WORK(&ci->vbus_work, vbus_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct ci13xxx_td {
|
|||
#define TD_CURR_OFFSET (0x0FFFUL << 0)
|
||||
#define TD_FRAME_NUM (0x07FFUL << 0)
|
||||
#define TD_RESERVED_MASK (0x0FFFUL << 0)
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed, aligned(4)));
|
||||
|
||||
/* DMA layout of queue heads */
|
||||
struct ci13xxx_qh {
|
||||
|
|
@ -57,7 +57,7 @@ struct ci13xxx_qh {
|
|||
/* 9 */
|
||||
u32 RESERVED;
|
||||
struct usb_ctrlrequest setup;
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed, aligned(4)));
|
||||
|
||||
/**
|
||||
* struct ci13xxx_req - usb request representation
|
||||
|
|
|
|||
261
drivers/usb/chipidea/usbmisc_imx.c
Normal file
261
drivers/usb/chipidea/usbmisc_imx.c
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ci13xxx_imx.h"
|
||||
|
||||
#define USB_DEV_MAX 4
|
||||
|
||||
#define MX25_USB_PHY_CTRL_OFFSET 0x08
|
||||
#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
|
||||
|
||||
#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
|
||||
#define MX53_USB_UH2_CTRL_OFFSET 0x14
|
||||
#define MX53_USB_UH3_CTRL_OFFSET 0x18
|
||||
#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
|
||||
#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
|
||||
#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
|
||||
|
||||
#define MX6_BM_OVER_CUR_DIS BIT(7)
|
||||
|
||||
struct imx_usbmisc {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
struct clk *clk;
|
||||
struct usbmisc_usb_device usbdev[USB_DEV_MAX];
|
||||
const struct usbmisc_ops *ops;
|
||||
};
|
||||
|
||||
static struct imx_usbmisc *usbmisc;
|
||||
|
||||
static struct usbmisc_usb_device *get_usbdev(struct device *dev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < USB_DEV_MAX; i++) {
|
||||
if (usbmisc->usbdev[i].dev == dev)
|
||||
return &usbmisc->usbdev[i];
|
||||
else if (!usbmisc->usbdev[i].dev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= USB_DEV_MAX)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &usbmisc->usbdev[i];
|
||||
}
|
||||
|
||||
static int usbmisc_imx25_post(struct device *dev)
|
||||
{
|
||||
struct usbmisc_usb_device *usbdev;
|
||||
void __iomem *reg;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
usbdev = get_usbdev(dev);
|
||||
if (IS_ERR(usbdev))
|
||||
return PTR_ERR(usbdev);
|
||||
|
||||
reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
|
||||
|
||||
if (usbdev->evdo) {
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(reg);
|
||||
writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
usleep_range(5000, 10000); /* needed to stabilize voltage */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx53_init(struct device *dev)
|
||||
{
|
||||
struct usbmisc_usb_device *usbdev;
|
||||
void __iomem *reg = NULL;
|
||||
unsigned long flags;
|
||||
u32 val = 0;
|
||||
|
||||
usbdev = get_usbdev(dev);
|
||||
if (IS_ERR(usbdev))
|
||||
return PTR_ERR(usbdev);
|
||||
|
||||
if (usbdev->disable_oc) {
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
switch (usbdev->index) {
|
||||
case 0:
|
||||
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
|
||||
val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
|
||||
break;
|
||||
case 1:
|
||||
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
|
||||
val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
|
||||
break;
|
||||
case 2:
|
||||
reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
|
||||
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
|
||||
break;
|
||||
case 3:
|
||||
reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
|
||||
val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
|
||||
break;
|
||||
}
|
||||
if (reg && val)
|
||||
writel(val, reg);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx6q_init(struct device *dev)
|
||||
{
|
||||
|
||||
struct usbmisc_usb_device *usbdev;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
usbdev = get_usbdev(dev);
|
||||
if (IS_ERR(usbdev))
|
||||
return PTR_ERR(usbdev);
|
||||
|
||||
if (usbdev->disable_oc) {
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
reg = readl(usbmisc->base + usbdev->index * 4);
|
||||
writel(reg | MX6_BM_OVER_CUR_DIS,
|
||||
usbmisc->base + usbdev->index * 4);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usbmisc_ops imx25_usbmisc_ops = {
|
||||
.post = usbmisc_imx25_post,
|
||||
};
|
||||
|
||||
static const struct usbmisc_ops imx53_usbmisc_ops = {
|
||||
.init = usbmisc_imx53_init,
|
||||
};
|
||||
|
||||
static const struct usbmisc_ops imx6q_usbmisc_ops = {
|
||||
.init = usbmisc_imx6q_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id usbmisc_imx_dt_ids[] = {
|
||||
{
|
||||
.compatible = "fsl,imx25-usbmisc",
|
||||
.data = &imx25_usbmisc_ops,
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,imx53-usbmisc",
|
||||
.data = &imx53_usbmisc_ops,
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,imx6q-usbmisc",
|
||||
.data = &imx6q_usbmisc_ops,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int usbmisc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct imx_usbmisc *data;
|
||||
int ret;
|
||||
struct of_device_id *tmp_dev;
|
||||
|
||||
if (usbmisc)
|
||||
return -EBUSY;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
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)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
|
||||
return PTR_ERR(data->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"clk_prepare_enable failed, err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tmp_dev = (struct of_device_id *)
|
||||
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
|
||||
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
|
||||
usbmisc = data;
|
||||
ret = usbmisc_set_ops(data->ops);
|
||||
if (ret) {
|
||||
usbmisc = NULL;
|
||||
clk_disable_unprepare(data->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
usbmisc_unset_ops(usbmisc->ops);
|
||||
clk_disable_unprepare(usbmisc->clk);
|
||||
usbmisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver usbmisc_imx_driver = {
|
||||
.probe = usbmisc_imx_probe,
|
||||
.remove = usbmisc_imx_remove,
|
||||
.driver = {
|
||||
.name = "usbmisc_imx",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = usbmisc_imx_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
int usbmisc_imx_drv_init(void)
|
||||
{
|
||||
return platform_driver_register(&usbmisc_imx_driver);
|
||||
}
|
||||
subsys_initcall(usbmisc_imx_drv_init);
|
||||
|
||||
void usbmisc_imx_drv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&usbmisc_imx_driver);
|
||||
}
|
||||
module_exit(usbmisc_imx_drv_exit);
|
||||
|
||||
MODULE_ALIAS("platform:usbmisc-imx");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("driver for imx usb non-core registers");
|
||||
MODULE_AUTHOR("Richard Zhao <[email protected]>");
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "ci13xxx_imx.h"
|
||||
|
||||
#define USB_DEV_MAX 4
|
||||
|
||||
#define BM_OVER_CUR_DIS BIT(7)
|
||||
|
||||
struct imx6q_usbmisc {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
struct clk *clk;
|
||||
struct usbmisc_usb_device usbdev[USB_DEV_MAX];
|
||||
};
|
||||
|
||||
static struct imx6q_usbmisc *usbmisc;
|
||||
|
||||
static struct usbmisc_usb_device *get_usbdev(struct device *dev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < USB_DEV_MAX; i++) {
|
||||
if (usbmisc->usbdev[i].dev == dev)
|
||||
return &usbmisc->usbdev[i];
|
||||
else if (!usbmisc->usbdev[i].dev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= USB_DEV_MAX)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &usbmisc->usbdev[i];
|
||||
}
|
||||
|
||||
static int usbmisc_imx6q_init(struct device *dev)
|
||||
{
|
||||
|
||||
struct usbmisc_usb_device *usbdev;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
usbdev = get_usbdev(dev);
|
||||
if (IS_ERR(usbdev))
|
||||
return PTR_ERR(usbdev);
|
||||
|
||||
if (usbdev->disable_oc) {
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
reg = readl(usbmisc->base + usbdev->index * 4);
|
||||
writel(reg | BM_OVER_CUR_DIS,
|
||||
usbmisc->base + usbdev->index * 4);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usbmisc_ops imx6q_usbmisc_ops = {
|
||||
.init = usbmisc_imx6q_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-usbmisc"},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int usbmisc_imx6q_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct imx6q_usbmisc *data;
|
||||
int ret;
|
||||
|
||||
if (usbmisc)
|
||||
return -EBUSY;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
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)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get clock, err=%ld\n", PTR_ERR(data->clk));
|
||||
return PTR_ERR(data->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"clk_prepare_enable failed, err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(data->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usbmisc = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbmisc_imx6q_remove(struct platform_device *pdev)
|
||||
{
|
||||
usbmisc_unset_ops(&imx6q_usbmisc_ops);
|
||||
clk_disable_unprepare(usbmisc->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver usbmisc_imx6q_driver = {
|
||||
.probe = usbmisc_imx6q_probe,
|
||||
.remove = usbmisc_imx6q_remove,
|
||||
.driver = {
|
||||
.name = "usbmisc_imx6q",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = usbmisc_imx6q_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
int __init usbmisc_imx6q_drv_init(void)
|
||||
{
|
||||
return platform_driver_register(&usbmisc_imx6q_driver);
|
||||
}
|
||||
subsys_initcall(usbmisc_imx6q_drv_init);
|
||||
|
||||
void __exit usbmisc_imx6q_drv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&usbmisc_imx6q_driver);
|
||||
}
|
||||
module_exit(usbmisc_imx6q_drv_exit);
|
||||
|
||||
MODULE_ALIAS("platform:usbmisc-imx6q");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
|
||||
MODULE_AUTHOR("Richard Zhao <[email protected]>");
|
||||
|
|
@ -2,11 +2,10 @@
|
|||
# USB Class driver configuration
|
||||
#
|
||||
comment "USB Device Class drivers"
|
||||
depends on USB
|
||||
|
||||
config USB_ACM
|
||||
tristate "USB Modem (CDC ACM) support"
|
||||
depends on USB && TTY
|
||||
depends on TTY
|
||||
---help---
|
||||
This driver supports USB modems and ISDN adapters which support the
|
||||
Communication Device Class Abstract Control Model interface.
|
||||
|
|
@ -21,7 +20,6 @@ config USB_ACM
|
|||
|
||||
config USB_PRINTER
|
||||
tristate "USB Printer support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect a USB printer to your computer's
|
||||
USB port.
|
||||
|
|
@ -31,7 +29,6 @@ config USB_PRINTER
|
|||
|
||||
config USB_WDM
|
||||
tristate "USB Wireless Device Management support"
|
||||
depends on USB
|
||||
---help---
|
||||
This driver supports the WMC Device Management functionality
|
||||
of cell phones compliant to the CDC WMC specification. You can use
|
||||
|
|
@ -42,7 +39,6 @@ config USB_WDM
|
|||
|
||||
config USB_TMC
|
||||
tristate "USB Test and Measurement Class support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect a USB device that follows
|
||||
the USB.org specification for USB Test and Measurement devices
|
||||
|
|
|
|||
|
|
@ -828,14 +828,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
|
|||
return rv;
|
||||
}
|
||||
|
||||
static const __u32 acm_tty_speed[] = {
|
||||
0, 50, 75, 110, 134, 150, 200, 300, 600,
|
||||
1200, 1800, 2400, 4800, 9600, 19200, 38400,
|
||||
57600, 115200, 230400, 460800, 500000, 576000,
|
||||
921600, 1000000, 1152000, 1500000, 2000000,
|
||||
2500000, 3000000, 3500000, 4000000
|
||||
};
|
||||
|
||||
static void acm_tty_set_termios(struct tty_struct *tty,
|
||||
struct ktermios *termios_old)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
|
@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct wdm_device *desc = file->private_data;
|
||||
int rv = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_WDM_MAX_COMMAND:
|
||||
if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
|
||||
rv = -EFAULT;
|
||||
break;
|
||||
default:
|
||||
rv = -ENOTTY;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static const struct file_operations wdm_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = wdm_read,
|
||||
|
|
@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = {
|
|||
.flush = wdm_flush,
|
||||
.release = wdm_release,
|
||||
.poll = wdm_poll,
|
||||
.unlocked_ioctl = wdm_ioctl,
|
||||
.compat_ioctl = wdm_ioctl,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -718,50 +718,32 @@ exit:
|
|||
|
||||
static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
|
||||
{
|
||||
u8 *buffer;
|
||||
int rv;
|
||||
|
||||
buffer = kmalloc(2, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
rv = usb_clear_halt(data->usb_dev,
|
||||
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
|
||||
|
||||
if (rv < 0) {
|
||||
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
|
||||
rv);
|
||||
goto exit;
|
||||
return rv;
|
||||
}
|
||||
rv = 0;
|
||||
|
||||
exit:
|
||||
kfree(buffer);
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
|
||||
{
|
||||
u8 *buffer;
|
||||
int rv;
|
||||
|
||||
buffer = kmalloc(2, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
rv = usb_clear_halt(data->usb_dev,
|
||||
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
|
||||
|
||||
if (rv < 0) {
|
||||
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
|
||||
rv);
|
||||
goto exit;
|
||||
return rv;
|
||||
}
|
||||
rv = 0;
|
||||
|
||||
exit:
|
||||
kfree(buffer);
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_capabilities(struct usbtmc_device_data *data)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#
|
||||
config USB_DEBUG
|
||||
bool "USB verbose debug messages"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want the USB core & hub drivers to produce a bunch
|
||||
of debug messages to the system log. Select this if you are having a
|
||||
|
|
@ -11,7 +10,6 @@ config USB_DEBUG
|
|||
|
||||
config USB_ANNOUNCE_NEW_DEVICES
|
||||
bool "USB announce new devices"
|
||||
depends on USB
|
||||
default N
|
||||
help
|
||||
Say Y here if you want the USB core to always announce the
|
||||
|
|
@ -25,11 +23,24 @@ config USB_ANNOUNCE_NEW_DEVICES
|
|||
log, or have any doubts about this, say N here.
|
||||
|
||||
comment "Miscellaneous USB options"
|
||||
depends on USB
|
||||
|
||||
config USB_DEFAULT_PERSIST
|
||||
bool "Enable USB persist by default"
|
||||
default y
|
||||
help
|
||||
Say N here if you don't want USB power session persistance
|
||||
enabled by default. If you say N it will make suspended USB
|
||||
devices that lose power get reenumerated as if they had been
|
||||
unplugged, causing any mounted filesystems to be lost. The
|
||||
persist feature can still be enabled for individual devices
|
||||
through the power/persist sysfs node. See
|
||||
Documentation/usb/persist.txt for more info.
|
||||
|
||||
If you have any questions about this, say Y here, only say N
|
||||
if you know exactly what you are doing.
|
||||
|
||||
config USB_DYNAMIC_MINORS
|
||||
bool "Dynamic USB minor allocation"
|
||||
depends on USB
|
||||
help
|
||||
If you say Y here, the USB subsystem will use dynamic minor
|
||||
allocation for any device that uses the USB major number.
|
||||
|
|
@ -38,25 +49,8 @@ config USB_DYNAMIC_MINORS
|
|||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config USB_SUSPEND
|
||||
bool "USB runtime power management (autosuspend) and wakeup"
|
||||
depends on USB && PM_RUNTIME
|
||||
help
|
||||
If you say Y here, you can use driver calls or the sysfs
|
||||
"power/control" file to enable or disable autosuspend for
|
||||
individual USB peripherals (see
|
||||
Documentation/usb/power-management.txt for more details).
|
||||
|
||||
Also, USB "remote wakeup" signaling is supported, whereby some
|
||||
USB devices (like keyboards and network adapters) can wake up
|
||||
their parent hub. That wakeup cascades up the USB tree, and
|
||||
could wake the system from states like suspend-to-RAM.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config USB_OTG
|
||||
bool "OTG support"
|
||||
depends on USB
|
||||
depends on USB_SUSPEND
|
||||
default n
|
||||
help
|
||||
|
|
|
|||
|
|
@ -739,6 +739,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
|
|||
index &= 0xff;
|
||||
switch (requesttype & USB_RECIP_MASK) {
|
||||
case USB_RECIP_ENDPOINT:
|
||||
if ((index & ~USB_DIR_IN) == 0)
|
||||
return 0;
|
||||
ret = findintfep(ps->dev, index);
|
||||
if (ret >= 0)
|
||||
ret = checkintf(ps, ret);
|
||||
|
|
|
|||
|
|
@ -1196,9 +1196,14 @@ done:
|
|||
*
|
||||
* This is the central routine for suspending USB devices. It calls the
|
||||
* suspend methods for all the interface drivers in @udev and then calls
|
||||
* the suspend method for @udev itself. If an error occurs at any stage,
|
||||
* all the interfaces which were suspended are resumed so that they remain
|
||||
* in the same state as the device.
|
||||
* the suspend method for @udev itself. When the routine is called in
|
||||
* autosuspend, if an error occurs at any stage, all the interfaces
|
||||
* which were suspended are resumed so that they remain in the same
|
||||
* state as the device, but when called from system sleep, all error
|
||||
* from suspend methods of interfaces and the non-root-hub device itself
|
||||
* are simply ignored, so all suspended interfaces are only resumed
|
||||
* to the device's state when @udev is root-hub and its suspend method
|
||||
* returns failure.
|
||||
*
|
||||
* Autosuspend requests originating from a child device or an interface
|
||||
* driver may be made without the protection of @udev's device lock, but
|
||||
|
|
@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
/* If the suspend failed, resume interfaces that did get suspended */
|
||||
if (status != 0) {
|
||||
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
|
||||
while (++i < n) {
|
||||
intf = udev->actconfig->interface[i];
|
||||
usb_resume_interface(udev, intf, msg, 0);
|
||||
if (udev->actconfig) {
|
||||
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
|
||||
while (++i < n) {
|
||||
intf = udev->actconfig->interface[i];
|
||||
usb_resume_interface(udev, intf, msg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the suspend succeeded then prevent any more URB submissions
|
||||
|
|
@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
|
|||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
/**
|
||||
* usb_enable_autosuspend - allow a USB device to be autosuspended
|
||||
|
|
@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
struct bus_type usb_bus_type = {
|
||||
.name = "usb",
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)
|
|||
c = usb_choose_configuration(udev);
|
||||
if (c >= 0) {
|
||||
err = usb_set_configuration(udev, c);
|
||||
if (err) {
|
||||
if (err && err != -ENODEV) {
|
||||
dev_err(&udev->dev, "can't set config #%d, error %d\n",
|
||||
c, err);
|
||||
/* This need not be fatal. The user can try to
|
||||
|
|
|
|||
|
|
@ -37,119 +37,123 @@
|
|||
|
||||
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
/* Coordinate handoffs between EHCI and companion controllers
|
||||
* during system resume
|
||||
/*
|
||||
* Coordinate handoffs between EHCI and companion controllers
|
||||
* during EHCI probing and system resume.
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(companions_mutex);
|
||||
static DECLARE_RWSEM(companions_rwsem);
|
||||
|
||||
#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
|
||||
#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
|
||||
#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
|
||||
|
||||
enum companion_action {
|
||||
SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
|
||||
};
|
||||
static inline int is_ohci_or_uhci(struct pci_dev *pdev)
|
||||
{
|
||||
return pdev->class == CL_OHCI || pdev->class == CL_UHCI;
|
||||
}
|
||||
|
||||
static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
enum companion_action action)
|
||||
typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd);
|
||||
|
||||
/* Iterate over PCI devices in the same slot as pdev and call fn for each */
|
||||
static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
companion_fn fn)
|
||||
{
|
||||
struct pci_dev *companion;
|
||||
struct usb_hcd *companion_hcd;
|
||||
unsigned int slot = PCI_SLOT(pdev->devfn);
|
||||
|
||||
/* Iterate through other PCI functions in the same slot.
|
||||
* If pdev is OHCI or UHCI then we are looking for EHCI, and
|
||||
* vice versa.
|
||||
/*
|
||||
* Iterate through other PCI functions in the same slot.
|
||||
* If the function's drvdata isn't set then it isn't bound to
|
||||
* a USB host controller driver, so skip it.
|
||||
*/
|
||||
companion = NULL;
|
||||
for_each_pci_dev(companion) {
|
||||
if (companion->bus != pdev->bus ||
|
||||
PCI_SLOT(companion->devfn) != slot)
|
||||
continue;
|
||||
|
||||
companion_hcd = pci_get_drvdata(companion);
|
||||
if (!companion_hcd)
|
||||
continue;
|
||||
|
||||
/* For SET_HS_COMPANION, store a pointer to the EHCI bus in
|
||||
* the OHCI/UHCI companion bus structure.
|
||||
* For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
|
||||
* in the OHCI/UHCI companion bus structure.
|
||||
* For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
|
||||
* companion controllers have fully resumed.
|
||||
*/
|
||||
|
||||
if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
|
||||
companion->class == CL_EHCI) {
|
||||
/* action must be SET_HS_COMPANION */
|
||||
dev_dbg(&companion->dev, "HS companion for %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
hcd->self.hs_companion = &companion_hcd->self;
|
||||
|
||||
} else if (pdev->class == CL_EHCI &&
|
||||
(companion->class == CL_OHCI ||
|
||||
companion->class == CL_UHCI)) {
|
||||
switch (action) {
|
||||
case SET_HS_COMPANION:
|
||||
dev_dbg(&pdev->dev, "HS companion for %s\n",
|
||||
dev_name(&companion->dev));
|
||||
companion_hcd->self.hs_companion = &hcd->self;
|
||||
break;
|
||||
case CLEAR_HS_COMPANION:
|
||||
companion_hcd->self.hs_companion = NULL;
|
||||
break;
|
||||
case WAIT_FOR_COMPANIONS:
|
||||
device_pm_wait_for_dev(&pdev->dev,
|
||||
&companion->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn(pdev, hcd, companion, companion_hcd);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
|
||||
/*
|
||||
* We're about to add an EHCI controller, which will unceremoniously grab
|
||||
* all the port connections away from its companions. To prevent annoying
|
||||
* error messages, lock the companion's root hub and gracefully unconfigure
|
||||
* it beforehand. Leave it locked until the EHCI controller is all set.
|
||||
*/
|
||||
static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd)
|
||||
{
|
||||
mutex_lock(&companions_mutex);
|
||||
dev_set_drvdata(&pdev->dev, hcd);
|
||||
companion_common(pdev, hcd, SET_HS_COMPANION);
|
||||
mutex_unlock(&companions_mutex);
|
||||
struct usb_device *udev;
|
||||
|
||||
if (is_ohci_or_uhci(companion)) {
|
||||
udev = companion_hcd->self.root_hub;
|
||||
usb_lock_device(udev);
|
||||
usb_set_configuration(udev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
|
||||
/*
|
||||
* Adding the EHCI controller has either succeeded or failed. Set the
|
||||
* companion pointer accordingly, and in either case, reconfigure and
|
||||
* unlock the root hub.
|
||||
*/
|
||||
static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd)
|
||||
{
|
||||
mutex_lock(&companions_mutex);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
struct usb_device *udev;
|
||||
|
||||
/* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
|
||||
if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
|
||||
hcd->self.hs_companion = NULL;
|
||||
|
||||
/* Otherwise search for companion buses and clear their pointers */
|
||||
else
|
||||
companion_common(pdev, hcd, CLEAR_HS_COMPANION);
|
||||
mutex_unlock(&companions_mutex);
|
||||
if (is_ohci_or_uhci(companion)) {
|
||||
if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */
|
||||
dev_dbg(&pdev->dev, "HS companion for %s\n",
|
||||
dev_name(&companion->dev));
|
||||
companion_hcd->self.hs_companion = &hcd->self;
|
||||
}
|
||||
udev = companion_hcd->self.root_hub;
|
||||
usb_set_configuration(udev, 1);
|
||||
usb_unlock_device(udev);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
|
||||
/*
|
||||
* We just added a non-EHCI controller. Find the EHCI controller to
|
||||
* which it is a companion, and store a pointer to the bus structure.
|
||||
*/
|
||||
static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd)
|
||||
{
|
||||
/* Only EHCI controllers need to wait.
|
||||
* No locking is needed because a controller cannot be resumed
|
||||
* while one of its companions is getting unbound.
|
||||
*/
|
||||
if (pdev->class == CL_EHCI)
|
||||
companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
|
||||
if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) {
|
||||
dev_dbg(&pdev->dev, "FS/LS companion for %s\n",
|
||||
dev_name(&companion->dev));
|
||||
hcd->self.hs_companion = &companion_hcd->self;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
/* We are removing an EHCI controller. Clear the companions' pointers. */
|
||||
static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd)
|
||||
{
|
||||
if (is_ohci_or_uhci(companion))
|
||||
companion_hcd->self.hs_companion = NULL;
|
||||
}
|
||||
|
||||
static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
|
||||
static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
|
||||
static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#endif /* !CONFIG_PM_SLEEP */
|
||||
/* An EHCI controller must wait for its companions before resuming. */
|
||||
static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
|
||||
struct pci_dev *companion, struct usb_hcd *companion_hcd)
|
||||
{
|
||||
if (is_ohci_or_uhci(companion))
|
||||
device_pm_wait_for_dev(&pdev->dev, &companion->dev);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
driver->description)) {
|
||||
dev_dbg(&dev->dev, "controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto clear_companion;
|
||||
goto put_hcd;
|
||||
}
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (hcd->regs == NULL) {
|
||||
|
|
@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
if (region == PCI_ROM_RESOURCE) {
|
||||
dev_dbg(&dev->dev, "no i/o regions available\n");
|
||||
retval = -EBUSY;
|
||||
goto clear_companion;
|
||||
goto put_hcd;
|
||||
}
|
||||
}
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
|
||||
/* Note: dev_set_drvdata must be called while holding the rwsem */
|
||||
if (dev->class == CL_EHCI) {
|
||||
down_write(&companions_rwsem);
|
||||
dev_set_drvdata(&dev->dev, hcd);
|
||||
for_each_companion(dev, hcd, ehci_pre_add);
|
||||
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
for_each_companion(dev, hcd, ehci_post_add);
|
||||
up_write(&companions_rwsem);
|
||||
} else {
|
||||
down_read(&companions_rwsem);
|
||||
dev_set_drvdata(&dev->dev, hcd);
|
||||
retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
else
|
||||
for_each_companion(dev, hcd, non_ehci_add);
|
||||
up_read(&companions_rwsem);
|
||||
}
|
||||
|
||||
if (retval != 0)
|
||||
goto unmap_registers;
|
||||
set_hs_companion(dev, hcd);
|
||||
|
||||
if (pci_dev_run_wake(dev))
|
||||
pm_runtime_put_noidle(&dev->dev);
|
||||
|
|
@ -266,8 +289,7 @@ release_mem_region:
|
|||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
} else
|
||||
release_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
clear_companion:
|
||||
clear_hs_companion(dev, hcd);
|
||||
put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
disable_pci:
|
||||
pci_disable_device(dev);
|
||||
|
|
@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
|
|||
usb_hcd_irq(0, hcd);
|
||||
local_irq_enable();
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
/* Note: dev_set_drvdata must be called while holding the rwsem */
|
||||
if (dev->class == CL_EHCI) {
|
||||
down_write(&companions_rwsem);
|
||||
for_each_companion(dev, hcd, ehci_remove);
|
||||
usb_remove_hcd(hcd);
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
up_write(&companions_rwsem);
|
||||
} else {
|
||||
/* Not EHCI; just clear the companion pointer */
|
||||
down_read(&companions_rwsem);
|
||||
hcd->self.hs_companion = NULL;
|
||||
usb_remove_hcd(hcd);
|
||||
dev_set_drvdata(&dev->dev, NULL);
|
||||
up_read(&companions_rwsem);
|
||||
}
|
||||
|
||||
if (hcd->driver->flags & HCD_MEMORY) {
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
} else {
|
||||
release_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
}
|
||||
clear_hs_companion(dev, hcd);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
|
@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event)
|
|||
pci_set_master(pci_dev);
|
||||
|
||||
if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
|
||||
if (event != PM_EVENT_AUTO_RESUME)
|
||||
wait_for_companions(pci_dev, hcd);
|
||||
|
||||
/*
|
||||
* Only EHCI controllers have to wait for their companions.
|
||||
* No locking is needed because PCI controller drivers do not
|
||||
* get unbound during system resume.
|
||||
*/
|
||||
if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)
|
||||
for_each_companion(pci_dev, hcd,
|
||||
ehci_wait_for_companions);
|
||||
|
||||
retval = hcd->driver->pci_resume(hcd,
|
||||
event == PM_EVENT_RESTORE);
|
||||
|
|
|
|||
|
|
@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
|
|||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
/* Workqueue routine for root-hub remote wakeup */
|
||||
static void hcd_resume_work(struct work_struct *work)
|
||||
|
|
@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
|
||||
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||
init_timer(&hcd->rh_timer);
|
||||
hcd->rh_timer.function = rh_timer_func;
|
||||
hcd->rh_timer.data = (unsigned long) hcd;
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
|
||||
#endif
|
||||
|
||||
|
|
@ -2590,7 +2590,7 @@ error_create_attr_group:
|
|||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq(&hcd_root_hub_lock);
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
cancel_work_sync(&hcd->wakeup_work);
|
||||
#endif
|
||||
mutex_lock(&usb_bus_list_lock);
|
||||
|
|
@ -2645,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
|
|||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
cancel_work_sync(&hcd->wakeup_work);
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,
|
|||
mutex_lock(&hub->status_mutex);
|
||||
ret = get_port_status(hub->hdev, port1, &hub->status->port);
|
||||
if (ret < 4) {
|
||||
dev_err(hub->intfdev,
|
||||
"%s failed (err = %d)\n", __func__, ret);
|
||||
if (ret != -ENODEV)
|
||||
dev_err(hub->intfdev,
|
||||
"%s failed (err = %d)\n", __func__, ret);
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
} else {
|
||||
|
|
@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)
|
|||
/* drop lock so HCD can concurrently report other TT errors */
|
||||
spin_unlock_irqrestore (&hub->tt.lock, flags);
|
||||
status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
|
||||
if (status)
|
||||
if (status && status != -ENODEV)
|
||||
dev_err (&hdev->dev,
|
||||
"clear tt %d (%04x) error %d\n",
|
||||
clear->tt, clear->devinfo, status);
|
||||
|
|
@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,
|
|||
|
||||
mutex_lock(&hub->status_mutex);
|
||||
ret = get_hub_status(hub->hdev, &hub->status->hub);
|
||||
if (ret < 0)
|
||||
dev_err (hub->intfdev,
|
||||
"%s failed (err = %d)\n", __func__, ret);
|
||||
else {
|
||||
if (ret < 0) {
|
||||
if (ret != -ENODEV)
|
||||
dev_err(hub->intfdev,
|
||||
"%s failed (err = %d)\n", __func__, ret);
|
||||
} else {
|
||||
*status = le16_to_cpu(hub->status->hub.wHubStatus);
|
||||
*change = le16_to_cpu(hub->status->hub.wHubChange);
|
||||
ret = 0;
|
||||
|
|
@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
|
|||
return -EINVAL;
|
||||
|
||||
ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
|
||||
if (ret) {
|
||||
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
|
||||
port1, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for the link to enter the disabled state. */
|
||||
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
|
||||
|
|
@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
|
|||
ret = usb_clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
}
|
||||
if (ret)
|
||||
if (ret && ret != -ENODEV)
|
||||
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
|
||||
port1, ret);
|
||||
return ret;
|
||||
|
|
@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,
|
|||
message = "hub has too many ports!";
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
} else if (hub->descriptor->bNbrPorts == 0) {
|
||||
message = "hub doesn't have any ports!";
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hdev->maxchild = hub->descriptor->bNbrPorts;
|
||||
|
|
@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)
|
|||
if (udev->config == NULL) {
|
||||
err = usb_get_configuration(udev);
|
||||
if (err < 0) {
|
||||
dev_err(&udev->dev, "can't read configurations, error %d\n",
|
||||
err);
|
||||
if (err != -ENODEV)
|
||||
dev_err(&udev->dev, "can't read configurations, error %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
|
|||
status = set_port_feature(hub->hdev, port1, (warm ?
|
||||
USB_PORT_FEAT_BH_PORT_RESET :
|
||||
USB_PORT_FEAT_RESET));
|
||||
if (status) {
|
||||
if (status == -ENODEV) {
|
||||
; /* The hub is gone */
|
||||
} else if (status) {
|
||||
dev_err(hub->intfdev,
|
||||
"cannot %sreset port %d (err = %d)\n",
|
||||
warm ? "warm " : "", port1, status);
|
||||
} else {
|
||||
status = hub_port_wait_reset(hub, port1, udev, delay,
|
||||
warm);
|
||||
if (status && status != -ENOTCONN)
|
||||
if (status && status != -ENOTCONN && status != -ENODEV)
|
||||
dev_dbg(hub->intfdev,
|
||||
"port_wait_reset: err = %d\n",
|
||||
status);
|
||||
|
|
@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usb_enable_ltm);
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* usb_disable_function_remotewakeup - disable usb3.0
|
||||
* device's function remote wakeup
|
||||
|
|
@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
|
|||
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
|
||||
* timer, no SRP, no requests through sysfs.
|
||||
*
|
||||
* If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
|
||||
* the root hub for their bus goes into global suspend ... so we don't
|
||||
* (falsely) update the device power state to say it suspended.
|
||||
* If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
|
||||
* suspended only when their bus goes into global suspend (i.e., the root
|
||||
* hub is suspended). Nevertheless, we change @udev->state to
|
||||
* USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
|
||||
* upstream port setting is stored in @udev->port_is_suspended.
|
||||
*
|
||||
* Returns 0 on success, else negative errno.
|
||||
*/
|
||||
|
|
@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
enum pm_qos_flags_status pm_qos_stat;
|
||||
int port1 = udev->portnum;
|
||||
int status;
|
||||
bool really_suspend = true;
|
||||
|
||||
/* enable remote wakeup when appropriate; this lets the device
|
||||
* wake up the upstream hub (including maybe the root hub).
|
||||
|
|
@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
/* see 7.1.7.6 */
|
||||
if (hub_is_superspeed(hub->hdev))
|
||||
status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
|
||||
else
|
||||
else if (PMSG_IS_AUTO(msg))
|
||||
status = set_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_SUSPEND);
|
||||
/*
|
||||
* For system suspend, we do not need to enable the suspend feature
|
||||
* on individual USB-2 ports. The devices will automatically go
|
||||
* into suspend a few ms after the root hub stops sending packets.
|
||||
* The USB 2.0 spec calls this "global suspend".
|
||||
*/
|
||||
else {
|
||||
really_suspend = false;
|
||||
status = 0;
|
||||
}
|
||||
if (status) {
|
||||
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
|
||||
port1, status);
|
||||
|
|
@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
|
||||
udev->do_remote_wakeup);
|
||||
usb_set_device_state(udev, USB_STATE_SUSPENDED);
|
||||
udev->port_is_suspended = 1;
|
||||
msleep(10);
|
||||
if (really_suspend) {
|
||||
udev->port_is_suspended = 1;
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
/* caller has locked udev */
|
||||
int usb_remote_wakeup(struct usb_device *udev)
|
||||
{
|
||||
|
|
@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)
|
|||
return status;
|
||||
}
|
||||
|
||||
#else /* CONFIG_USB_SUSPEND */
|
||||
|
||||
/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
|
||||
|
||||
int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* However we may need to do a reset-resume */
|
||||
|
||||
int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
|
||||
int port1 = udev->portnum;
|
||||
int status;
|
||||
u16 portchange, portstatus;
|
||||
|
||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||
status = check_port_resume_type(udev,
|
||||
hub, port1, status, portchange, portstatus);
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
|
||||
hub_port_logical_disconnect(hub, port1);
|
||||
} else if (udev->reset_resume) {
|
||||
dev_dbg(&udev->dev, "reset-resume\n");
|
||||
status = usb_reset_and_verify_device(udev);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int check_ports_changed(struct usb_hub *hub)
|
||||
|
|
@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
goto fail;
|
||||
}
|
||||
if (r) {
|
||||
dev_err(&udev->dev,
|
||||
"device descriptor read/64, error %d\n",
|
||||
r);
|
||||
if (r != -ENODEV)
|
||||
dev_err(&udev->dev, "device descriptor read/64, error %d\n",
|
||||
r);
|
||||
retval = -EMSGSIZE;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
msleep(200);
|
||||
}
|
||||
if (retval < 0) {
|
||||
dev_err(&udev->dev,
|
||||
"device not accepting address %d, error %d\n",
|
||||
devnum, retval);
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device not accepting address %d, error %d\n",
|
||||
devnum, retval);
|
||||
goto fail;
|
||||
}
|
||||
if (udev->speed == USB_SPEED_SUPER) {
|
||||
|
|
@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
|
||||
retval = usb_get_device_descriptor(udev, 8);
|
||||
if (retval < 8) {
|
||||
dev_err(&udev->dev,
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev,
|
||||
"device descriptor read/8, error %d\n",
|
||||
retval);
|
||||
if (retval >= 0)
|
||||
|
|
@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
|
||||
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
|
||||
if (retval < (signed)sizeof(udev->descriptor)) {
|
||||
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
||||
retval);
|
||||
if (retval != -ENODEV)
|
||||
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
|
||||
retval);
|
||||
if (retval >= 0)
|
||||
retval = -ENOMSG;
|
||||
goto fail;
|
||||
|
|
@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
if (portstatus & USB_PORT_STAT_ENABLE) {
|
||||
status = 0; /* Nothing to do */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
} else if (udev->state == USB_STATE_SUSPENDED &&
|
||||
udev->persist_enabled) {
|
||||
/* For a suspended device, treat this as a
|
||||
|
|
@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
USB_PORT_STAT_C_ENABLE)) {
|
||||
status = hub_port_debounce_be_stable(hub, port1);
|
||||
if (status < 0) {
|
||||
if (printk_ratelimit())
|
||||
if (status != -ENODEV && printk_ratelimit())
|
||||
dev_err(hub_dev, "connect-debounce failed, "
|
||||
"port %d disabled\n", port1);
|
||||
portstatus &= ~USB_PORT_STAT_CONNECTION;
|
||||
|
|
@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
else
|
||||
unit_load = 100;
|
||||
|
||||
status = 0;
|
||||
for (i = 0; i < SET_CONFIG_TRIES; i++) {
|
||||
|
||||
/* reallocate for each attempt, since references
|
||||
|
|
@ -4526,9 +4522,11 @@ loop:
|
|||
}
|
||||
if (hub->hdev->parent ||
|
||||
!hcd->driver->port_handed_over ||
|
||||
!(hcd->driver->port_handed_over)(hcd, port1))
|
||||
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
|
||||
port1);
|
||||
!(hcd->driver->port_handed_over)(hcd, port1)) {
|
||||
if (status != -ENOTCONN && status != -ENODEV)
|
||||
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
|
||||
port1);
|
||||
}
|
||||
|
||||
done:
|
||||
hub_port_disable(hub, port1, 1);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static void usb_port_device_release(struct device *dev)
|
|||
kfree(port_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int usb_port_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct usb_port *port_dev = to_usb_port(dev);
|
||||
|
|
@ -138,7 +138,7 @@ static int usb_port_runtime_suspend(struct device *dev)
|
|||
#endif
|
||||
|
||||
static const struct dev_pm_ops usb_port_pm_ops = {
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
.runtime_suspend = usb_port_runtime_suspend,
|
||||
.runtime_resume = usb_port_runtime_resume,
|
||||
.runtime_idle = pm_generic_runtime_idle,
|
||||
|
|
|
|||
|
|
@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)
|
|||
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
|
||||
udev->quirks);
|
||||
|
||||
/* For the present, all devices default to USB-PERSIST enabled */
|
||||
#if 0 /* was: #ifdef CONFIG_PM */
|
||||
#ifdef CONFIG_USB_DEFAULT_PERSIST
|
||||
if (!(udev->quirks & USB_QUIRK_RESET))
|
||||
udev->persist_enabled = 1;
|
||||
#else
|
||||
/* Hubs are automatically enabled for USB-PERSIST */
|
||||
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
|
||||
udev->persist_enabled = 1;
|
||||
|
||||
#else
|
||||
/* In the absence of PM, we can safely enable USB-PERSIST
|
||||
* for all devices. It will affect things like hub resets
|
||||
* and EMF-related port disables.
|
||||
*/
|
||||
if (!(udev->quirks & USB_QUIRK_RESET))
|
||||
udev->persist_enabled = 1;
|
||||
#endif /* CONFIG_PM */
|
||||
#endif /* CONFIG_USB_DEFAULT_PERSIST */
|
||||
}
|
||||
|
||||
void usb_detect_interface_quirks(struct usb_device *udev)
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)
|
|||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
static ssize_t
|
||||
show_connected_duration(struct device *dev, struct device_attribute *attr,
|
||||
|
|
@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)
|
|||
#define add_power_attributes(dev) 0
|
||||
#define remove_power_attributes(dev) do {} while (0)
|
||||
|
||||
#endif /* CONFIG_USB_SUSPEND */
|
||||
#endif /* CONFIG_PM_RUNTIME */
|
||||
|
||||
|
||||
/* Descriptor fields */
|
||||
|
|
|
|||
|
|
@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
|
|||
void usb_poison_urb(struct urb *urb)
|
||||
{
|
||||
might_sleep();
|
||||
if (!(urb && urb->dev && urb->ep))
|
||||
if (!urb)
|
||||
return;
|
||||
atomic_inc(&urb->reject);
|
||||
|
||||
if (!urb->dev || !urb->ep)
|
||||
return;
|
||||
|
||||
usb_hcd_unlink_urb(urb, -ENOENT);
|
||||
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";
|
|||
|
||||
static bool nousb; /* Disable USB when built into kernel image */
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int usb_autosuspend_delay = 2; /* Default delay value,
|
||||
* in seconds */
|
||||
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
|
||||
|
|
@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
|
|||
.thaw = usb_dev_thaw,
|
||||
.poweroff = usb_dev_poweroff,
|
||||
.restore = usb_dev_restore,
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
.runtime_suspend = usb_runtime_suspend,
|
||||
.runtime_resume = usb_runtime_resume,
|
||||
.runtime_idle = usb_runtime_idle,
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
extern void usb_autosuspend_device(struct usb_device *udev);
|
||||
extern int usb_autoresume_device(struct usb_device *udev);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
config USB_DWC3
|
||||
tristate "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
|
||||
select USB_OTG_UTILS
|
||||
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
|
||||
help
|
||||
Say Y or M here if your system has a Dual Role SuperSpeed
|
||||
|
|
|
|||
|
|
@ -140,7 +140,8 @@ 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 *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;
|
||||
|
||||
|
|
@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
|||
}
|
||||
}
|
||||
|
||||
static void dwc3_core_num_eps(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
||||
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
|
||||
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
|
||||
|
||||
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
|
||||
dwc->num_in_eps, dwc->num_out_eps);
|
||||
}
|
||||
|
||||
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
|
|
@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||
if (dwc->revision < DWC3_REVISION_190A)
|
||||
reg |= DWC3_GCTL_U2RSTECN;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
dwc3_core_num_eps(dwc);
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err0;
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -351,8 +359,6 @@ err0:
|
|||
|
||||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
}
|
||||
|
|
@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
|
||||
if (IS_ERR(dwc->usb2_phy)) {
|
||||
ret = PTR_ERR(dwc->usb2_phy);
|
||||
|
||||
/*
|
||||
* if -ENXIO is returned, it means PHY layer wasn't
|
||||
* enabled, so it makes no sense to return -EPROBE_DEFER
|
||||
* in that case, since no PHY driver will ever probe.
|
||||
*/
|
||||
if (ret == -ENXIO)
|
||||
return ret;
|
||||
|
||||
dev_err(dev, "no usb2 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
|
||||
if (IS_ERR(dwc->usb3_phy)) {
|
||||
ret = PTR_ERR(dwc->usb2_phy);
|
||||
|
||||
/*
|
||||
* if -ENXIO is returned, it means PHY layer wasn't
|
||||
* enabled, so it makes no sense to return -EPROBE_DEFER
|
||||
* in that case, since no PHY driver will ever probe.
|
||||
*/
|
||||
if (ret == -ENXIO)
|
||||
return ret;
|
||||
|
||||
dev_err(dev, "no usb3 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
|
@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
dwc->regs_size = resource_size(res);
|
||||
dwc->dev = dev;
|
||||
|
||||
dev->dma_mask = dev->parent->dma_mask;
|
||||
dev->dma_parms = dev->parent->dma_parms;
|
||||
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
|
||||
|
||||
if (!strncmp("super", maximum_speed, 5))
|
||||
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
|
||||
else if (!strncmp("high", maximum_speed, 4))
|
||||
|
|
@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
goto err0;
|
||||
}
|
||||
|
||||
mode = DWC3_MODE(dwc->hwparams.hwparams0);
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
|
||||
mode = DWC3_MODE_HOST;
|
||||
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
||||
mode = DWC3_MODE_DEVICE;
|
||||
else
|
||||
mode = DWC3_MODE_DRD;
|
||||
|
||||
switch (mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
|
|
@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize gadget\n");
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
break;
|
||||
case DWC3_MODE_HOST:
|
||||
|
|
@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
break;
|
||||
case DWC3_MODE_DRD:
|
||||
|
|
@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
ret = dwc3_host_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize gadget\n");
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported mode of operation %d\n", mode);
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
dwc->mode = mode;
|
||||
|
||||
ret = dwc3_debugfs_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize debugfs\n");
|
||||
goto err2;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
pm_runtime_allow(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
err3:
|
||||
switch (mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
dwc3_gadget_exit(dwc);
|
||||
|
|
@ -546,6 +587,9 @@ err2:
|
|||
break;
|
||||
}
|
||||
|
||||
err2:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
err1:
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
|
|
@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev)
|
|||
break;
|
||||
}
|
||||
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
dwc3_free_event_buffers(dwc);
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwc3_prepare(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
switch (dwc->mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
case DWC3_MODE_DRD:
|
||||
dwc3_gadget_prepare(dwc);
|
||||
/* FALLTHROUGH */
|
||||
case DWC3_MODE_HOST:
|
||||
default:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_complete(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
switch (dwc->mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
case DWC3_MODE_DRD:
|
||||
dwc3_gadget_complete(dwc);
|
||||
/* FALLTHROUGH */
|
||||
case DWC3_MODE_HOST:
|
||||
default:
|
||||
dwc3_event_buffers_setup(dwc);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
}
|
||||
|
||||
static int dwc3_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
switch (dwc->mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
case DWC3_MODE_DRD:
|
||||
dwc3_gadget_suspend(dwc);
|
||||
/* FALLTHROUGH */
|
||||
case DWC3_MODE_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
msleep(100);
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
|
||||
|
||||
switch (dwc->mode) {
|
||||
case DWC3_MODE_DEVICE:
|
||||
case DWC3_MODE_DRD:
|
||||
dwc3_gadget_resume(dwc);
|
||||
/* FALLTHROUGH */
|
||||
case DWC3_MODE_HOST:
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dwc3_dev_pm_ops = {
|
||||
.prepare = dwc3_prepare,
|
||||
.complete = dwc3_complete,
|
||||
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
|
||||
};
|
||||
|
||||
#define DWC3_PM_OPS &(dwc3_dev_pm_ops)
|
||||
#else
|
||||
#define DWC3_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id of_dwc3_match[] = {
|
||||
{
|
||||
|
|
@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = {
|
|||
.driver = {
|
||||
.name = "dwc3",
|
||||
.of_match_table = of_match_ptr(of_dwc3_match),
|
||||
.pm = DWC3_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -154,8 +154,9 @@
|
|||
/* OTG Registers */
|
||||
#define DWC3_OCFG 0xcc00
|
||||
#define DWC3_OCTL 0xcc04
|
||||
#define DWC3_OEVTEN 0xcc08
|
||||
#define DWC3_OSTS 0xcc0C
|
||||
#define DWC3_OEVT 0xcc08
|
||||
#define DWC3_OEVTEN 0xcc0C
|
||||
#define DWC3_OSTS 0xcc10
|
||||
|
||||
/* Bit fields */
|
||||
|
||||
|
|
@ -369,6 +370,9 @@ struct dwc3_trb;
|
|||
* @list: a list of event buffers
|
||||
* @buf: _THE_ buffer
|
||||
* @length: size of this buffer
|
||||
* @lpos: event offset
|
||||
* @count: cache of last read event count register
|
||||
* @flags: flags related to this event buffer
|
||||
* @dma: dma_addr_t
|
||||
* @dwc: pointer to DWC controller
|
||||
*/
|
||||
|
|
@ -376,6 +380,10 @@ struct dwc3_event_buffer {
|
|||
void *buf;
|
||||
unsigned length;
|
||||
unsigned int lpos;
|
||||
unsigned int count;
|
||||
unsigned int flags;
|
||||
|
||||
#define DWC3_EVENT_PENDING BIT(0)
|
||||
|
||||
dma_addr_t dma;
|
||||
|
||||
|
|
@ -487,12 +495,6 @@ enum dwc3_link_state {
|
|||
DWC3_LINK_STATE_MASK = 0x0f,
|
||||
};
|
||||
|
||||
enum dwc3_device_state {
|
||||
DWC3_DEFAULT_STATE,
|
||||
DWC3_ADDRESS_STATE,
|
||||
DWC3_CONFIGURED_STATE,
|
||||
};
|
||||
|
||||
/* TRB Length, PCM and Status */
|
||||
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
|
||||
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
|
||||
|
|
@ -574,6 +576,14 @@ struct dwc3_hwparams {
|
|||
/* HWPARAMS1 */
|
||||
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
|
||||
|
||||
/* HWPARAMS3 */
|
||||
#define DWC3_NUM_IN_EPS_MASK (0x1f << 18)
|
||||
#define DWC3_NUM_EPS_MASK (0x3f << 12)
|
||||
#define DWC3_NUM_EPS(p) (((p)->hwparams3 & \
|
||||
(DWC3_NUM_EPS_MASK)) >> 12)
|
||||
#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \
|
||||
(DWC3_NUM_IN_EPS_MASK)) >> 18)
|
||||
|
||||
/* HWPARAMS7 */
|
||||
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
|
||||
|
||||
|
|
@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
|
|||
* @gadget_driver: pointer to the gadget driver
|
||||
* @regs: base address for our registers
|
||||
* @regs_size: address space size
|
||||
* @irq: IRQ number
|
||||
* @num_event_buffers: calculated number of event buffers
|
||||
* @u1u2: only used on revisions <1.83a for workaround
|
||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
|
|
@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
|
|||
* @mode: mode of operation
|
||||
* @usb2_phy: pointer to USB2 PHY
|
||||
* @usb3_phy: pointer to USB3 PHY
|
||||
* @dcfg: saved contents of DCFG register
|
||||
* @gctl: saved contents of GCTL register
|
||||
* @is_selfpowered: true when we are selfpowered
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
* @ep0_bounced: true when we used bounce buffer
|
||||
|
|
@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
|
|||
* @u2pel: parameter from Set SEL request.
|
||||
* @u1sel: parameter from Set SEL request.
|
||||
* @u1pel: parameter from Set SEL request.
|
||||
* @num_out_eps: number of out endpoints
|
||||
* @num_in_eps: number of in endpoints
|
||||
* @ep0_next_event: hold the next expected event
|
||||
* @ep0state: state of endpoint zero
|
||||
* @link_state: link state
|
||||
|
|
@ -656,8 +669,10 @@ struct dwc3 {
|
|||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t ep0_bounce_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
struct platform_device *xhci;
|
||||
|
|
@ -675,6 +690,10 @@ struct dwc3 {
|
|||
void __iomem *regs;
|
||||
size_t regs_size;
|
||||
|
||||
/* used for suspend/resume */
|
||||
u32 dcfg;
|
||||
u32 gctl;
|
||||
|
||||
u32 num_event_buffers;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
|
|
@ -694,6 +713,9 @@ struct dwc3 {
|
|||
#define DWC3_REVISION_202A 0x5533202a
|
||||
#define DWC3_REVISION_210A 0x5533210a
|
||||
#define DWC3_REVISION_220A 0x5533220a
|
||||
#define DWC3_REVISION_230A 0x5533230a
|
||||
#define DWC3_REVISION_240A 0x5533240a
|
||||
#define DWC3_REVISION_250A 0x5533250a
|
||||
|
||||
unsigned is_selfpowered:1;
|
||||
unsigned three_stage_setup:1;
|
||||
|
|
@ -704,11 +726,11 @@ struct dwc3 {
|
|||
unsigned delayed_status:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned resize_fifos:1;
|
||||
unsigned pullups_connected:1;
|
||||
|
||||
enum dwc3_ep0_next ep0_next_event;
|
||||
enum dwc3_ep0_state ep0state;
|
||||
enum dwc3_link_state link_state;
|
||||
enum dwc3_device_state dev_state;
|
||||
|
||||
u16 isoch_delay;
|
||||
u16 u2sel;
|
||||
|
|
@ -718,6 +740,9 @@ struct dwc3 {
|
|||
|
||||
u8 speed;
|
||||
|
||||
u8 num_out_eps;
|
||||
u8 num_in_eps;
|
||||
|
||||
void *mem;
|
||||
|
||||
struct dwc3_hwparams hwparams;
|
||||
|
|
@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
|
|||
{ }
|
||||
#endif
|
||||
|
||||
/* power management interface */
|
||||
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
|
||||
int dwc3_gadget_prepare(struct dwc3 *dwc);
|
||||
void dwc3_gadget_complete(struct dwc3 *dwc);
|
||||
int dwc3_gadget_suspend(struct dwc3 *dwc);
|
||||
int dwc3_gadget_resume(struct dwc3 *dwc);
|
||||
#else
|
||||
static inline int dwc3_gadget_prepare(struct dwc3 *dwc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dwc3_gadget_complete(struct dwc3 *dwc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
|
||||
|
||||
#endif /* __DRIVERS_USB_DWC3_CORE_H */
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
|
||||
}
|
||||
|
||||
static struct debugfs_reg32 dwc3_regs[] = {
|
||||
static const struct debugfs_reg32 dwc3_regs[] = {
|
||||
dump_register(GSBUSCFG0),
|
||||
dump_register(GSBUSCFG1),
|
||||
dump_register(GTXTHRCFG),
|
||||
|
|
@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = {
|
|||
|
||||
dump_register(OCFG),
|
||||
dump_register(OCTL),
|
||||
dump_register(OEVT),
|
||||
dump_register(OEVTEN),
|
||||
dump_register(OSTS),
|
||||
};
|
||||
|
|
@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
|
|||
case DWC3_LINK_STATE_LPBK:
|
||||
seq_printf(s, "Loopback\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RESET:
|
||||
seq_printf(s, "Reset\n");
|
||||
break;
|
||||
case DWC3_LINK_STATE_RESUME:
|
||||
seq_printf(s, "Resume\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "UNKNOWN %d\n", reg);
|
||||
seq_printf(s, "UNKNOWN %d\n", state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
|
|||
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) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
|
||||
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_mode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_testmode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
|
||||
IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
|
||||
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_testmode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_link_state_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_link_state_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/nop-usb-xceiv.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
struct dwc3_exynos {
|
||||
struct platform_device *dwc3;
|
||||
struct platform_device *usb2_phy;
|
||||
struct platform_device *usb3_phy;
|
||||
struct device *dev;
|
||||
|
|
@ -86,21 +86,30 @@ err1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_exynos_remove_child(struct device *dev, void *unused)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static int dwc3_exynos_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_exynos *exynos;
|
||||
struct clk *clk;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
|
||||
if (!exynos) {
|
||||
dev_err(dev, "not enough memory\n");
|
||||
return -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||
* 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;
|
||||
if (!dev->dma_mask)
|
||||
dev->dma_mask = &dwc3_exynos_dma_mask;
|
||||
|
||||
platform_set_drvdata(pdev, exynos);
|
||||
|
||||
ret = dwc3_exynos_register_phys(exynos);
|
||||
if (ret) {
|
||||
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;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(dev, "usbdrd30");
|
||||
|
|
@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
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;
|
||||
exynos->dwc3 = dwc3;
|
||||
exynos->dev = dev;
|
||||
exynos->clk = clk;
|
||||
|
||||
clk_enable(exynos->clk);
|
||||
clk_prepare_enable(exynos->clk);
|
||||
|
||||
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");
|
||||
if (node) {
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add dwc3 core\n");
|
||||
goto err2;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "no device node, failed to add dwc3 core\n");
|
||||
ret = -ENODEV;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
clk_disable(clk);
|
||||
clk_disable_unprepare(clk);
|
||||
err1:
|
||||
platform_device_put(dwc3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(exynos->dwc3);
|
||||
platform_device_unregister(exynos->usb2_phy);
|
||||
platform_device_unregister(exynos->usb3_phy);
|
||||
device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
|
||||
|
||||
clk_disable(exynos->clk);
|
||||
clk_disable_unprepare(exynos->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwc3_exynos_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(exynos->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_exynos_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3_exynos *exynos = dev_get_drvdata(dev);
|
||||
|
||||
clk_enable(exynos->clk);
|
||||
|
||||
/* runtime set active to reflect active state. */
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static struct platform_driver dwc3_exynos_driver = {
|
||||
.probe = dwc3_exynos_probe,
|
||||
.remove = dwc3_exynos_remove,
|
||||
.driver = {
|
||||
.name = "exynos-dwc3",
|
||||
.of_match_table = of_match_ptr(exynos_dwc3_match),
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
#include <linux/of_platform.h>
|
||||
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/nop-usb-xceiv.h>
|
||||
|
||||
/*
|
||||
* All these registers belong to OMAP's Wrapper around the
|
||||
|
|
@ -117,20 +116,17 @@ struct dwc3_omap {
|
|||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
struct platform_device *usb2_phy;
|
||||
struct platform_device *usb3_phy;
|
||||
struct device *dev;
|
||||
|
||||
int irq;
|
||||
void __iomem *base;
|
||||
|
||||
void *context;
|
||||
u32 resource_size;
|
||||
u32 utmi_otg_status;
|
||||
|
||||
u32 dma_status:1;
|
||||
};
|
||||
|
||||
struct dwc3_omap *_omap;
|
||||
static struct dwc3_omap *_omap;
|
||||
|
||||
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
|
||||
{
|
||||
|
|
@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
|
|||
writel(value, base + offset);
|
||||
}
|
||||
|
||||
void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
|
||||
int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
|
||||
{
|
||||
u32 val;
|
||||
struct dwc3_omap *omap = _omap;
|
||||
|
||||
if (!omap)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
switch (status) {
|
||||
case OMAP_DWC3_ID_GROUND:
|
||||
dev_dbg(omap->dev, "ID GND\n");
|
||||
|
|
@ -189,64 +188,10 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
|
|||
dev_dbg(omap->dev, "ID float\n");
|
||||
}
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
int ret;
|
||||
|
||||
memset(&pdata, 0x00, sizeof(pdata));
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
omap->usb2_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB2;
|
||||
|
||||
ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
omap->usb3_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB3;
|
||||
|
||||
ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
ret = platform_device_add(omap->usb2_phy);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
ret = platform_device_add(omap->usb3_phy);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
platform_device_del(omap->usb2_phy);
|
||||
|
||||
err2:
|
||||
platform_device_put(omap->usb3_phy);
|
||||
|
||||
err1:
|
||||
platform_device_put(omap->usb2_phy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
{
|
||||
struct dwc3_omap *omap = _omap;
|
||||
|
|
@ -307,121 +252,10 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
|
||||
{
|
||||
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
||||
struct dwc3_omap *omap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
int size;
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
|
||||
const u32 *utmi_mode;
|
||||
u32 reg;
|
||||
|
||||
void __iomem *base;
|
||||
void *context;
|
||||
|
||||
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
|
||||
if (!omap) {
|
||||
dev_err(dev, "not enough memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
|
||||
irq = platform_get_irq(pdev, 1);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "missing memory base resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||
if (!base) {
|
||||
dev_err(dev, "ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = dwc3_omap_register_phys(omap);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
|
||||
if (!context) {
|
||||
dev_err(dev, "couldn't allocate dwc3 context memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
|
||||
omap->resource_size = resource_size(res);
|
||||
omap->context = context;
|
||||
omap->dev = dev;
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
utmi_mode = of_get_property(node, "utmi-mode", &size);
|
||||
if (utmi_mode && size == sizeof(*utmi_mode)) {
|
||||
reg |= *utmi_mode;
|
||||
} else {
|
||||
if (!pdata) {
|
||||
dev_dbg(dev, "missing platform data\n");
|
||||
} else {
|
||||
switch (pdata->utmi_mode) {
|
||||
case DWC3_OMAP_UTMI_MODE_SW:
|
||||
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
|
||||
break;
|
||||
case DWC3_OMAP_UTMI_MODE_HW:
|
||||
reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "UNKNOWN utmi mode %d\n",
|
||||
pdata->utmi_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
|
||||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable all IRQs */
|
||||
reg = USBOTGSS_IRQO_COREIRQ_ST;
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
|
||||
|
|
@ -437,14 +271,120 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
|||
USBOTGSS_IRQ1_IDPULLUP_FALL);
|
||||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
|
||||
{
|
||||
/* disable all IRQs */
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
|
||||
}
|
||||
|
||||
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
||||
struct dwc3_omap *omap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
|
||||
int utmi_mode = 0;
|
||||
|
||||
u32 reg;
|
||||
|
||||
void __iomem *base;
|
||||
|
||||
if (!node) {
|
||||
dev_err(dev, "device node not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
|
||||
if (!omap) {
|
||||
dev_err(dev, "not enough memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "missing memory base resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
||||
if (!base) {
|
||||
dev_err(dev, "ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
|
||||
omap->dev = dev;
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
dev->dma_mask = &dwc3_omap_dma_mask;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
of_property_read_u32(node, "utmi-mode", &utmi_mode);
|
||||
|
||||
switch (utmi_mode) {
|
||||
case DWC3_OMAP_UTMI_MODE_SW:
|
||||
reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
|
||||
break;
|
||||
case DWC3_OMAP_UTMI_MODE_HW:
|
||||
reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
|
||||
}
|
||||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
|
||||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwc3_omap_enable_irqs(omap);
|
||||
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to create dwc3 core\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct dwc3_omap *omap = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(omap->usb2_phy);
|
||||
platform_device_unregister(omap->usb3_phy);
|
||||
dwc3_omap_disable_irqs(omap);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
|
||||
|
|
@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id of_dwc3_match[] = {
|
||||
{
|
||||
"ti,dwc3",
|
||||
.compatible = "ti,dwc3"
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_match);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwc3_omap_prepare(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
dwc3_omap_disable_irqs(omap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_omap_complete(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
dwc3_omap_enable_irqs(omap);
|
||||
}
|
||||
|
||||
static int dwc3_omap_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
omap->utmi_otg_status = dwc3_omap_readl(omap->base,
|
||||
USBOTGSS_UTMI_OTG_STATUS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
|
||||
omap->utmi_otg_status);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
|
||||
.prepare = dwc3_omap_prepare,
|
||||
.complete = dwc3_omap_complete,
|
||||
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&dwc3_omap_dev_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static struct platform_driver dwc3_omap_driver = {
|
||||
.probe = dwc3_omap_probe,
|
||||
.remove = dwc3_omap_remove,
|
||||
.driver = {
|
||||
.name = "omap-dwc3",
|
||||
.of_match_table = of_dwc3_match,
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dwc3_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
|
||||
pci_disable_device(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = pci_enable_device(pci);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't re-enable device --> %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct pci_driver dwc3_pci_driver = {
|
||||
.name = "dwc3-pci",
|
||||
.id_table = dwc3_pci_id_table,
|
||||
.probe = dwc3_pci_probe,
|
||||
.remove = dwc3_pci_remove,
|
||||
.driver = {
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
u32 wIndex;
|
||||
u32 reg;
|
||||
int ret;
|
||||
enum usb_device_state state;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
recip = ctrl->bRequestType & USB_RECIP_MASK;
|
||||
state = dwc->gadget.state;
|
||||
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
|
||||
|
|
@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
* default control pipe
|
||||
*/
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
||||
if (state != USB_STATE_CONFIGURED)
|
||||
return -EINVAL;
|
||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||
return -EINVAL;
|
||||
|
|
@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
break;
|
||||
|
||||
case USB_DEVICE_U2_ENABLE:
|
||||
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
||||
if (state != USB_STATE_CONFIGURED)
|
||||
return -EINVAL;
|
||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||
return -EINVAL;
|
||||
|
|
@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||
|
||||
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
enum usb_device_state state = dwc->gadget.state;
|
||||
u32 addr;
|
||||
u32 reg;
|
||||
|
||||
|
|
@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
|
||||
if (state == USB_STATE_CONFIGURED) {
|
||||
dev_dbg(dwc->dev, "trying to set address when configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
if (addr)
|
||||
dwc->dev_state = DWC3_ADDRESS_STATE;
|
||||
usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
|
||||
else
|
||||
dwc->dev_state = DWC3_DEFAULT_STATE;
|
||||
usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
|
||||
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
enum usb_device_state state = dwc->gadget.state;
|
||||
u32 cfg;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
|
@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
dwc->start_config_issued = false;
|
||||
cfg = le16_to_cpu(ctrl->wValue);
|
||||
|
||||
switch (dwc->dev_state) {
|
||||
case DWC3_DEFAULT_STATE:
|
||||
switch (state) {
|
||||
case USB_STATE_DEFAULT:
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case DWC3_ADDRESS_STATE:
|
||||
case USB_STATE_ADDRESS:
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
/* if the cfg matches and the cfg is non zero */
|
||||
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
|
||||
dwc->dev_state = DWC3_CONFIGURED_STATE;
|
||||
usb_gadget_set_state(&dwc->gadget,
|
||||
USB_STATE_CONFIGURED);
|
||||
|
||||
/*
|
||||
* Enable transition to U1/U2 state when
|
||||
* nothing is pending from application.
|
||||
|
|
@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
}
|
||||
break;
|
||||
|
||||
case DWC3_CONFIGURED_STATE:
|
||||
case USB_STATE_CONFIGURED:
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
if (!cfg)
|
||||
dwc->dev_state = DWC3_ADDRESS_STATE;
|
||||
usb_gadget_set_state(&dwc->gadget,
|
||||
USB_STATE_ADDRESS);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
|
@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
|
|||
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
enum usb_device_state state = dwc->gadget.state;
|
||||
u16 wLength;
|
||||
u16 wValue;
|
||||
|
||||
if (dwc->dev_state == DWC3_DEFAULT_STATE)
|
||||
if (state == USB_STATE_DEFAULT)
|
||||
return -EINVAL;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
|
|
|
|||
|
|
@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
|||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
reg |= DWC3_DCTL_RUN_STOP;
|
||||
dwc->pullups_connected = true;
|
||||
} else {
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
dwc->pullups_connected = false;
|
||||
}
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
|
@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Enable all but Start and End of Frame IRQs */
|
||||
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
|
||||
DWC3_DEVTEN_EVNTOVERFLOWEN |
|
||||
DWC3_DEVTEN_CMDCMPLTEN |
|
||||
DWC3_DEVTEN_ERRTICERREN |
|
||||
DWC3_DEVTEN_WKUPEVTEN |
|
||||
DWC3_DEVTEN_ULSTCNGEN |
|
||||
DWC3_DEVTEN_CONNECTDONEEN |
|
||||
DWC3_DEVTEN_USBRSTEN |
|
||||
DWC3_DEVTEN_DISCONNEVTEN);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
|
||||
{
|
||||
/* mask all interrupts */
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
|
||||
|
||||
static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|||
struct dwc3_ep *dep;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int irq;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
|
@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|||
}
|
||||
|
||||
dwc->gadget_driver = driver;
|
||||
dwc->gadget.dev.driver = &driver->driver;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg &= ~(DWC3_DCFG_SPEED_MASK);
|
||||
|
|
@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
|||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
|
||||
IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
|
||||
irq, ret);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc3_gadget_enable_irq(dwc);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
|
|||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
int irq;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
dwc3_gadget_disable_irq(dwc);
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
free_irq(irq, dwc);
|
||||
|
||||
__dwc3_gadget_ep_disable(dwc->eps[0]);
|
||||
__dwc3_gadget_ep_disable(dwc->eps[1]);
|
||||
|
||||
dwc->gadget_driver = NULL;
|
||||
dwc->gadget.dev.driver = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
|
|
@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
|
|||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
||||
static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
u8 num, u32 direction)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u8 epnum;
|
||||
u8 i;
|
||||
|
||||
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
||||
for (i = 0; i < num; i++) {
|
||||
u8 epnum = (i << 1) | (!!direction);
|
||||
|
||||
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
|
||||
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
|
||||
if (!dep) {
|
||||
dev_err(dwc->dev, "can't allocate endpoint %d\n",
|
||||
|
|
@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
|||
|
||||
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
|
||||
(epnum & 1) ? "in" : "out");
|
||||
|
||||
dep->endpoint.name = dep->name;
|
||||
dep->direction = (epnum & 1);
|
||||
|
||||
|
|
@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
||||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
|
||||
if (ret < 0) {
|
||||
dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
|
||||
if (ret < 0) {
|
||||
dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
|
|
@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
|||
|
||||
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
|
||||
dep = dwc->eps[epnum];
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
dwc3_free_trb_pool(dep);
|
||||
|
||||
if (epnum != 0 && epnum != 1)
|
||||
|
|
@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
|||
}
|
||||
}
|
||||
|
||||
static void dwc3_gadget_release(struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
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)
|
||||
|
|
@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
|
|||
struct dwc3_ep *dep;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
|
||||
|
|
@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
if (!(dep->flags & DWC3_EP_STALL))
|
||||
continue;
|
||||
|
|
@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|||
}
|
||||
|
||||
/* after reset -> Default State */
|
||||
dwc->dev_state = DWC3_DEFAULT_STATE;
|
||||
usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
|
||||
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
|
|
@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
|
|||
unsigned int evtinfo)
|
||||
{
|
||||
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
|
||||
unsigned int pwropt;
|
||||
|
||||
/*
|
||||
* WORKAROUND: DWC3 < 2.50a have an issue when configured without
|
||||
* Hibernation mode enabled which would show up when device detects
|
||||
* host-initiated U3 exit.
|
||||
*
|
||||
* In that case, device will generate a Link State Change Interrupt
|
||||
* from U3 to RESUME which is only necessary if Hibernation is
|
||||
* configured in.
|
||||
*
|
||||
* There are no functional changes due to such spurious event and we
|
||||
* just need to ignore it.
|
||||
*
|
||||
* Refers to:
|
||||
*
|
||||
* STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
|
||||
* operational mode
|
||||
*/
|
||||
pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
|
||||
if ((dwc->revision < DWC3_REVISION_250A) &&
|
||||
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
|
||||
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
|
||||
(next == DWC3_LINK_STATE_RESUME)) {
|
||||
dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
|
||||
|
|
@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
|
|||
}
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
|
||||
{
|
||||
struct dwc3 *dwc = _dwc;
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
struct dwc3_event_buffer *evt;
|
||||
int left;
|
||||
|
||||
evt = dwc->ev_buffs[i];
|
||||
left = evt->count;
|
||||
|
||||
if (!(evt->flags & DWC3_EVENT_PENDING))
|
||||
continue;
|
||||
|
||||
while (left > 0) {
|
||||
union dwc3_event event;
|
||||
|
||||
event.raw = *(u32 *) (evt->buf + evt->lpos);
|
||||
|
||||
dwc3_process_event_entry(dwc, &event);
|
||||
|
||||
/*
|
||||
* FIXME we wrap around correctly to the next entry as
|
||||
* almost all entries are 4 bytes in size. There is one
|
||||
* entry which has 12 bytes which is a regular entry
|
||||
* followed by 8 bytes data. ATM I don't know how
|
||||
* things are organized if we get next to the a
|
||||
* boundary so I worry about that once we try to handle
|
||||
* that.
|
||||
*/
|
||||
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
|
||||
left -= 4;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
|
||||
}
|
||||
|
||||
evt->count = 0;
|
||||
evt->flags &= ~DWC3_EVENT_PENDING;
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int left;
|
||||
u32 count;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
|
||||
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
|
||||
count &= DWC3_GEVNTCOUNT_MASK;
|
||||
if (!count)
|
||||
return IRQ_NONE;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
left = count;
|
||||
evt->count = count;
|
||||
evt->flags |= DWC3_EVENT_PENDING;
|
||||
|
||||
while (left > 0) {
|
||||
union dwc3_event event;
|
||||
|
||||
event.raw = *(u32 *) (evt->buf + evt->lpos);
|
||||
|
||||
dwc3_process_event_entry(dwc, &event);
|
||||
/*
|
||||
* XXX we wrap around correctly to the next entry as almost all
|
||||
* entries are 4 bytes in size. There is one entry which has 12
|
||||
* bytes which is a regular entry followed by 8 bytes data. ATM
|
||||
* I don't know how things are organized if were get next to the
|
||||
* a boundary so I worry about that once we try to handle that.
|
||||
*/
|
||||
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
|
||||
left -= 4;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
|
||||
|
|
@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
|
|||
irqreturn_t status;
|
||||
|
||||
status = dwc3_process_event_buf(dwc, i);
|
||||
if (status == IRQ_HANDLED)
|
||||
if (status == IRQ_WAKE_THREAD)
|
||||
ret = status;
|
||||
}
|
||||
|
||||
|
|
@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
{
|
||||
u32 reg;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
|
||||
&dwc->ctrl_req_addr, GFP_KERNEL);
|
||||
|
|
@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
goto err3;
|
||||
}
|
||||
|
||||
dev_set_name(&dwc->gadget.dev, "gadget");
|
||||
|
||||
dwc->gadget.ops = &dwc3_gadget_ops;
|
||||
dwc->gadget.max_speed = USB_SPEED_SUPER;
|
||||
dwc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
dwc->gadget.dev.parent = dwc->dev;
|
||||
dwc->gadget.sg_supported = true;
|
||||
|
||||
dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
|
||||
|
||||
dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
|
||||
dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
|
||||
dwc->gadget.dev.release = dwc3_gadget_release;
|
||||
dwc->gadget.name = "dwc3-gadget";
|
||||
|
||||
/*
|
||||
|
|
@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||
if (ret)
|
||||
goto err4;
|
||||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
|
||||
ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
|
||||
"dwc3", dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
|
||||
irq, ret);
|
||||
goto err5;
|
||||
}
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
/* Enable all but Start and End of Frame IRQs */
|
||||
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
|
||||
DWC3_DEVTEN_EVNTOVERFLOWEN |
|
||||
DWC3_DEVTEN_CMDCMPLTEN |
|
||||
DWC3_DEVTEN_ERRTICERREN |
|
||||
DWC3_DEVTEN_WKUPEVTEN |
|
||||
DWC3_DEVTEN_ULSTCNGEN |
|
||||
DWC3_DEVTEN_CONNECTDONEEN |
|
||||
DWC3_DEVTEN_USBRSTEN |
|
||||
DWC3_DEVTEN_DISCONNEVTEN);
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
|
||||
/* automatic phy suspend only on recent versions */
|
||||
/* Enable USB2 LPM and automatic phy suspend only on recent versions */
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
}
|
||||
|
||||
ret = device_register(&dwc->gadget.dev);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register gadget device\n");
|
||||
put_device(&dwc->gadget.dev);
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register udc\n");
|
||||
goto err7;
|
||||
goto err5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err7:
|
||||
device_unregister(&dwc->gadget.dev);
|
||||
|
||||
err6:
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
|
||||
free_irq(irq, dwc);
|
||||
|
||||
err5:
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
|
||||
|
|
@ -2588,15 +2674,11 @@ err0:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
{
|
||||
int irq;
|
||||
|
||||
usb_del_gadget_udc(&dwc->gadget);
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
|
||||
free_irq(irq, dwc);
|
||||
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
|
||||
|
|
@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
|||
|
||||
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
|
||||
dwc->ctrl_req, dwc->ctrl_req_addr);
|
||||
|
||||
device_unregister(&dwc->gadget.dev);
|
||||
}
|
||||
|
||||
int dwc3_gadget_prepare(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->pullups_connected)
|
||||
dwc3_gadget_disable_irq(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_gadget_complete(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->pullups_connected) {
|
||||
dwc3_gadget_enable_irq(dwc);
|
||||
dwc3_gadget_run_stop(dwc, true);
|
||||
}
|
||||
}
|
||||
|
||||
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||
{
|
||||
__dwc3_gadget_ep_disable(dwc->eps[0]);
|
||||
__dwc3_gadget_ep_disable(dwc->eps[1]);
|
||||
|
||||
dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
|
||||
/* Start with SuperSpeed Default */
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
if (ret)
|
||||
goto err0;
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/* begin to receive SETUP packets */
|
||||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
__dwc3_gadget_ep_disable(dwc->eps[0]);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ config USB_AT91
|
|||
config USB_LPC32XX
|
||||
tristate "LPC32XX USB Peripheral Controller"
|
||||
depends on ARCH_LPC32XX
|
||||
depends on USB_PHY
|
||||
select USB_ISP1301
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
|
|
@ -195,8 +196,8 @@ config USB_FUSB300
|
|||
config USB_OMAP
|
||||
tristate "OMAP USB Device Controller"
|
||||
depends on ARCH_OMAP1
|
||||
depends on USB_PHY
|
||||
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
|
||||
select USB_OTG_UTILS if ARCH_OMAP
|
||||
help
|
||||
Many Texas Instruments OMAP processors have flexible full
|
||||
speed USB device controllers, with support for up to 30
|
||||
|
|
@ -211,7 +212,6 @@ config USB_OMAP
|
|||
config USB_PXA25X
|
||||
tristate "PXA 25x or IXP 4xx"
|
||||
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Intel's PXA 25x series XScale ARM-5TE processors include
|
||||
an integrated full speed USB 1.1 device controller. The
|
||||
|
|
@ -259,8 +259,6 @@ config USB_RENESAS_USBHS_UDC
|
|||
|
||||
config USB_PXA27X
|
||||
tristate "PXA 27x"
|
||||
depends on ARCH_PXA && (PXA27x || PXA3xx)
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Intel's PXA 27x series XScale ARM v5TE processors include
|
||||
an integrated full speed USB 1.1 device controller.
|
||||
|
|
@ -329,9 +327,6 @@ config USB_MV_UDC
|
|||
|
||||
config USB_MV_U3D
|
||||
tristate "MARVELL PXA2128 USB 3.0 controller"
|
||||
depends on CPU_MMP3
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SUPERSPEED
|
||||
help
|
||||
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
||||
controller, which support super speed USB peripheral.
|
||||
|
|
@ -501,6 +496,7 @@ endmenu
|
|||
# composite based drivers
|
||||
config USB_LIBCOMPOSITE
|
||||
tristate
|
||||
select CONFIGFS_FS
|
||||
depends on USB_GADGET
|
||||
|
||||
config USB_F_ACM
|
||||
|
|
@ -512,6 +508,12 @@ config USB_F_SS_LB
|
|||
config USB_U_SERIAL
|
||||
tristate
|
||||
|
||||
config USB_F_SERIAL
|
||||
tristate
|
||||
|
||||
config USB_F_OBEX
|
||||
tristate
|
||||
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
default USB_ETH
|
||||
|
|
@ -766,6 +768,8 @@ config USB_G_SERIAL
|
|||
depends on TTY
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
select USB_F_SERIAL
|
||||
select USB_F_OBEX
|
||||
select USB_LIBCOMPOSITE
|
||||
help
|
||||
The Serial Gadget talks to the Linux-USB generic serial driver.
|
||||
|
|
@ -839,6 +843,7 @@ config USB_G_NOKIA
|
|||
depends on PHONET
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_SERIAL
|
||||
select USB_F_ACM
|
||||
help
|
||||
The Nokia composite gadget provides support for acm, obex
|
||||
and phonet in only one composite gadget driver.
|
||||
|
|
@ -957,6 +962,7 @@ config USB_G_WEBCAM
|
|||
tristate "USB Webcam Gadget"
|
||||
depends on VIDEO_DEV
|
||||
select USB_LIBCOMPOSITE
|
||||
select VIDEOBUF2_VMALLOC
|
||||
help
|
||||
The Webcam Gadget acts as a composite USB Audio and Video Class
|
||||
device. It provides a userspace API to process UVC control requests
|
||||
|
|
|
|||
|
|
@ -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 functions.o
|
||||
libcomposite-y += composite.o functions.o configfs.o
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
|
|
@ -36,10 +36,15 @@ 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
|
||||
usb_f_acm-y := f_acm.o
|
||||
obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o
|
||||
usb_f_ss_lb-y := f_loopback.o f_sourcesink.o
|
||||
obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o
|
||||
obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
|
||||
usb_f_serial-y := f_serial.o
|
||||
obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
|
||||
usb_f_obex-y := f_obex.o
|
||||
obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ 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;
|
||||
/*
|
||||
|
|
@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst;
|
|||
*/
|
||||
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)) {
|
||||
|
|
@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
|
|||
if (IS_ERR(f_acm_inst))
|
||||
return PTR_ERR(f_acm_inst);
|
||||
|
||||
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);
|
||||
|
|
@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
|
|||
int status;
|
||||
void *retp;
|
||||
|
||||
/* set up serial link layer */
|
||||
status = gserial_alloc_line(&tty_line);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* set up mass storage function */
|
||||
retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
|
||||
if (IS_ERR(retp)) {
|
||||
status = PTR_ERR(retp);
|
||||
goto fail0;
|
||||
return PTR_ERR(retp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
|
|||
/* error recovery */
|
||||
fail1:
|
||||
fsg_common_put(&fsg_common);
|
||||
fail0:
|
||||
gserial_free_line(tty_line);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
|
|||
{
|
||||
usb_put_function(f_acm);
|
||||
usb_put_function_instance(f_acm_inst);
|
||||
gserial_free_line(tty_line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
|
|||
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
/* Some gadget drivers use both ep0 directions.
|
||||
* NOTE: to gadget driver, ep0 is just one endpoint...
|
||||
|
|
@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g,
|
|||
shutdown(dev, driver);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
|
||||
/* set SD */
|
||||
|
|
@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
|
|||
if (dev->active)
|
||||
pci_disable_device(pdev);
|
||||
|
||||
device_unregister(&dev->gadget.dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
|
||||
udc_remove(dev);
|
||||
|
|
@ -3245,8 +3242,6 @@ static int udc_pci_probe(
|
|||
dev->phys_addr = resource;
|
||||
dev->irq = pdev->irq;
|
||||
dev->pdev = pdev;
|
||||
dev->gadget.dev.parent = &pdev->dev;
|
||||
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
|
||||
/* general probing */
|
||||
if (udc_probe(dev) == 0)
|
||||
|
|
@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
|
|||
dev->gadget.ops = &udc_ops;
|
||||
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.dev.release = gadget_release;
|
||||
dev->gadget.name = name;
|
||||
dev->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
|
|
@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev)
|
|||
"driver version: %s(for Geode5536 B1)\n", tmp);
|
||||
udc = dev;
|
||||
|
||||
retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
|
||||
retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto finished;
|
||||
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval) {
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
put_device(&dev->gadget.dev);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* timer init */
|
||||
init_timer(&udc_timer);
|
||||
udc_timer.function = udc_timer_function;
|
||||
|
|
|
|||
|
|
@ -472,7 +472,6 @@ struct udc_request {
|
|||
|
||||
/* flags */
|
||||
unsigned dma_going : 1,
|
||||
dma_mapping : 1,
|
||||
dma_done : 1;
|
||||
/* phys. address */
|
||||
dma_addr_t td_phys;
|
||||
|
|
|
|||
|
|
@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget,
|
|||
|
||||
udc = container_of(gadget, struct at91_udc, gadget);
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
|
|
@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget,
|
|||
at91_udp_write(udc, AT91_UDP_IDR, ~0);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
DBG("unbound from %s\n", driver->driver.name);
|
||||
|
|
@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev)
|
|||
DBG("clocks missing\n");
|
||||
retval = -ENODEV;
|
||||
/* NOTE: we "know" here that refcounts on these are NOPs */
|
||||
goto fail0b;
|
||||
}
|
||||
|
||||
retval = device_register(&udc->gadget.dev);
|
||||
if (retval < 0) {
|
||||
put_device(&udc->gadget.dev);
|
||||
goto fail0b;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* don't do anything until we have both gadget driver and VBUS */
|
||||
|
|
@ -1857,8 +1849,6 @@ fail3:
|
|||
fail2:
|
||||
free_irq(udc->udp_irq, udc);
|
||||
fail1:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
fail0b:
|
||||
iounmap(udc->udp_baseaddr);
|
||||
fail0a:
|
||||
if (cpu_is_at91rm9200())
|
||||
|
|
@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev)
|
|||
gpio_free(udc->board.vbus_pin);
|
||||
}
|
||||
free_irq(udc->udp_irq, udc);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
iounmap(udc->udp_baseaddr);
|
||||
|
||||
if (cpu_is_at91rm9200())
|
||||
|
|
|
|||
|
|
@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
|
|||
if (req->req.status == -EINPROGRESS)
|
||||
req->req.status = status;
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(
|
||||
&udc->pdev->dev, req->req.dma, req->req.length,
|
||||
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
}
|
||||
if (req->using_dma)
|
||||
usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
|
||||
|
||||
DBG(DBG_GADGET | DBG_REQ,
|
||||
"%s: req %p complete: status %d, actual %u\n",
|
||||
|
|
@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
|
||||
return &req->req;
|
||||
}
|
||||
|
|
@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->using_dma = 1;
|
||||
|
||||
if (req->req.dma == DMA_ADDR_INVALID) {
|
||||
req->req.dma = dma_map_single(
|
||||
&udc->pdev->dev, req->req.buf, req->req.length,
|
||||
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
} else {
|
||||
dma_sync_single_for_device(
|
||||
&udc->pdev->dev, req->req.dma, req->req.length,
|
||||
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = 0;
|
||||
}
|
||||
|
||||
req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
|
||||
| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
|
||||
| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
|
||||
|
|
@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
|
|||
|
||||
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
clk_enable(udc->pclk);
|
||||
|
|
@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
|
|||
toggle_bias(0);
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
clk_disable(udc->hclk);
|
||||
|
|
@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
|
||||
(unsigned long)fifo->start, udc->fifo);
|
||||
|
||||
device_initialize(&udc->gadget.dev);
|
||||
udc->gadget.dev.parent = &pdev->dev;
|
||||
udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
|
||||
platform_set_drvdata(pdev, udc);
|
||||
|
||||
/* Make sure we start from a clean slate */
|
||||
|
|
@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
|||
}
|
||||
udc->irq = irq;
|
||||
|
||||
ret = device_add(&udc->gadget.dev);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pdata->vbus_pin)) {
|
||||
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
|
||||
udc->vbus_pin = pdata->vbus_pin;
|
||||
|
|
@ -2007,9 +1980,6 @@ err_add_udc:
|
|||
gpio_free(udc->vbus_pin);
|
||||
}
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
err_device_add:
|
||||
free_irq(irq, udc);
|
||||
err_request_irq:
|
||||
kfree(usba_ep);
|
||||
|
|
@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
|
|||
clk_put(udc->hclk);
|
||||
clk_put(udc->pclk);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,12 +216,6 @@
|
|||
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
|
||||
#define EP0_NR_BANKS 1
|
||||
|
||||
/*
|
||||
* REVISIT: Try to eliminate this value. Can we rely on req->mapped to
|
||||
* provide this information?
|
||||
*/
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#define FIFO_IOMEM_ID 0
|
||||
#define CTRL_IOMEM_ID 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
|
|||
|
||||
udc->driver = driver;
|
||||
driver->driver.bus = NULL;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.dev.of_node = udc->dev->of_node;
|
||||
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
|
@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget,
|
|||
spin_lock_irqsave(&udc->lock, flags);
|
||||
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
|
||||
/*
|
||||
* If we switch the PHY too abruptly after dropping D+, the host
|
||||
|
|
@ -2305,17 +2303,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
|
|||
* Driver init/exit
|
||||
***********************************************************************/
|
||||
|
||||
/**
|
||||
* bcm63xx_udc_gadget_release - Called from device_release().
|
||||
* @dev: Unused.
|
||||
*
|
||||
* We get a warning if this function doesn't exist, but it's empty because
|
||||
* we don't have to free any of the memory allocated with the devm_* APIs.
|
||||
*/
|
||||
static void bcm63xx_udc_gadget_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* bcm63xx_udc_probe - Initialize a new instance of the UDC.
|
||||
* @pdev: Platform device struct from the bcm63xx BSP code.
|
||||
|
|
@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
|
|||
|
||||
spin_lock_init(&udc->lock);
|
||||
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
|
||||
dev_set_name(&udc->gadget.dev, "gadget");
|
||||
|
||||
udc->gadget.ops = &bcm63xx_udc_ops;
|
||||
udc->gadget.name = dev_name(dev);
|
||||
udc->gadget.dev.parent = dev;
|
||||
udc->gadget.dev.release = bcm63xx_udc_gadget_release;
|
||||
udc->gadget.dev.dma_mask = dev->dma_mask;
|
||||
|
||||
if (!pd->use_fullspeed && !use_fullspeed)
|
||||
udc->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
|
@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
rc = device_register(&udc->gadget.dev);
|
||||
if (rc)
|
||||
goto out_uninit;
|
||||
|
||||
bcm63xx_udc_init_debugfs(udc);
|
||||
rc = usb_add_gadget_udc(dev, &udc->gadget);
|
||||
if (!rc)
|
||||
return 0;
|
||||
|
||||
bcm63xx_udc_cleanup_debugfs(udc);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
out_uninit:
|
||||
bcm63xx_uninit_udc_hw(udc);
|
||||
return rc;
|
||||
|
|
@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
|
|||
|
||||
bcm63xx_udc_cleanup_debugfs(udc);
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
BUG_ON(udc->driver);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
|
|
|||
|
|
@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
};
|
||||
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
static struct eth_dev *the_dev;
|
||||
/*-------------------------------------------------------------------------*/
|
||||
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)) {
|
||||
|
|
@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
|
|||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
status = ecm_bind_config(c, hostaddr);
|
||||
status = ecm_bind_config(c, hostaddr, the_dev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
|
|
@ -130,12 +128,11 @@ static int __init cdc_do_config(struct usb_configuration *c)
|
|||
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))
|
||||
if (IS_ERR(f_acm)) {
|
||||
status = PTR_ERR(f_acm);
|
||||
goto err_func_acm;
|
||||
}
|
||||
|
||||
status = usb_add_function(c, f_acm);
|
||||
if (status)
|
||||
|
|
@ -169,14 +166,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
|||
}
|
||||
|
||||
/* set up network link layer */
|
||||
status = gether_setup(cdev->gadget, hostaddr);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* set up serial link layer */
|
||||
status = gserial_alloc_line(&tty_line);
|
||||
if (status < 0)
|
||||
goto fail0;
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev))
|
||||
return PTR_ERR(the_dev);
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
|
|
@ -200,9 +192,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
|
||||
fail1:
|
||||
gserial_free_line(tty_line);
|
||||
fail0:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -210,8 +200,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
|
|||
{
|
||||
usb_put_function(f_acm);
|
||||
usb_put_function_instance(fi_serial);
|
||||
gserial_free_line(tty_line);
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
|
|||
kfree(cdev->req->buf);
|
||||
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
|
||||
}
|
||||
cdev->next_string_id = 0;
|
||||
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
|
||||
}
|
||||
|
||||
|
|
|
|||
1003
drivers/usb/gadget/configfs.c
Normal file
1003
drivers/usb/gadget/configfs.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
|
|||
dum->devstatus = 0;
|
||||
|
||||
dum->driver = driver;
|
||||
dum->gadget.dev.driver = &driver->driver;
|
||||
dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
|
|
@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
|
|||
dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
dum->gadget.dev.driver = NULL;
|
||||
dum->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
|
|||
|
||||
/* The gadget structure is stored inside the hcd structure and will be
|
||||
* released along with it. */
|
||||
static void dummy_gadget_release(struct device *dev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void init_dummy_udc_hw(struct dummy *dum)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
|
|||
dum->gadget.ops = &dummy_ops;
|
||||
dum->gadget.max_speed = USB_SPEED_SUPER;
|
||||
|
||||
dev_set_name(&dum->gadget.dev, "gadget");
|
||||
dum->gadget.dev.parent = &pdev->dev;
|
||||
dum->gadget.dev.release = dummy_gadget_release;
|
||||
rc = device_register(&dum->gadget.dev);
|
||||
if (rc < 0) {
|
||||
put_device(&dum->gadget.dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_dummy_udc_hw(dum);
|
||||
|
||||
rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
|
||||
|
|
@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
|
|||
err_dev:
|
||||
usb_del_gadget_udc(&dum->gadget);
|
||||
err_udc:
|
||||
device_unregister(&dum->gadget.dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
|
|||
usb_del_gadget_udc(&dum->gadget);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
device_remove_file(&dum->gadget.dev, &dev_attr_function);
|
||||
device_unregister(&dum->gadget.dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1923,7 +1906,7 @@ done:
|
|||
}
|
||||
|
||||
/* usb 3.0 root hub device descriptor */
|
||||
struct {
|
||||
static struct {
|
||||
struct usb_bos_descriptor bos;
|
||||
struct usb_ss_cap_descriptor ss_cap;
|
||||
} __packed usb3_bos_desc = {
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
};
|
||||
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
static struct eth_dev *the_dev;
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
|
@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
|
|||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return rndis_bind_config(c, hostaddr);
|
||||
return rndis_bind_config(c, hostaddr, the_dev);
|
||||
}
|
||||
|
||||
static struct usb_configuration rndis_config_driver = {
|
||||
|
|
@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c)
|
|||
}
|
||||
|
||||
if (use_eem)
|
||||
return eem_bind_config(c);
|
||||
return eem_bind_config(c, the_dev);
|
||||
else if (can_support_ecm(c->cdev->gadget))
|
||||
return ecm_bind_config(c, hostaddr);
|
||||
return ecm_bind_config(c, hostaddr, the_dev);
|
||||
else
|
||||
return geth_bind_config(c, hostaddr);
|
||||
return geth_bind_config(c, hostaddr, the_dev);
|
||||
}
|
||||
|
||||
static struct usb_configuration eth_config_driver = {
|
||||
|
|
@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
|
|||
int status;
|
||||
|
||||
/* set up network link layer */
|
||||
status = gether_setup(cdev->gadget, hostaddr);
|
||||
if (status < 0)
|
||||
return status;
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev))
|
||||
return PTR_ERR(the_dev);
|
||||
|
||||
/* set up main config label and device descriptor */
|
||||
if (use_eem) {
|
||||
|
|
@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit eth_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -715,72 +715,6 @@ 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_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_acm *acm = func_to_acm(f);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
if (acm->notify_req)
|
||||
gs_free_req(acm->notify, acm->notify_req);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
/**
|
||||
* acm_bind_config - add a CDC ACM function to a configuration
|
||||
* @c: the configuration to support the CDC ACM instance
|
||||
* @port_num: /dev/ttyGS* port this interface will use
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
*/
|
||||
int acm_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
struct f_acm *acm;
|
||||
int status;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
acm = acm_alloc_basic_func();
|
||||
if (!acm)
|
||||
return -ENOMEM;
|
||||
|
||||
acm->port_num = port_num;
|
||||
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);
|
||||
|
|
@ -803,10 +737,24 @@ 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();
|
||||
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
|
||||
if (!acm)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
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";
|
||||
acm->port.func.strings = acm_strings;
|
||||
/* 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;
|
||||
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
acm->port_num = opts->port_num;
|
||||
acm->port.func.unbind = acm_unbind;
|
||||
|
|
@ -815,24 +763,85 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
|
|||
return &acm->port.func;
|
||||
}
|
||||
|
||||
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_serial_opts,
|
||||
func_inst.group);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_STRUCT(f_serial_opts);
|
||||
static ssize_t f_acm_attr_show(struct config_item *item,
|
||||
struct configfs_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
struct f_serial_opts_attribute *f_serial_opts_attr =
|
||||
container_of(attr, struct f_serial_opts_attribute, attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (f_serial_opts_attr->show)
|
||||
ret = f_serial_opts_attr->show(opts, page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void acm_attr_release(struct config_item *item)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
|
||||
usb_put_function_instance(&opts->func_inst);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations acm_item_ops = {
|
||||
.release = acm_attr_release,
|
||||
.show_attribute = f_acm_attr_show,
|
||||
};
|
||||
|
||||
static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", opts->port_num);
|
||||
}
|
||||
|
||||
static struct f_serial_opts_attribute f_acm_port_num =
|
||||
__CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
|
||||
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
&f_acm_port_num.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct config_item_type acm_func_type = {
|
||||
.ct_item_ops = &acm_item_ops,
|
||||
.ct_attrs = acm_attrs,
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
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);
|
||||
gserial_free_line(opts->port_num);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *acm_alloc_instance(void)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
int ret;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
opts->func_inst.free_func_inst = acm_free_instance;
|
||||
ret = gserial_alloc_line(&opts->port_num);
|
||||
if (ret) {
|
||||
kfree(opts);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
config_group_init_type_name(&opts->func_inst.group, "",
|
||||
&acm_func_type);
|
||||
return &opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int
|
||||
ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
struct f_ecm *ecm;
|
||||
int status;
|
||||
|
|
@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
|
||||
ecm_string_defs[1].s = ecm->ethaddr;
|
||||
|
||||
ecm->port.ioport = dev;
|
||||
ecm->port.cdc_filter = DEFAULT_FILTER;
|
||||
|
||||
ecm->port.func.name = "cdc_ethernet";
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ error:
|
|||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int __init eem_bind_config(struct usb_configuration *c)
|
||||
int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
|
||||
{
|
||||
struct f_eem *eem;
|
||||
int status;
|
||||
|
|
@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
|
|||
if (!eem)
|
||||
return -ENOMEM;
|
||||
|
||||
eem->port.ioport = dev;
|
||||
eem->port.cdc_filter = DEFAULT_FILTER;
|
||||
|
||||
eem->port.func.name = "cdc_eem";
|
||||
|
|
|
|||
|
|
@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
struct f_ncm *ncm;
|
||||
int status;
|
||||
|
|
@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
|
||||
spin_lock_init(&ncm->lock);
|
||||
ncm_reset_values(ncm);
|
||||
ncm->port.ioport = dev;
|
||||
ncm->port.is_fixed = true;
|
||||
|
||||
ncm->port.func.name = "cdc_network";
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_interface_descriptor obex_control_intf __initdata = {
|
||||
static struct usb_interface_descriptor obex_control_intf = {
|
||||
.bLength = sizeof(obex_control_intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
|
|
@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
|
|||
.bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX,
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
|
||||
static struct usb_interface_descriptor obex_data_nop_intf = {
|
||||
.bLength = sizeof(obex_data_nop_intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 1,
|
||||
|
|
@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
|
|||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor obex_data_intf __initdata = {
|
||||
static struct usb_interface_descriptor obex_data_intf = {
|
||||
.bLength = sizeof(obex_data_intf),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 2,
|
||||
|
|
@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
|
|||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
|
||||
static struct usb_cdc_header_desc obex_cdc_header_desc = {
|
||||
.bLength = sizeof(obex_cdc_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = cpu_to_le16(0x0120),
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
|
||||
static struct usb_cdc_union_desc obex_cdc_union_desc = {
|
||||
.bLength = sizeof(obex_cdc_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
|
|
@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
|
|||
.bSlaveInterface0 = 2,
|
||||
};
|
||||
|
||||
static struct usb_cdc_obex_desc obex_desc __initdata = {
|
||||
static struct usb_cdc_obex_desc obex_desc = {
|
||||
.bLength = sizeof(obex_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_OBEX_TYPE,
|
||||
|
|
@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
|
|||
|
||||
/* High-Speed Support */
|
||||
|
||||
static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
|
|||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
|
|||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *hs_function[] = {
|
||||
(struct usb_descriptor_header *) &obex_control_intf,
|
||||
(struct usb_descriptor_header *) &obex_cdc_header_desc,
|
||||
(struct usb_descriptor_header *) &obex_desc,
|
||||
|
|
@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
|
|||
|
||||
/* Full-Speed Support */
|
||||
|
||||
static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
|
|||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
|
|||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *fs_function[] = {
|
||||
(struct usb_descriptor_header *) &obex_control_intf,
|
||||
(struct usb_descriptor_header *) &obex_cdc_header_desc,
|
||||
(struct usb_descriptor_header *) &obex_desc,
|
||||
|
|
@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init
|
||||
obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
/* Some controllers can't support CDC OBEX ... */
|
||||
static inline bool can_support_obex(struct usb_configuration *c)
|
||||
{
|
||||
/* Since the first interface is a NOP, we can ignore the
|
||||
* issue of multi-interface support on most controllers.
|
||||
*
|
||||
* Altsettings are mandatory, however...
|
||||
*/
|
||||
if (!gadget_supports_altsettings(c->cdev->gadget))
|
||||
return false;
|
||||
|
||||
/* everything else is *probably* fine ... */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_obex *obex = func_to_obex(f);
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
if (!can_support_obex(c))
|
||||
return -EINVAL;
|
||||
|
||||
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
|
||||
status = usb_string_ids_tab(c->cdev, obex_string_defs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
obex_control_intf.iInterface =
|
||||
obex_string_defs[OBEX_CTRL_IDX].id;
|
||||
|
||||
status = obex_string_defs[OBEX_DATA_IDX].id;
|
||||
obex_data_nop_intf.iInterface = status;
|
||||
obex_data_intf.iInterface = status;
|
||||
}
|
||||
|
||||
/* allocate instance-specific interface IDs, and patch descriptors */
|
||||
|
||||
status = usb_interface_id(c, f);
|
||||
|
|
@ -319,6 +348,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
/* allocate instance-specific endpoints */
|
||||
|
||||
status = -ENODEV;
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
|
|
@ -376,29 +406,16 @@ fail:
|
|||
return status;
|
||||
}
|
||||
|
||||
#ifdef USBF_OBEX_INCLUDED
|
||||
|
||||
static void
|
||||
obex_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
obex_string_defs[OBEX_CTRL_IDX].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_obex(f));
|
||||
}
|
||||
|
||||
/* Some controllers can't support CDC OBEX ... */
|
||||
static inline bool can_support_obex(struct usb_configuration *c)
|
||||
{
|
||||
/* Since the first interface is a NOP, we can ignore the
|
||||
* issue of multi-interface support on most controllers.
|
||||
*
|
||||
* Altsettings are mandatory, however...
|
||||
*/
|
||||
if (!gadget_supports_altsettings(c->cdev->gadget))
|
||||
return false;
|
||||
|
||||
/* everything else is *probably* fine ... */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* obex_bind_config - add a CDC OBEX function to a configuration
|
||||
* @c: the configuration to support the CDC OBEX instance
|
||||
|
|
@ -412,21 +429,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
|
|||
struct f_obex *obex;
|
||||
int status;
|
||||
|
||||
if (!can_support_obex(c))
|
||||
return -EINVAL;
|
||||
|
||||
if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
|
||||
status = usb_string_ids_tab(c->cdev, obex_string_defs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
obex_control_intf.iInterface =
|
||||
obex_string_defs[OBEX_CTRL_IDX].id;
|
||||
|
||||
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 */
|
||||
obex = kzalloc(sizeof *obex, GFP_KERNEL);
|
||||
if (!obex)
|
||||
|
|
@ -441,7 +443,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
|
|||
obex->port.func.strings = obex_strings;
|
||||
/* descriptors are per-instance copies */
|
||||
obex->port.func.bind = obex_bind;
|
||||
obex->port.func.unbind = obex_unbind;
|
||||
obex->port.func.unbind = obex_old_unbind;
|
||||
obex->port.func.set_alt = obex_set_alt;
|
||||
obex->port.func.get_alt = obex_get_alt;
|
||||
obex->port.func.disable = obex_disable;
|
||||
|
|
@ -453,5 +455,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
|
|||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_serial_opts,
|
||||
func_inst.group);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_STRUCT(f_serial_opts);
|
||||
static ssize_t f_obex_attr_show(struct config_item *item,
|
||||
struct configfs_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
struct f_serial_opts_attribute *f_serial_opts_attr =
|
||||
container_of(attr, struct f_serial_opts_attribute, attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (f_serial_opts_attr->show)
|
||||
ret = f_serial_opts_attr->show(opts, page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void obex_attr_release(struct config_item *item)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
|
||||
usb_put_function_instance(&opts->func_inst);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations obex_item_ops = {
|
||||
.release = obex_attr_release,
|
||||
.show_attribute = f_obex_attr_show,
|
||||
};
|
||||
|
||||
static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", opts->port_num);
|
||||
}
|
||||
|
||||
static struct f_serial_opts_attribute f_obex_port_num =
|
||||
__CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
&f_obex_port_num.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct config_item_type obex_func_type = {
|
||||
.ct_item_ops = &obex_item_ops,
|
||||
.ct_attrs = acm_attrs,
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void obex_free_inst(struct usb_function_instance *f)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
opts = container_of(f, struct f_serial_opts, func_inst);
|
||||
gserial_free_line(opts->port_num);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *obex_alloc_inst(void)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
int ret;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
opts->func_inst.free_func_inst = obex_free_inst;
|
||||
ret = gserial_alloc_line(&opts->port_num);
|
||||
if (ret) {
|
||||
kfree(opts);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
config_group_init_type_name(&opts->func_inst.group, "",
|
||||
&obex_func_type);
|
||||
|
||||
return &opts->func_inst;
|
||||
}
|
||||
|
||||
static void obex_free(struct usb_function *f)
|
||||
{
|
||||
struct f_obex *obex;
|
||||
|
||||
obex = func_to_obex(f);
|
||||
kfree(obex);
|
||||
}
|
||||
|
||||
static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
obex_string_defs[OBEX_CTRL_IDX].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
|
||||
struct usb_function *obex_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_obex *obex;
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
obex = kzalloc(sizeof(*obex), GFP_KERNEL);
|
||||
if (!obex)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
|
||||
obex->port_num = opts->port_num;
|
||||
|
||||
obex->port.connect = obex_connect;
|
||||
obex->port.disconnect = obex_disconnect;
|
||||
|
||||
obex->port.func.name = "obex";
|
||||
obex->port.func.strings = obex_strings;
|
||||
/* descriptors are per-instance copies */
|
||||
obex->port.func.bind = obex_bind;
|
||||
obex->port.func.unbind = obex_unbind;
|
||||
obex->port.func.set_alt = obex_set_alt;
|
||||
obex->port.func.get_alt = obex_get_alt;
|
||||
obex->port.func.disable = obex_disable;
|
||||
obex->port.func.free_func = obex_free;
|
||||
|
||||
return &obex->port.func;
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
|
||||
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
|
|||
|
||||
int
|
||||
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer)
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev)
|
||||
{
|
||||
struct f_rndis *rndis;
|
||||
int status;
|
||||
|
|
@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
|||
rndis->vendorID = vendorID;
|
||||
rndis->manufacturer = manufacturer;
|
||||
|
||||
rndis->port.ioport = dev;
|
||||
/* RNDIS activates when the host changes this filter */
|
||||
rndis->port.cdc_filter = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
|
|
@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
|
|||
|
||||
/* interface descriptor: */
|
||||
|
||||
static struct usb_interface_descriptor gser_interface_desc __initdata = {
|
||||
static struct usb_interface_descriptor gser_interface_desc = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
|
|
@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
|
|||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_fs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_fs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *gser_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_out_desc,
|
||||
|
|
@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
|
|||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_hs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *gser_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_out_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_ss_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_ss_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
|
||||
static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
|
||||
.bLength = sizeof gser_ss_bulk_comp_desc,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_ss_function[] __initdata = {
|
||||
static struct usb_descriptor_header *gser_ss_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
|
||||
|
|
@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
|
|||
|
||||
/* serial function driver setup/binding */
|
||||
|
||||
static int __init
|
||||
gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
/* REVISIT might want instance-specific strings to help
|
||||
* distinguish instances ...
|
||||
*/
|
||||
|
||||
/* maybe allocate device-global string ID */
|
||||
if (gser_string_defs[0].id == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
gser_string_defs[0].id = status;
|
||||
}
|
||||
|
||||
/* allocate instance-specific interface IDs */
|
||||
status = usb_interface_id(c, f);
|
||||
if (status < 0)
|
||||
|
|
@ -246,44 +258,115 @@ fail:
|
|||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
|
||||
{
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_gser(f));
|
||||
return container_of(to_config_group(item), struct f_serial_opts,
|
||||
func_inst.group);
|
||||
}
|
||||
|
||||
/**
|
||||
* gser_bind_config - add a generic serial function to a configuration
|
||||
* @c: the configuration to support the serial instance
|
||||
* @port_num: /dev/ttyGS* port this interface will use
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
CONFIGFS_ATTR_STRUCT(f_serial_opts);
|
||||
static ssize_t f_serial_attr_show(struct config_item *item,
|
||||
struct configfs_attribute *attr,
|
||||
char *page)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
struct f_serial_opts_attribute *f_serial_opts_attr =
|
||||
container_of(attr, struct f_serial_opts_attribute, attr);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (f_serial_opts_attr->show)
|
||||
ret = f_serial_opts_attr->show(opts, page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void serial_attr_release(struct config_item *item)
|
||||
{
|
||||
struct f_serial_opts *opts = to_f_serial_opts(item);
|
||||
|
||||
usb_put_function_instance(&opts->func_inst);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations serial_item_ops = {
|
||||
.release = serial_attr_release,
|
||||
.show_attribute = f_serial_attr_show,
|
||||
};
|
||||
|
||||
static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
|
||||
{
|
||||
return sprintf(page, "%u\n", opts->port_num);
|
||||
}
|
||||
|
||||
static struct f_serial_opts_attribute f_serial_port_num =
|
||||
__CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
&f_serial_port_num.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct config_item_type serial_func_type = {
|
||||
.ct_item_ops = &serial_item_ops,
|
||||
.ct_attrs = acm_attrs,
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void gser_free_inst(struct usb_function_instance *f)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
opts = container_of(f, struct f_serial_opts, func_inst);
|
||||
gserial_free_line(opts->port_num);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *gser_alloc_inst(void)
|
||||
{
|
||||
struct f_serial_opts *opts;
|
||||
int ret;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
opts->func_inst.free_func_inst = gser_free_inst;
|
||||
ret = gserial_alloc_line(&opts->port_num);
|
||||
if (ret) {
|
||||
kfree(opts);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
config_group_init_type_name(&opts->func_inst.group, "",
|
||||
&serial_func_type);
|
||||
|
||||
return &opts->func_inst;
|
||||
}
|
||||
|
||||
static void gser_free(struct usb_function *f)
|
||||
{
|
||||
struct f_gser *serial;
|
||||
|
||||
serial = func_to_gser(f);
|
||||
kfree(serial);
|
||||
}
|
||||
|
||||
static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
|
||||
struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_gser *gser;
|
||||
int status;
|
||||
|
||||
/* REVISIT might want instance-specific strings to help
|
||||
* distinguish instances ...
|
||||
*/
|
||||
|
||||
/* maybe allocate device-global string ID */
|
||||
if (gser_string_defs[0].id == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
gser_string_defs[0].id = status;
|
||||
}
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
gser = kzalloc(sizeof *gser, GFP_KERNEL);
|
||||
gser = kzalloc(sizeof(*gser), GFP_KERNEL);
|
||||
if (!gser)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gser->port_num = port_num;
|
||||
opts = container_of(fi, struct f_serial_opts, func_inst);
|
||||
|
||||
gser->port_num = opts->port_num;
|
||||
|
||||
gser->port.func.name = "gser";
|
||||
gser->port.func.strings = gser_strings;
|
||||
|
|
@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
|||
gser->port.func.unbind = gser_unbind;
|
||||
gser->port.func.set_alt = gser_set_alt;
|
||||
gser->port.func.disable = gser_disable;
|
||||
gser->port.func.free_func = gser_free;
|
||||
|
||||
status = usb_add_function(c, &gser->port.func);
|
||||
if (status)
|
||||
kfree(gser);
|
||||
return status;
|
||||
return &gser->port.func;
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Al Borchers");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
|
|
|||
|
|
@ -898,7 +898,7 @@ static struct usb_function *source_sink_alloc_func(
|
|||
return &ss->function;
|
||||
}
|
||||
|
||||
static void acm_free_instance(struct usb_function_instance *fi)
|
||||
static void source_sink_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_ss_opts *ss_opts;
|
||||
|
||||
|
|
@ -913,7 +913,7 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
|
|||
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;
|
||||
ss_opts->func_inst.free_func_inst = source_sink_free_instance;
|
||||
return &ss_opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,
|
||||
|
|
|
|||
|
|
@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
struct f_gether *geth;
|
||||
int status;
|
||||
|
|
@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
|||
snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
|
||||
geth_string_defs[1].s = geth->ethaddr;
|
||||
|
||||
geth->port.ioport = dev;
|
||||
geth->port.cdc_filter = DEFAULT_FILTER;
|
||||
|
||||
geth->port.func.name = "cdc_subset";
|
||||
|
|
|
|||
|
|
@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param;
|
|||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* module parameters specific to the Video streaming endpoint */
|
||||
static unsigned streaming_interval = 1;
|
||||
static unsigned int streaming_interval = 1;
|
||||
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_interval, "1 - 16");
|
||||
|
||||
static unsigned streaming_maxpacket = 1024;
|
||||
static unsigned int streaming_maxpacket = 1024;
|
||||
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
|
||||
MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
|
||||
|
||||
static unsigned streaming_mult;
|
||||
module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
|
||||
|
||||
static unsigned streaming_maxburst;
|
||||
static unsigned int streaming_maxburst;
|
||||
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
||||
|
||||
|
|
@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
|||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define UVC_STRING_ASSOCIATION_IDX 0
|
||||
#define UVC_STRING_CONTROL_IDX 1
|
||||
#define UVC_STRING_STREAMING_IDX 2
|
||||
#define UVC_STRING_CONTROL_IDX 0
|
||||
#define UVC_STRING_STREAMING_IDX 1
|
||||
|
||||
static struct usb_string uvc_en_us_strings[] = {
|
||||
[UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
|
||||
[UVC_STRING_CONTROL_IDX].s = "Video Control",
|
||||
[UVC_STRING_CONTROL_IDX].s = "UVC Camera",
|
||||
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
|
||||
{ }
|
||||
};
|
||||
|
|
@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
|
|||
#define UVC_INTF_VIDEO_CONTROL 0
|
||||
#define UVC_INTF_VIDEO_STREAMING 1
|
||||
|
||||
#define STATUS_BYTECOUNT 16 /* 16 bytes status */
|
||||
#define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */
|
||||
|
||||
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
|
||||
.bLength = sizeof(uvc_iad),
|
||||
|
|
@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
|
|||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
|
||||
static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
|
||||
.bInterval = 8,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
|
||||
.bLength = sizeof(uvc_ss_control_comp),
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
/* The following 3 values can be tweaked if necessary. */
|
||||
.bMaxBurst = 0,
|
||||
.bmAttributes = 0,
|
||||
.wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
|
||||
};
|
||||
|
||||
static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
|
||||
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_ENDPOINT,
|
||||
.bDescriptorSubType = UVC_EP_INTERRUPT,
|
||||
.wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
|
||||
|
|
@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
|
|||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
|
||||
static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1,
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
|
||||
static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
/* super speed support */
|
||||
static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = 8,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
|
||||
.bLength = sizeof uvc_ss_control_comp,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
/* the following 3 values can be tweaked if necessary */
|
||||
/* .bMaxBurst = 0, */
|
||||
/* .bmAttributes = 0, */
|
||||
.wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_SYNC_ASYNC
|
||||
| USB_ENDPOINT_XFER_ISOC,
|
||||
/* The wMaxPacketSize and bInterval values will be initialized from
|
||||
* module parameters.
|
||||
*/
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
|
||||
.bLength = sizeof uvc_ss_streaming_comp,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
/* the following 3 values can be tweaked if necessary */
|
||||
.bMaxBurst = 0,
|
||||
.bmAttributes = 0,
|
||||
.wBytesPerInterval = cpu_to_le16(1024),
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
|
||||
.bLength = sizeof(uvc_ss_streaming_comp),
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
/* The following 3 values can be tweaked if necessary. */
|
||||
.bMaxBurst = 0,
|
||||
.bmAttributes = 0,
|
||||
.wBytesPerInterval = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
|
||||
|
|
@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void uvc_function_setup_continue(struct uvc_device *uvc)
|
||||
{
|
||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||
|
||||
usb_composite_setup_continue(cdev);
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_function_get_alt(struct usb_function *f, unsigned interface)
|
||||
{
|
||||
|
|
@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
|||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_CONNECTED;
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case 1:
|
||||
if (uvc->state != UVC_STATE_CONNECTED)
|
||||
|
|
@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
|||
memset(&v4l2_event, 0, sizeof(v4l2_event));
|
||||
v4l2_event.type = UVC_EVENT_STREAMON;
|
||||
v4l2_event_queue(uvc->vdev, &v4l2_event);
|
||||
|
||||
uvc->state = UVC_STATE_STREAMING;
|
||||
break;
|
||||
return USB_GADGET_DELAYED_STATUS;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
const struct uvc_descriptor_header * const *uvc_streaming_cls;
|
||||
const struct usb_descriptor_header * const *uvc_streaming_std;
|
||||
const struct usb_descriptor_header * const *src;
|
||||
static struct usb_endpoint_descriptor *uvc_control_ep;
|
||||
struct usb_descriptor_header **dst;
|
||||
struct usb_descriptor_header **hdr;
|
||||
unsigned int control_size;
|
||||
|
|
@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
uvc_control_desc = uvc->desc.ss_control;
|
||||
uvc_streaming_cls = uvc->desc.ss_streaming;
|
||||
uvc_streaming_std = uvc_ss_streaming;
|
||||
uvc_control_ep = &uvc_ss_control_ep;
|
||||
break;
|
||||
|
||||
case USB_SPEED_HIGH:
|
||||
uvc_control_desc = uvc->desc.fs_control;
|
||||
uvc_streaming_cls = uvc->desc.hs_streaming;
|
||||
uvc_streaming_std = uvc_hs_streaming;
|
||||
uvc_control_ep = &uvc_fs_control_ep;
|
||||
break;
|
||||
|
||||
case USB_SPEED_FULL:
|
||||
|
|
@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
uvc_control_desc = uvc->desc.fs_control;
|
||||
uvc_streaming_cls = uvc->desc.fs_streaming;
|
||||
uvc_streaming_std = uvc_fs_streaming;
|
||||
uvc_control_ep = &uvc_fs_control_ep;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
* Class-specific UVC control descriptors
|
||||
* uvc_control_ep
|
||||
* uvc_control_cs_ep
|
||||
* uvc_ss_control_comp (for SS only)
|
||||
* uvc_streaming_intf_alt0
|
||||
* Class-specific UVC streaming descriptors
|
||||
* uvc_{fs|hs}_streaming
|
||||
|
|
@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
control_size = 0;
|
||||
streaming_size = 0;
|
||||
bytes = uvc_iad.bLength + uvc_control_intf.bLength
|
||||
+ uvc_control_ep->bLength + uvc_control_cs_ep.bLength
|
||||
+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
|
||||
+ uvc_streaming_intf_alt0.bLength;
|
||||
|
||||
if (speed == USB_SPEED_SUPER) {
|
||||
|
|
@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
}
|
||||
|
||||
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
|
||||
*src; ++src) {
|
||||
*src; ++src) {
|
||||
control_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
}
|
||||
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
|
||||
*src; ++src) {
|
||||
*src; ++src) {
|
||||
streaming_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
|
|
@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
uvc_control_header->bInCollection = 1;
|
||||
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
|
||||
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
|
||||
if (speed == USB_SPEED_SUPER)
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
|
||||
|
||||
|
|
@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
UVC_COPY_DESCRIPTORS(mem, dst,
|
||||
(const struct usb_descriptor_header**)uvc_streaming_cls);
|
||||
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
|
||||
uvc_streaming_header->bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
|
||||
|
||||
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
|
||||
|
||||
|
|
@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
uvc->control_ep->driver_data = NULL;
|
||||
uvc->video.ep->driver_data = NULL;
|
||||
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0;
|
||||
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
|
||||
kfree(uvc->control_buf);
|
||||
|
||||
|
|
@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
unsigned int max_packet_mult;
|
||||
unsigned int max_packet_size;
|
||||
struct usb_ep *ep;
|
||||
int ret = -EINVAL;
|
||||
|
||||
INFO(cdev, "uvc_function_bind\n");
|
||||
|
||||
/* sanity check the streaming endpoint module parameters */
|
||||
if (streaming_interval < 1)
|
||||
streaming_interval = 1;
|
||||
if (streaming_interval > 16)
|
||||
streaming_interval = 16;
|
||||
if (streaming_mult > 2)
|
||||
streaming_mult = 2;
|
||||
if (streaming_maxburst > 15)
|
||||
streaming_maxburst = 15;
|
||||
|
||||
/*
|
||||
* fill in the FS video streaming specific descriptors from the
|
||||
* module parameters
|
||||
/* Sanity check the streaming endpoint module parameters.
|
||||
*/
|
||||
uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
|
||||
1023 : streaming_maxpacket;
|
||||
streaming_interval = clamp(streaming_interval, 1U, 16U);
|
||||
streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
|
||||
streaming_maxburst = min(streaming_maxburst, 15U);
|
||||
|
||||
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
|
||||
* module parameters.
|
||||
*
|
||||
* NOTE: We assume that the user knows what they are doing and won't
|
||||
* give parameters that their UDC doesn't support.
|
||||
*/
|
||||
if (streaming_maxpacket <= 1024) {
|
||||
max_packet_mult = 1;
|
||||
max_packet_size = streaming_maxpacket;
|
||||
} else if (streaming_maxpacket <= 2048) {
|
||||
max_packet_mult = 2;
|
||||
max_packet_size = streaming_maxpacket / 2;
|
||||
} else {
|
||||
max_packet_mult = 3;
|
||||
max_packet_size = streaming_maxpacket / 3;
|
||||
}
|
||||
|
||||
uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
|
||||
uvc_fs_streaming_ep.bInterval = streaming_interval;
|
||||
|
||||
uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
|
||||
uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
|
||||
uvc_hs_streaming_ep.bInterval = streaming_interval;
|
||||
|
||||
uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
|
||||
uvc_ss_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
|
||||
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
|
||||
uvc_ss_streaming_comp.wBytesPerInterval =
|
||||
max_packet_size * max_packet_mult * streaming_maxburst;
|
||||
|
||||
/* Allocate endpoints. */
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate control EP\n");
|
||||
goto error;
|
||||
|
|
@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
uvc->control_ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
|
||||
&uvc_ss_streaming_comp);
|
||||
else if (gadget_is_dualspeed(cdev->gadget))
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
|
||||
else
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
|
||||
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate streaming EP\n");
|
||||
goto error;
|
||||
|
|
@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
uvc->video.ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
|
||||
|
||||
/* Allocate interface IDs. */
|
||||
if ((ret = usb_interface_id(c, f)) < 0)
|
||||
goto error;
|
||||
|
|
@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
|
||||
uvc->streaming_intf = ret;
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
if (gadget_is_dualspeed(cdev->gadget))
|
||||
|
|
@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c,
|
|||
|
||||
/* Validate the descriptors. */
|
||||
if (fs_control == NULL || fs_control[0] == NULL ||
|
||||
fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
goto error;
|
||||
|
||||
if (ss_control == NULL || ss_control[0] == NULL ||
|
||||
ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
goto error;
|
||||
|
||||
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
|
||||
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
|
||||
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
if (ss_streaming == NULL || ss_streaming[0] == NULL ||
|
||||
ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
uvc->desc.fs_control = fs_control;
|
||||
|
|
@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c,
|
|||
uvc->desc.hs_streaming = hs_streaming;
|
||||
uvc->desc.ss_streaming = ss_streaming;
|
||||
|
||||
/* Allocate string descriptor numbers. */
|
||||
if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
|
||||
/* String descriptors are global, we only need to allocate string IDs
|
||||
* for the first UVC function. UVC functions beyond the first (if any)
|
||||
* will reuse the same IDs.
|
||||
*/
|
||||
if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) {
|
||||
ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
|
||||
if (ret)
|
||||
goto error;
|
||||
uvc_iad.iFunction =
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_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;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/video.h>
|
||||
|
||||
extern int uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *fs_control,
|
||||
const struct uvc_descriptor_header * const *hs_control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming,
|
||||
const struct uvc_descriptor_header * const *ss_streaming);
|
||||
int uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *fs_control,
|
||||
const struct uvc_descriptor_header * const *hs_control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming,
|
||||
const struct uvc_descriptor_header * const *ss_streaming);
|
||||
|
||||
#endif /* _F_UVC_H_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
|
|||
driver->driver.bus = NULL;
|
||||
/* hook up the driver */
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.speed = driver->max_speed;
|
||||
|
||||
/* Enable IRQ reg and Set usbcmd reg EN bit */
|
||||
|
|
@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
|
|||
nuke(loop_ep, -ESHUTDOWN);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
|
||||
|
|
@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
|
|||
|
||||
/* name: Identifies the controller hardware type. */
|
||||
udc->gadget.name = driver_name;
|
||||
|
||||
device_initialize(&udc->gadget.dev);
|
||||
|
||||
dev_set_name(&udc->gadget.dev, "gadget");
|
||||
|
||||
udc->gadget.dev.release = qe_udc_release;
|
||||
udc->gadget.dev.parent = &ofdev->dev;
|
||||
|
||||
/* initialize qe_ep struct */
|
||||
|
|
@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev)
|
|||
goto err5;
|
||||
}
|
||||
|
||||
ret = device_add(&udc->gadget.dev);
|
||||
ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget,
|
||||
qe_udc_release);
|
||||
if (ret)
|
||||
goto err6;
|
||||
|
||||
ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
|
||||
if (ret)
|
||||
goto err7;
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, udc);
|
||||
dev_info(udc->dev,
|
||||
"%s USB controller initialized as device\n",
|
||||
(udc->soc_type == PORT_QE) ? "QE" : "CPM");
|
||||
return 0;
|
||||
|
||||
err7:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err6:
|
||||
free_irq(udc->usb_irq, udc);
|
||||
err5:
|
||||
|
|
@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev)
|
|||
|
||||
iounmap(udc->usb_regs);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
/* wait for release() of gadget.dev to free udc */
|
||||
wait_for_completion(&done);
|
||||
|
||||
|
|
|
|||
|
|
@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
|
|||
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
|
||||
}
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
ep_is_in(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
} else
|
||||
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
ep_is_in(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
|
||||
|
||||
if (status && (status != -ESHUTDOWN))
|
||||
VDBG("complete %s req %p stat %d len %u/%u",
|
||||
|
|
@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
struct fsl_req *req = container_of(_req, struct fsl_req, req);
|
||||
struct fsl_udc *udc;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* catch various bogus parameters */
|
||||
if (!_req || !req->req.complete || !req->req.buf
|
||||
|
|
@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
|
||||
req->ep = ep;
|
||||
|
||||
/* map virtual address to hardware */
|
||||
if (req->req.dma == DMA_ADDR_INVALID) {
|
||||
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
|
||||
req->req.buf,
|
||||
req->req.length, ep_is_in(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
} else {
|
||||
dma_sync_single_for_device(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
ep_is_in(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 0;
|
||||
}
|
||||
ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->req.status = -EINPROGRESS;
|
||||
req->req.actual = 0;
|
||||
|
|
@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
|
|||
{
|
||||
struct fsl_req *req = udc->status_req;
|
||||
struct fsl_ep *ep;
|
||||
int ret;
|
||||
|
||||
if (direction == EP_DIR_IN)
|
||||
udc->ep0_dir = USB_DIR_IN;
|
||||
|
|
@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
|
|||
req->req.complete = NULL;
|
||||
req->dtd_count = 0;
|
||||
|
||||
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
|
||||
req->req.buf, req->req.length,
|
||||
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
|
||||
fsl_queue_td(ep, req);
|
||||
|
|
@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
|
|||
u16 tmp = 0; /* Status, cpu endian */
|
||||
struct fsl_req *req;
|
||||
struct fsl_ep *ep;
|
||||
int ret;
|
||||
|
||||
ep = &udc->eps[0];
|
||||
|
||||
|
|
@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
|
|||
req->req.complete = NULL;
|
||||
req->dtd_count = 0;
|
||||
|
||||
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
|
||||
req->req.buf, req->req.length,
|
||||
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
|
||||
if (ret)
|
||||
goto stall;
|
||||
|
||||
/* prime the data phase */
|
||||
if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
|
||||
|
|
@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g,
|
|||
driver->driver.bus = NULL;
|
||||
/* hook up the driver */
|
||||
udc_controller->driver = driver;
|
||||
udc_controller->gadget.dev.driver = &driver->driver;
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
|
|
@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g,
|
|||
if (retval < 0) {
|
||||
ERR("can't bind to transceiver\n");
|
||||
driver->unbind(&udc_controller->gadget);
|
||||
udc_controller->gadget.dev.driver = 0;
|
||||
udc_controller->driver = 0;
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g,
|
|||
nuke(loop_ep, -ESHUTDOWN);
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
udc_controller->gadget.dev.driver = NULL;
|
||||
udc_controller->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -2521,12 +2493,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
|
||||
/* Setup gadget.dev and register with kernel */
|
||||
dev_set_name(&udc_controller->gadget.dev, "gadget");
|
||||
udc_controller->gadget.dev.release = fsl_udc_release;
|
||||
udc_controller->gadget.dev.parent = &pdev->dev;
|
||||
udc_controller->gadget.dev.of_node = pdev->dev.of_node;
|
||||
ret = device_register(&udc_controller->gadget.dev);
|
||||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
|
||||
udc_controller->gadget.is_otg = 1;
|
||||
|
|
@ -2559,10 +2526,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
|
||||
if (udc_controller->td_pool == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister;
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
|
||||
ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget,
|
||||
fsl_udc_release);
|
||||
if (ret)
|
||||
goto err_del_udc;
|
||||
|
||||
|
|
@ -2571,8 +2539,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
|||
|
||||
err_del_udc:
|
||||
dma_pool_destroy(udc_controller->td_pool);
|
||||
err_unregister:
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
err_free_irq:
|
||||
free_irq(udc_controller->irq, udc_controller);
|
||||
err_iounmap:
|
||||
|
|
@ -2622,7 +2588,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
|
|||
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
device_unregister(&udc_controller->gadget.dev);
|
||||
/* free udc --wait for the release() finished */
|
||||
wait_for_completion(&done);
|
||||
|
||||
|
|
@ -2747,21 +2712,7 @@ static struct platform_driver udc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
|
||||
return platform_driver_probe(&udc_driver, fsl_udc_probe);
|
||||
}
|
||||
|
||||
module_init(udc_init);
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
printk(KERN_WARNING "%s unregistered\n", driver_desc);
|
||||
}
|
||||
|
||||
module_exit(udc_exit);
|
||||
module_platform_driver_probe(udc_driver, fsl_udc_probe);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
|
|||
|
||||
if (reg & FUSB300_EPSET0_STL) {
|
||||
printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
|
||||
reg &= ~FUSB300_EPSET0_STL;
|
||||
reg |= FUSB300_EPSET0_STL_CLR;
|
||||
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
|
||||
}
|
||||
}
|
||||
|
|
@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
|
|||
|
||||
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
|
||||
FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
|
||||
return;
|
||||
|
||||
IDMA_RESET:
|
||||
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0,
|
||||
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
|
||||
reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
|
||||
reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
|
||||
iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
|
||||
}
|
||||
|
||||
static void fusb300_set_idma(struct fusb300_ep *ep,
|
||||
static void fusb300_set_idma(struct fusb300_ep *ep,
|
||||
struct fusb300_request *req)
|
||||
{
|
||||
dma_addr_t d;
|
||||
int ret;
|
||||
|
||||
d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(NULL, d)) {
|
||||
printk(KERN_DEBUG "dma_mapping_error\n");
|
||||
ret = usb_gadget_map_request(&ep->fusb300->gadget,
|
||||
&req->req, DMA_TO_DEVICE);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
|
||||
|
||||
fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
|
||||
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
|
||||
|
||||
fusb300_fill_idma_prdtbl(ep, d, req->req.length);
|
||||
fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
|
||||
/* check idma is done */
|
||||
fusb300_wait_idma_finished(ep);
|
||||
|
||||
dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
|
||||
usb_gadget_unmap_request(&ep->fusb300->gadget,
|
||||
&req->req, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void in_ep_fifo_handler(struct fusb300_ep *ep)
|
||||
|
|
@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
|
|||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
fusb300->driver = driver;
|
||||
fusb300->gadget.dev.driver = &driver->driver;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g,
|
|||
struct fusb300 *fusb300 = to_fusb300(g);
|
||||
|
||||
driver->unbind(&fusb300->gadget);
|
||||
fusb300->gadget.dev.driver = NULL;
|
||||
|
||||
init_controller(fusb300);
|
||||
fusb300->driver = NULL;
|
||||
|
|
@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
|
|||
|
||||
fusb300->gadget.ops = &fusb300_gadget_ops;
|
||||
|
||||
device_initialize(&fusb300->gadget.dev);
|
||||
|
||||
dev_set_name(&fusb300->gadget.dev, "gadget");
|
||||
|
||||
fusb300->gadget.max_speed = USB_SPEED_HIGH;
|
||||
fusb300->gadget.dev.parent = &pdev->dev;
|
||||
fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
fusb300->gadget.dev.release = pdev->dev.release;
|
||||
fusb300->gadget.name = udc_name;
|
||||
fusb300->reg = reg;
|
||||
|
||||
|
|
@ -1478,19 +1469,10 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@
|
|||
/*
|
||||
* * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
|
||||
* */
|
||||
#define FUSB300_EPSET0_STL_CLR (1 << 3)
|
||||
#define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
|
||||
#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1)
|
||||
#define FUSB300_EPSET0_STL (1 << 0)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#define pr_fmt(fmt) "g_ffs: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
|
|
@ -38,13 +37,16 @@
|
|||
# include "u_ether.c"
|
||||
|
||||
static u8 gfs_hostaddr[ETH_ALEN];
|
||||
static struct eth_dev *the_dev;
|
||||
# ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
# endif
|
||||
#else
|
||||
# define gether_cleanup() do { } while (0)
|
||||
# define gether_setup(gadget, hostaddr) ((int)0)
|
||||
# define the_dev NULL
|
||||
# define gether_cleanup(dev) do { } while (0)
|
||||
# define gfs_hostaddr NULL
|
||||
struct eth_dev;
|
||||
#endif
|
||||
|
||||
#include "f_fs.c"
|
||||
|
|
@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
|
|||
|
||||
struct gfs_configuration {
|
||||
struct usb_configuration c;
|
||||
int (*eth)(struct usb_configuration *c, u8 *ethaddr);
|
||||
int (*eth)(struct usb_configuration *c, u8 *ethaddr,
|
||||
struct eth_dev *dev);
|
||||
} gfs_configurations[] = {
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
{
|
||||
|
|
@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
|||
|
||||
if (missing_funcs)
|
||||
return -ENODEV;
|
||||
|
||||
ret = gether_setup(cdev->gadget, gfs_hostaddr);
|
||||
if (unlikely(ret < 0))
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
|
||||
#endif
|
||||
if (IS_ERR(the_dev)) {
|
||||
ret = PTR_ERR(the_dev);
|
||||
goto error_quick;
|
||||
}
|
||||
gfs_ether_setup = true;
|
||||
|
||||
ret = usb_string_ids_tab(cdev, gfs_strings);
|
||||
|
|
@ -386,7 +392,7 @@ error_unbind:
|
|||
for (i = 0; i < func_num; i++)
|
||||
functionfs_unbind(ffs_tab[i].ffs_data);
|
||||
error:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
error_quick:
|
||||
gfs_ether_setup = false;
|
||||
return ret;
|
||||
|
|
@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
|
|||
* do...?
|
||||
*/
|
||||
if (gfs_ether_setup)
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
gfs_ether_setup = false;
|
||||
|
||||
for (i = func_num; i--; )
|
||||
|
|
@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c)
|
|||
}
|
||||
|
||||
if (gc->eth) {
|
||||
ret = gc->eth(c, gfs_hostaddr);
|
||||
ret = gc->eth(c, gfs_hostaddr, the_dev);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c)
|
|||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
return can_support_ecm(c->cdev->gadget)
|
||||
? ecm_bind_config(c, ethaddr)
|
||||
: geth_bind_config(c, ethaddr);
|
||||
? ecm_bind_config(c, ethaddr, dev)
|
||||
: geth_bind_config(c, ethaddr, dev);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@
|
|||
#define DRIVER_DESC "TC86C001 USB Device Controller"
|
||||
#define DRIVER_VERSION "30-Oct 2003"
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
static const char driver_name [] = "goku_udc";
|
||||
static const char driver_desc [] = DRIVER_DESC;
|
||||
|
||||
|
|
@ -275,7 +273,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
return &req->req;
|
||||
}
|
||||
|
|
@ -1354,7 +1351,6 @@ static int goku_udc_start(struct usb_gadget *g,
|
|||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
/*
|
||||
* then enable host detection and ep0; and we're ready
|
||||
|
|
@ -1394,7 +1390,6 @@ static int goku_udc_stop(struct usb_gadget *g,
|
|||
dev->driver = NULL;
|
||||
stop_activity(dev, driver);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
dev->gadget.dev.driver = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1716,8 +1711,6 @@ static void goku_remove(struct pci_dev *pdev)
|
|||
pci_resource_len (pdev, 0));
|
||||
if (dev->enabled)
|
||||
pci_disable_device(pdev);
|
||||
if (dev->registered)
|
||||
device_unregister(&dev->gadget.dev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
dev->regs = NULL;
|
||||
|
|
@ -1756,10 +1749,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
dev->gadget.max_speed = USB_SPEED_FULL;
|
||||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.dev.parent = &pdev->dev;
|
||||
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
dev->gadget.dev.release = gadget_release;
|
||||
dev->gadget.name = driver_name;
|
||||
|
||||
/* now all the pci goodies ... */
|
||||
|
|
@ -1810,13 +1799,8 @@ 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
|
||||
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval) {
|
||||
put_device(&dev->gadget.dev);
|
||||
goto err;
|
||||
}
|
||||
dev->registered = 1;
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
|
|
|
|||
|
|
@ -250,8 +250,7 @@ struct goku_udc {
|
|||
got_region:1,
|
||||
req_config:1,
|
||||
configured:1,
|
||||
enabled:1,
|
||||
registered:1;
|
||||
enabled:1;
|
||||
|
||||
/* pci state used to access those endpoints */
|
||||
struct pci_dev *pdev;
|
||||
|
|
|
|||
|
|
@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget,
|
|||
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;
|
||||
|
||||
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
|
||||
__func__, driver->driver.name);
|
||||
|
|
@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
|
|||
imx_udc_disable(imx_usb);
|
||||
del_timer(&imx_usb->timer);
|
||||
|
||||
imx_usb->gadget.dev.driver = NULL;
|
||||
imx_usb->driver = NULL;
|
||||
|
||||
D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
|
||||
|
|
@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
imx_usb->clk = clk;
|
||||
imx_usb->dev = &pdev->dev;
|
||||
|
||||
device_initialize(&imx_usb->gadget.dev);
|
||||
|
||||
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);
|
||||
|
|
@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
|
||||
if (ret)
|
||||
goto fail5;
|
||||
goto fail4;
|
||||
|
||||
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);
|
||||
|
|
@ -1509,7 +1496,6 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
|
|||
status = req->req.status;
|
||||
|
||||
if (ep->lep) {
|
||||
enum dma_data_direction direction;
|
||||
|
||||
if (ep->is_in)
|
||||
direction = DMA_TO_DEVICE;
|
||||
else
|
||||
direction = DMA_FROM_DEVICE;
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
direction);
|
||||
req->req.dma = 0;
|
||||
req->mapped = 0;
|
||||
} else
|
||||
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
direction);
|
||||
usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
|
||||
|
||||
/* Free DDs */
|
||||
udc_dd_free(udc, req->dd_desc_ptr);
|
||||
|
|
@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
|
|||
}
|
||||
|
||||
if (ep->lep) {
|
||||
enum dma_data_direction direction;
|
||||
struct lpc32xx_usbd_dd_gad *dd;
|
||||
|
||||
/* Map DMA pointer */
|
||||
if (ep->is_in)
|
||||
direction = DMA_TO_DEVICE;
|
||||
else
|
||||
direction = DMA_FROM_DEVICE;
|
||||
|
||||
if (req->req.dma == 0) {
|
||||
req->req.dma = dma_map_single(
|
||||
ep->udc->gadget.dev.parent,
|
||||
req->req.buf, req->req.length, direction);
|
||||
req->mapped = 1;
|
||||
} else {
|
||||
dma_sync_single_for_device(
|
||||
ep->udc->gadget.dev.parent, req->req.dma,
|
||||
req->req.length, direction);
|
||||
req->mapped = 0;
|
||||
}
|
||||
status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* For the request, build a list of DDs */
|
||||
dd = udc_dd_alloc(udc);
|
||||
|
|
@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget,
|
|||
}
|
||||
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.dev.of_node = udc->dev->of_node;
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
|
|
@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget,
|
|||
}
|
||||
|
||||
udc->enabled = 0;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
|
|||
udc_disable(udc);
|
||||
udc_reinit(udc);
|
||||
|
||||
retval = device_register(&udc->gadget.dev);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "Device registration failure\n");
|
||||
goto dev_register_fail;
|
||||
}
|
||||
|
||||
/* Request IRQs - low and high priority USB device IRQs are routed to
|
||||
* the same handler, while the DMA interrupt is routed elsewhere */
|
||||
retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
|
||||
|
|
@ -3320,8 +3281,6 @@ irq_dev_fail:
|
|||
irq_hp_fail:
|
||||
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
|
||||
irq_lp_fail:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
dev_register_fail:
|
||||
dma_pool_destroy(udc->dd_cache);
|
||||
dma_alloc_fail:
|
||||
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
|
||||
|
|
@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
|
|||
free_irq(udc->udp_irq[IRQ_USB_HP], udc);
|
||||
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
clk_put(udc->usb_otg_clk);
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
|
|
|
|||
|
|
@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g,
|
|||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
m66592->driver = driver;
|
||||
m66592->gadget.dev.driver = &driver->driver;
|
||||
|
||||
m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
|
||||
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
|
||||
|
|
@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g,
|
|||
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
|
||||
|
||||
driver->unbind(&m66592->gadget);
|
||||
m66592->gadget.dev.driver = NULL;
|
||||
|
||||
init_controller(m66592);
|
||||
disable_controller(m66592);
|
||||
|
|
@ -1538,7 +1536,6 @@ 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);
|
||||
|
|
@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev)
|
|||
dev_set_drvdata(&pdev->dev, m66592);
|
||||
|
||||
m66592->gadget.ops = &m66592_gadget_ops;
|
||||
device_initialize(&m66592->gadget.dev);
|
||||
dev_set_name(&m66592->gadget.dev, "gadget");
|
||||
m66592->gadget.max_speed = USB_SPEED_HIGH;
|
||||
m66592->gadget.dev.parent = &pdev->dev;
|
||||
m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
m66592->gadget.dev.release = pdev->dev.release;
|
||||
m66592->gadget.name = udc_name;
|
||||
|
||||
init_timer(&m66592->timer);
|
||||
|
|
@ -1674,12 +1666,6 @@ 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;
|
||||
|
|
@ -1688,9 +1674,6 @@ 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:
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ static struct fsg_common fsg_common;
|
|||
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
static unsigned char tty_line;
|
||||
static struct usb_function_instance *fi_acm;
|
||||
static struct eth_dev *the_dev;
|
||||
|
||||
/********** RNDIS **********/
|
||||
|
||||
|
|
@ -152,13 +152,15 @@ static __init int rndis_do_config(struct usb_configuration *c)
|
|||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
ret = rndis_bind_config(c, hostaddr);
|
||||
ret = rndis_bind_config(c, hostaddr, the_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
f_acm_rndis = usb_get_function(fi_acm);
|
||||
if (IS_ERR(f_acm_rndis))
|
||||
if (IS_ERR(f_acm_rndis)) {
|
||||
ret = PTR_ERR(f_acm_rndis);
|
||||
goto err_func_acm;
|
||||
}
|
||||
|
||||
ret = usb_add_function(c, f_acm_rndis);
|
||||
if (ret)
|
||||
|
|
@ -214,7 +216,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
|
|||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
ret = ecm_bind_config(c, hostaddr);
|
||||
ret = ecm_bind_config(c, hostaddr, the_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -269,7 +271,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
|
|||
static int __ref multi_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct f_serial_opts *opts;
|
||||
int status;
|
||||
|
||||
if (!can_support_ecm(cdev->gadget)) {
|
||||
|
|
@ -279,24 +280,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
|
|||
}
|
||||
|
||||
/* set up network link layer */
|
||||
status = gether_setup(cdev->gadget, hostaddr);
|
||||
if (status < 0)
|
||||
return status;
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev))
|
||||
return PTR_ERR(the_dev);
|
||||
|
||||
/* set up serial link layer */
|
||||
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;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
opts = container_of(fi_acm, struct f_serial_opts, func_inst);
|
||||
opts->port_num = tty_line;
|
||||
|
||||
/* set up mass storage function */
|
||||
{
|
||||
void *retp;
|
||||
|
|
@ -334,10 +328,8 @@ fail2:
|
|||
fsg_common_put(&fsg_common);
|
||||
fail1:
|
||||
usb_put_function_instance(fi_acm);
|
||||
fail0dot5:
|
||||
gserial_free_line(tty_line);
|
||||
fail0:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -350,8 +342,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
|
|||
usb_put_function(f_acm_rndis);
|
||||
#endif
|
||||
usb_put_function_instance(fi_acm);
|
||||
gserial_free_line(tty_line);
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/mv_usb.h>
|
||||
#include <linux/clk.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "mv_u3d.h"
|
||||
|
||||
|
|
@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
|
|||
struct mv_u3d_trb *curr_trb;
|
||||
dma_addr_t cur_deq_lo;
|
||||
struct mv_u3d_ep_context *curr_ep_context;
|
||||
int trb_complete, actual, remaining_length;
|
||||
int trb_complete, actual, remaining_length = 0;
|
||||
int direction, ep_num;
|
||||
int retval = 0;
|
||||
u32 tmp, status, length;
|
||||
|
|
@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
|
|||
*/
|
||||
static
|
||||
void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
|
||||
__releases(&ep->udc->lock)
|
||||
__acquires(&ep->udc->lock)
|
||||
{
|
||||
struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
|
||||
|
||||
|
|
@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
|
||||
__func__, _ep->name, (u32)req);
|
||||
dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
|
||||
__func__, _ep->name, req);
|
||||
|
||||
/* catch various bogus parameters */
|
||||
if (!req->req.complete || !req->req.buf
|
||||
|| !list_empty(&req->queue)) {
|
||||
dev_err(u3d->dev,
|
||||
"%s, bad params, _req: 0x%x,"
|
||||
"req->req.complete: 0x%x, req->req.buf: 0x%x,"
|
||||
"%s, bad params, _req: 0x%p,"
|
||||
"req->req.complete: 0x%p, req->req.buf: 0x%p,"
|
||||
"list_empty: 0x%x\n",
|
||||
__func__, (u32)_req,
|
||||
(u32)req->req.complete, (u32)req->req.buf,
|
||||
(u32)list_empty(&req->queue));
|
||||
__func__, _req,
|
||||
req->req.complete, req->req.buf,
|
||||
list_empty(&req->queue));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (unlikely(!ep->ep.desc)) {
|
||||
|
|
@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|||
struct mv_u3d_req, queue);
|
||||
|
||||
/* Point first TRB of next request to the EP context. */
|
||||
iowrite32((u32) next_req->trb_head,
|
||||
iowrite32((unsigned long) next_req->trb_head,
|
||||
&ep_context->trb_addr_lo);
|
||||
} else {
|
||||
struct mv_u3d_ep_context *ep_context;
|
||||
|
|
@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g,
|
|||
/* hook up the driver ... */
|
||||
driver->driver.bus = NULL;
|
||||
u3d->driver = driver;
|
||||
u3d->gadget.dev.driver = &driver->driver;
|
||||
|
||||
u3d->ep0_dir = USB_DIR_OUT;
|
||||
|
||||
|
|
@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g,
|
|||
|
||||
spin_unlock_irqrestore(&u3d->lock, flags);
|
||||
|
||||
u3d->gadget.dev.driver = NULL;
|
||||
u3d->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
|
|||
|
||||
static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
|
||||
struct usb_ctrlrequest *setup)
|
||||
__releases(&u3c->lock)
|
||||
__acquires(&u3c->lock)
|
||||
{
|
||||
bool delegate = false;
|
||||
|
||||
|
|
@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void mv_u3d_gadget_release(struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
static int mv_u3d_remove(struct platform_device *dev)
|
||||
{
|
||||
struct mv_u3d *u3d = platform_get_drvdata(dev);
|
||||
|
|
@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
|
|||
|
||||
clk_put(u3d->clk);
|
||||
|
||||
device_unregister(&u3d->gadget.dev);
|
||||
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
kfree(u3d);
|
||||
|
|
@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
u3d->dev = &dev->dev;
|
||||
u3d->vbus = pdata->vbus;
|
||||
|
||||
u3d->clk = clk_get(&dev->dev, pdata->clkname[0]);
|
||||
u3d->clk = clk_get(&dev->dev, NULL);
|
||||
if (IS_ERR(u3d->clk)) {
|
||||
retval = PTR_ERR(u3d->clk);
|
||||
goto err_get_clk;
|
||||
|
|
@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
retval = -EBUSY;
|
||||
goto err_map_cap_regs;
|
||||
} else {
|
||||
dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n",
|
||||
(unsigned int)r->start, (unsigned int)u3d->cap_regs);
|
||||
dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
|
||||
(unsigned long) r->start,
|
||||
(unsigned long) u3d->cap_regs);
|
||||
}
|
||||
|
||||
/* we will access controller register, so enable the u3d controller */
|
||||
|
|
@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs
|
||||
u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
|
||||
+ MV_U3D_USB3_OP_REGS_OFFSET);
|
||||
|
||||
u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs
|
||||
u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
|
||||
+ ioread32(&u3d->cap_regs->vuoff));
|
||||
|
||||
u3d->max_eps = 16;
|
||||
|
|
@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
|
||||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&u3d->gadget.dev, "gadget");
|
||||
u3d->gadget.dev.parent = &dev->dev;
|
||||
u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
|
||||
u3d->gadget.dev.release = mv_u3d_gadget_release;
|
||||
u3d->gadget.name = driver_name; /* gadget name */
|
||||
|
||||
retval = device_register(&u3d->gadget.dev);
|
||||
if (retval)
|
||||
goto err_register_gadget_device;
|
||||
|
||||
mv_u3d_eps_init(u3d);
|
||||
|
||||
/* external vbus detection */
|
||||
|
|
@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev)
|
|||
return 0;
|
||||
|
||||
err_unregister:
|
||||
device_unregister(&u3d->gadget.dev);
|
||||
err_register_gadget_device:
|
||||
free_irq(u3d->irq, &dev->dev);
|
||||
err_request_irq:
|
||||
err_get_irq:
|
||||
|
|
@ -2021,7 +2004,7 @@ err_pdata:
|
|||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mv_u3d_suspend(struct device *dev)
|
||||
{
|
||||
struct mv_u3d *u3d = dev_get_drvdata(dev);
|
||||
|
|
@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
|
||||
|
||||
static void mv_u3d_shutdown(struct platform_device *dev)
|
||||
{
|
||||
struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
|
||||
|
|
@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev)
|
|||
|
||||
static struct platform_driver mv_u3d_driver = {
|
||||
.probe = mv_u3d_probe,
|
||||
.remove = __exit_p(mv_u3d_remove),
|
||||
.remove = mv_u3d_remove,
|
||||
.shutdown = mv_u3d_shutdown,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mv-u3d",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &mv_u3d_pm_ops,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -222,8 +222,7 @@ struct mv_udc {
|
|||
struct mv_usb_platform_data *pdata;
|
||||
|
||||
/* some SOC has mutiple clock sources for USB*/
|
||||
unsigned int clknum;
|
||||
struct clk *clk[0];
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* endpoint data structure */
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index,
|
|||
* request is still in progress.
|
||||
*/
|
||||
static void done(struct mv_ep *ep, struct mv_req *req, int status)
|
||||
__releases(&ep->udc->lock)
|
||||
__acquires(&ep->udc->lock)
|
||||
{
|
||||
struct mv_udc *udc = NULL;
|
||||
unsigned char stopped = ep->stopped;
|
||||
|
|
@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
|
|||
dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
|
||||
}
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
((ep_dir(ep) == EP_DIR_IN) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE));
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
} else
|
||||
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
((ep_dir(ep) == EP_DIR_IN) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE));
|
||||
usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
|
||||
|
||||
if (status && (status != -ESHUTDOWN))
|
||||
dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
|
||||
|
|
@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
req->ep = ep;
|
||||
|
||||
/* map virtual address to hardware */
|
||||
if (req->req.dma == DMA_ADDR_INVALID) {
|
||||
req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
|
||||
req->req.buf,
|
||||
req->req.length, ep_dir(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
} else {
|
||||
dma_sync_single_for_device(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
ep_dir(ep)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 0;
|
||||
}
|
||||
retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
req->req.status = -EINPROGRESS;
|
||||
req->req.actual = 0;
|
||||
|
|
@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
return 0;
|
||||
|
||||
err_unmap_dma:
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
((ep_dir(ep) == EP_DIR_IN) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE));
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
} else
|
||||
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
((ep_dir(ep) == EP_DIR_IN) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE));
|
||||
usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = {
|
|||
|
||||
static void udc_clock_enable(struct mv_udc *udc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < udc->clknum; i++)
|
||||
clk_prepare_enable(udc->clk[i]);
|
||||
clk_prepare_enable(udc->clk);
|
||||
}
|
||||
|
||||
static void udc_clock_disable(struct mv_udc *udc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < udc->clknum; i++)
|
||||
clk_disable_unprepare(udc->clk[i]);
|
||||
clk_disable_unprepare(udc->clk);
|
||||
}
|
||||
|
||||
static void udc_stop(struct mv_udc *udc)
|
||||
|
|
@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
|
|||
/* hook up the driver ... */
|
||||
driver->driver.bus = NULL;
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
|
||||
udc->usb_state = USB_STATE_ATTACHED;
|
||||
udc->ep0_state = WAIT_FOR_SETUP;
|
||||
|
|
@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
|
|||
dev_err(&udc->dev->dev,
|
||||
"unable to register peripheral to otg\n");
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
|
@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget,
|
|||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
/* unbind gadget driver */
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
|
|||
|
||||
return 0;
|
||||
out:
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
((ep_dir(ep) == EP_DIR_IN) ?
|
||||
DMA_TO_DEVICE : DMA_FROM_DEVICE));
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
}
|
||||
usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1695,6 +1647,8 @@ out:
|
|||
|
||||
static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
|
||||
struct usb_ctrlrequest *setup)
|
||||
__releases(&ep->udc->lock)
|
||||
__acquires(&ep->udc->lock)
|
||||
{
|
||||
bool delegate = false;
|
||||
|
||||
|
|
@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc)
|
|||
}
|
||||
}
|
||||
|
||||
void irq_process_reset(struct mv_udc *udc)
|
||||
static void irq_process_reset(struct mv_udc *udc)
|
||||
{
|
||||
u32 tmp;
|
||||
unsigned int loops;
|
||||
|
|
@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev)
|
|||
|
||||
mv_udc_disable(udc);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
/* free dev, wait for the release() finished */
|
||||
wait_for_completion(udc->done);
|
||||
|
||||
|
|
@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct mv_udc *udc;
|
||||
int retval = 0;
|
||||
int clk_i = 0;
|
||||
struct resource *r;
|
||||
size_t size;
|
||||
|
||||
|
|
@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
|
||||
udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
|
||||
if (udc == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for udc\n");
|
||||
return -ENOMEM;
|
||||
|
|
@ -2173,27 +2123,25 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
|
||||
udc->dev = pdev;
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
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
|
||||
if (IS_ERR(udc->transceiver)) {
|
||||
retval = PTR_ERR(udc->transceiver);
|
||||
|
||||
udc->clknum = pdata->clknum;
|
||||
for (clk_i = 0; clk_i < udc->clknum; 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]);
|
||||
return retval;
|
||||
if (retval == -ENXIO)
|
||||
return retval;
|
||||
|
||||
udc->transceiver = NULL;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
/* udc only have one sysclk. */
|
||||
udc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(udc->clk))
|
||||
return PTR_ERR(udc->clk);
|
||||
|
||||
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
|
||||
if (r == NULL) {
|
||||
dev_err(&pdev->dev, "no I/O memory resource defined\n");
|
||||
|
|
@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
|
||||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&udc->gadget.dev, "gadget");
|
||||
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_destroy_dma;
|
||||
|
||||
eps_init(udc);
|
||||
|
||||
/* VBUS detect: we can disable/enable clock on demand.*/
|
||||
|
|
@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
if (!udc->qwork) {
|
||||
dev_err(&pdev->dev, "cannot create workqueue\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_unregister;
|
||||
goto err_destroy_dma;
|
||||
}
|
||||
|
||||
INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
|
||||
|
|
@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
else
|
||||
udc->vbus_active = 1;
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto err_create_workqueue;
|
||||
|
||||
|
|
@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
|
||||
err_create_workqueue:
|
||||
destroy_workqueue(udc->qwork);
|
||||
err_unregister:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err_destroy_dma:
|
||||
dma_pool_destroy(udc->dtd_pool);
|
||||
err_free_dma:
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
struct eth_dev *the_dev;
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c)
|
|||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return ncm_bind_config(c, hostaddr);
|
||||
return ncm_bind_config(c, hostaddr, the_dev);
|
||||
}
|
||||
|
||||
static struct usb_configuration ncm_config_driver = {
|
||||
|
|
@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
|
|||
int status;
|
||||
|
||||
/* set up network link layer */
|
||||
status = gether_setup(cdev->gadget, hostaddr);
|
||||
if (status < 0)
|
||||
return status;
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev))
|
||||
return PTR_ERR(the_dev);
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
|
|
@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit gncm_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ static const char * const ep_name[] = {
|
|||
"ep-a", "ep-b", "ep-c",
|
||||
};
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
#ifdef CONFIG_USB_NET2272_DMA
|
||||
/*
|
||||
* use_dma: the NET2272 can use an external DMA controller.
|
||||
|
|
@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
|
||||
return &req->req;
|
||||
|
|
@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (likely(req != 0))
|
||||
if (likely(req))
|
||||
list_add_tail(&req->queue, &ep->queue);
|
||||
|
||||
if (likely(!list_empty(&ep->queue)))
|
||||
|
|
@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget,
|
|||
dev->softconnect = 1;
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
/* ... then enable host detection and ep0; and we're ready
|
||||
* for set_configuration as well as eventual disconnect.
|
||||
|
|
@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget,
|
|||
stop_activity(dev, driver);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
|
||||
dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
|
||||
|
|
@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep)
|
|||
| (ep->dev->dma_eot_polarity << EOT_POLARITY)
|
||||
| (ep->dev->dma_dack_polarity << DACK_POLARITY)
|
||||
| (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
|
||||
| ((ep->dma >> 1) << DMA_ENDPOINT_SELECT));
|
||||
| (ep->dma << DMA_ENDPOINT_SELECT));
|
||||
|
||||
ep->dev->dma_busy = 0;
|
||||
|
||||
|
|
@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep)
|
|||
ep->irqs++;
|
||||
|
||||
dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
|
||||
ep->ep.name, stat0, stat1, req ? &req->req : 0);
|
||||
ep->ep.name, stat0, stat1, req ? &req->req : NULL);
|
||||
|
||||
net2272_ep_write(ep, EP_STAT0, stat0 &
|
||||
~((1 << NAK_OUT_PACKETS)
|
||||
|
|
@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev)
|
|||
free_irq(dev->irq, dev);
|
||||
iounmap(dev->base_addr);
|
||||
|
||||
device_unregister(&dev->gadget.dev);
|
||||
device_remove_file(dev->dev, &dev_attr_registers);
|
||||
|
||||
dev_info(dev->dev, "unbind\n");
|
||||
|
|
@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
|
|||
ret->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&ret->gadget.dev, "gadget");
|
||||
ret->gadget.dev.parent = dev;
|
||||
ret->gadget.dev.dma_mask = dev->dma_mask;
|
||||
ret->gadget.dev.release = net2272_gadget_release;
|
||||
ret->gadget.name = driver_name;
|
||||
|
||||
return ret;
|
||||
|
|
@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
|
|||
dma_mode_string());
|
||||
dev_info(dev->dev, "version: %s\n", driver_vers);
|
||||
|
||||
ret = device_register(&dev->gadget.dev);
|
||||
if (ret)
|
||||
goto err_irq;
|
||||
ret = device_create_file(dev->dev, &dev_attr_registers);
|
||||
if (ret)
|
||||
goto err_dev_reg;
|
||||
goto err_irq;
|
||||
|
||||
ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
|
||||
ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget,
|
||||
net2272_gadget_release);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
|
|
@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
|
|||
|
||||
err_add_udc:
|
||||
device_remove_file(dev->dev, &dev_attr_registers);
|
||||
err_dev_reg:
|
||||
device_unregister(&dev->gadget.dev);
|
||||
err_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
err:
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@
|
|||
#define DRIVER_DESC "PLX NET228x USB Peripheral Controller"
|
||||
#define DRIVER_VERSION "2005 Sept 27"
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
#define EP_DONTUSE 13 /* nonzero */
|
||||
|
||||
#define USE_RDK_LEDS /* GPIO pins control three LEDs */
|
||||
|
|
@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
|
||||
/* this dma descriptor may be swapped with the previous dummy */
|
||||
|
|
@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
|
|||
return NULL;
|
||||
}
|
||||
td->dmacount = 0; /* not VALID */
|
||||
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmadesc = td->dmaaddr;
|
||||
req->td = td;
|
||||
}
|
||||
|
|
@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget,
|
|||
dev->softconnect = 1;
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
|
||||
if (retval) goto err_unbind;
|
||||
|
|
@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,
|
|||
err_func:
|
||||
device_remove_file (&dev->pdev->dev, &dev_attr_function);
|
||||
err_unbind:
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget,
|
|||
stop_activity (dev, driver);
|
||||
spin_unlock_irqrestore (&dev->lock, flags);
|
||||
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
|
||||
net2280_led_active (dev, 0);
|
||||
|
|
@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep)
|
|||
return;
|
||||
|
||||
/* manual DMA queue advance after short OUT */
|
||||
if (likely (ep->dma != 0)) {
|
||||
if (likely (ep->dma)) {
|
||||
if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
|
||||
u32 count;
|
||||
int stopped = ep->stopped;
|
||||
|
|
@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
/* hw handles device and interface status */
|
||||
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
|
||||
goto delegate;
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == 0
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == NULL
|
||||
|| w_length > 2)
|
||||
goto do_stall;
|
||||
|
||||
|
|
@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
if (w_value != USB_ENDPOINT_HALT
|
||||
|| w_length != 0)
|
||||
goto do_stall;
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == 0)
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == NULL)
|
||||
goto do_stall;
|
||||
if (e->wedged) {
|
||||
VDEBUG(dev, "%s wedged, halt not cleared\n",
|
||||
|
|
@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
if (w_value != USB_ENDPOINT_HALT
|
||||
|| w_length != 0)
|
||||
goto do_stall;
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == 0)
|
||||
if ((e = get_ep_by_addr (dev, w_index)) == NULL)
|
||||
goto do_stall;
|
||||
if (e->ep.name == ep0name)
|
||||
goto do_stall;
|
||||
|
|
@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev)
|
|||
pci_resource_len (pdev, 0));
|
||||
if (dev->enabled)
|
||||
pci_disable_device (pdev);
|
||||
device_unregister (&dev->gadget.dev);
|
||||
device_remove_file (&pdev->dev, &dev_attr_registers);
|
||||
pci_set_drvdata (pdev, NULL);
|
||||
|
||||
|
|
@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
dev->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
/* the "gadget" abstracts/virtualizes the controller */
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.dev.parent = &pdev->dev;
|
||||
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
dev->gadget.dev.release = gadget_release;
|
||||
dev->gadget.name = driver_name;
|
||||
|
||||
/* now all the pci goodies ... */
|
||||
|
|
@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto done;
|
||||
}
|
||||
td->dmacount = 0; /* not VALID */
|
||||
td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
|
||||
td->dmadesc = td->dmaaddr;
|
||||
dev->ep [i].dummy = td;
|
||||
}
|
||||
|
|
@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
use_dma
|
||||
? (use_dma_chaining ? "chaining" : "enabled")
|
||||
: "disabled");
|
||||
retval = device_register (&dev->gadget.dev);
|
||||
if (retval) goto done;
|
||||
retval = device_create_file (&pdev->dev, &dev_attr_registers);
|
||||
if (retval) goto done;
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto done;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@
|
|||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
#define USB_FACM_INCLUDED
|
||||
#include "f_acm.c"
|
||||
#define USBF_OBEX_INCLUDED
|
||||
#include "f_ecm.c"
|
||||
#include "f_obex.c"
|
||||
#include "f_serial.c"
|
||||
#include "f_phonet.c"
|
||||
#include "u_ether.c"
|
||||
|
||||
|
|
@ -98,45 +96,19 @@ MODULE_AUTHOR("Felipe Balbi");
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct usb_function *f_acm_cfg1;
|
||||
static struct usb_function *f_acm_cfg2;
|
||||
static u8 hostaddr[ETH_ALEN];
|
||||
static struct eth_dev *the_dev;
|
||||
|
||||
enum {
|
||||
TTY_PORT_OBEX0,
|
||||
TTY_PORT_OBEX1,
|
||||
TTY_PORT_ACM,
|
||||
TTY_PORTS_MAX,
|
||||
};
|
||||
|
||||
static unsigned char tty_lines[TTY_PORTS_MAX];
|
||||
|
||||
static int __init nokia_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = phonet_bind_config(c);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind phonet config\n");
|
||||
|
||||
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX0]);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
||||
|
||||
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX1]);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
||||
|
||||
status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind acm config\n");
|
||||
|
||||
status = ecm_bind_config(c, hostaddr);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind ecm config\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration nokia_config_500ma_driver = {
|
||||
.label = "Bus Powered",
|
||||
.bConfigurationValue = 1,
|
||||
|
|
@ -153,6 +125,51 @@ static struct usb_configuration nokia_config_100ma_driver = {
|
|||
.MaxPower = 100,
|
||||
};
|
||||
|
||||
static struct usb_function_instance *fi_acm;
|
||||
|
||||
static int __init nokia_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct usb_function *f_acm;
|
||||
int status = 0;
|
||||
|
||||
status = phonet_bind_config(c);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind phonet config\n");
|
||||
|
||||
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX0]);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
||||
|
||||
status = obex_bind_config(c, tty_lines[TTY_PORT_OBEX1]);
|
||||
if (status)
|
||||
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
|
||||
|
||||
f_acm = usb_get_function(fi_acm);
|
||||
if (IS_ERR(f_acm))
|
||||
return PTR_ERR(f_acm);
|
||||
|
||||
status = usb_add_function(c, f_acm);
|
||||
if (status)
|
||||
goto err_conf;
|
||||
|
||||
status = ecm_bind_config(c, hostaddr, the_dev);
|
||||
if (status) {
|
||||
pr_debug("could not bind ecm config %d\n", status);
|
||||
goto err_ecm;
|
||||
}
|
||||
if (c == &nokia_config_500ma_driver)
|
||||
f_acm_cfg1 = f_acm;
|
||||
else
|
||||
f_acm_cfg2 = f_acm;
|
||||
|
||||
return status;
|
||||
err_ecm:
|
||||
usb_remove_function(c, f_acm);
|
||||
err_conf:
|
||||
usb_put_function(f_acm);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __init nokia_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
|
|
@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
|
|||
goto err_ether;
|
||||
}
|
||||
|
||||
status = gether_setup(cdev->gadget, hostaddr);
|
||||
if (status < 0)
|
||||
the_dev = gether_setup(cdev->gadget, hostaddr);
|
||||
if (IS_ERR(the_dev)) {
|
||||
status = PTR_ERR(the_dev);
|
||||
goto err_ether;
|
||||
}
|
||||
|
||||
status = usb_string_ids_tab(cdev, strings_dev);
|
||||
if (status < 0)
|
||||
|
|
@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
|
|||
if (!gadget_supports_altsettings(gadget))
|
||||
goto err_usb;
|
||||
|
||||
fi_acm = usb_get_function_instance("acm");
|
||||
if (IS_ERR(fi_acm))
|
||||
goto err_usb;
|
||||
|
||||
/* finally register the configuration */
|
||||
status = usb_add_config(cdev, &nokia_config_500ma_driver,
|
||||
nokia_bind_config);
|
||||
if (status < 0)
|
||||
goto err_usb;
|
||||
goto err_acm_inst;
|
||||
|
||||
status = usb_add_config(cdev, &nokia_config_100ma_driver,
|
||||
nokia_bind_config);
|
||||
if (status < 0)
|
||||
goto err_usb;
|
||||
goto err_put_cfg1;
|
||||
|
||||
usb_composite_overwrite_options(cdev, &coverwrite);
|
||||
dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_cfg1:
|
||||
usb_put_function(f_acm_cfg1);
|
||||
err_acm_inst:
|
||||
usb_put_function_instance(fi_acm);
|
||||
err_usb:
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
err_ether:
|
||||
cur_line--;
|
||||
while (cur_line >= 0)
|
||||
|
|
@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
|
|||
{
|
||||
int i;
|
||||
|
||||
usb_put_function(f_acm_cfg1);
|
||||
usb_put_function(f_acm_cfg2);
|
||||
usb_put_function_instance(fi_acm);
|
||||
gphonet_cleanup();
|
||||
|
||||
for (i = 0; i < TTY_PORTS_MAX; i++)
|
||||
gserial_free_line(tty_lines[i]);
|
||||
|
||||
gether_cleanup();
|
||||
gether_cleanup(the_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void)
|
|||
usb_composite_unregister(&nokia_driver);
|
||||
}
|
||||
module_exit(nokia_cleanup);
|
||||
|
||||
|
|
|
|||
|
|
@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g,
|
|||
/* hook up the driver */
|
||||
driver->driver.bus = NULL;
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
if (udc->dc_clk != NULL)
|
||||
|
|
@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g,
|
|||
ERR("can't bind to transceiver\n");
|
||||
if (driver->unbind) {
|
||||
driver->unbind(&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
}
|
||||
goto done;
|
||||
|
|
@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g,
|
|||
udc_quiesce(udc);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
|
||||
if (udc->dc_clk != NULL)
|
||||
|
|
@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
|
|||
udc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
udc->gadget.max_speed = USB_SPEED_FULL;
|
||||
udc->gadget.name = driver_name;
|
||||
|
||||
device_initialize(&udc->gadget.dev);
|
||||
dev_set_name(&udc->gadget.dev, "gadget");
|
||||
udc->gadget.dev.release = omap_udc_release;
|
||||
udc->gadget.dev.parent = &odev->dev;
|
||||
if (use_dma)
|
||||
udc->gadget.dev.dma_mask = odev->dev.dma_mask;
|
||||
|
||||
udc->transceiver = xceiv;
|
||||
|
||||
/* ep0 is special; put it right after the SETUP buffer */
|
||||
|
|
@ -2912,14 +2901,13 @@ bad_on_1710:
|
|||
}
|
||||
|
||||
create_proc_file();
|
||||
status = device_add(&udc->gadget.dev);
|
||||
status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
|
||||
omap_udc_release);
|
||||
if (status)
|
||||
goto cleanup4;
|
||||
|
||||
status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (!status)
|
||||
return status;
|
||||
/* If fail, fall through */
|
||||
return 0;
|
||||
|
||||
cleanup4:
|
||||
remove_proc_file();
|
||||
|
||||
|
|
@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev)
|
|||
release_mem_region(pdev->resource[0].start,
|
||||
pdev->resource[0].end - pdev->resource[0].start + 1);
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
wait_for_completion(&done);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -358,7 +358,6 @@ struct pch_udc_dev {
|
|||
prot_stall:1,
|
||||
irq_registered:1,
|
||||
mem_region:1,
|
||||
registered:1,
|
||||
suspended:1,
|
||||
connected:1,
|
||||
vbus_session:1,
|
||||
|
|
@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
|
|||
*/
|
||||
static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
|
||||
int status)
|
||||
__releases(&dev->lock)
|
||||
__acquires(&dev->lock)
|
||||
{
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned halted = ep->halted;
|
||||
|
|
@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
|
|||
* @dev: Reference to the device structure
|
||||
*/
|
||||
static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
|
||||
__releases(&dev->lock)
|
||||
__acquires(&dev->lock)
|
||||
{
|
||||
u32 stat;
|
||||
int setup_supported;
|
||||
|
|
@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g,
|
|||
|
||||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
/* get ready for ep0 traffic */
|
||||
pch_udc_setup_ep0(dev);
|
||||
|
|
@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g,
|
|||
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
|
||||
|
||||
/* Assures that there are no pending requests with this driver */
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
dev->connected = 0;
|
||||
|
||||
|
|
@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev)
|
|||
pci_resource_len(pdev, PCH_UDC_PCI_BAR));
|
||||
if (dev->active)
|
||||
pci_disable_device(pdev);
|
||||
if (dev->registered)
|
||||
device_unregister(&dev->gadget.dev);
|
||||
kfree(dev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
|
@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev,
|
|||
if (retval)
|
||||
goto finished;
|
||||
|
||||
dev_set_name(&dev->gadget.dev, "gadget");
|
||||
dev->gadget.dev.parent = &pdev->dev;
|
||||
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
dev->gadget.dev.release = gadget_release;
|
||||
dev->gadget.name = KBUILD_MODNAME;
|
||||
dev->gadget.max_speed = USB_SPEED_HIGH;
|
||||
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval)
|
||||
goto finished;
|
||||
dev->registered = 1;
|
||||
|
||||
/* Put the device in disconnected state till a driver is bound */
|
||||
pch_udc_set_disconnect(dev);
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
if (retval)
|
||||
goto finished;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
|
|||
|
||||
/* first hook up the driver ... */
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
dev->pullup = 1;
|
||||
|
||||
/* ... then enable host detection and ep0; and we're ready
|
||||
|
|
@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g,
|
|||
if (!IS_ERR_OR_NULL(dev->transceiver))
|
||||
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
|
||||
|
||||
dev->gadget.dev.driver = NULL;
|
||||
dev->driver = NULL;
|
||||
|
||||
dump_state(dev);
|
||||
|
|
@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
|
|||
dev->timer.function = udc_watchdog;
|
||||
dev->timer.data = (unsigned long) dev;
|
||||
|
||||
device_initialize(&dev->gadget.dev);
|
||||
dev->gadget.dev.parent = &pdev->dev;
|
||||
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
|
||||
retval = device_add(&dev->gadget.dev);
|
||||
if (retval) {
|
||||
dev->driver = NULL;
|
||||
dev->gadget.dev.driver = NULL;
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
the_controller = dev;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
|
|
@ -2199,8 +2186,6 @@ lubbock_fail0:
|
|||
free_irq(irq, dev);
|
||||
#endif
|
||||
err_irq1:
|
||||
device_unregister(&dev->gadget.dev);
|
||||
err_device_add:
|
||||
if (gpio_is_valid(dev->mach->gpio_pullup))
|
||||
gpio_free(dev->mach->gpio_pullup);
|
||||
err_gpio_pullup:
|
||||
|
|
@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
|
|||
return -EBUSY;
|
||||
|
||||
usb_del_gadget_udc(&dev->gadget);
|
||||
device_unregister(&dev->gadget.dev);
|
||||
dev->pullup = 0;
|
||||
pullup(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,14 +24,12 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/prefetch.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
#include <linux/platform_data/pxa2xx_udc.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <mach/udc.h>
|
||||
|
||||
#include "pxa27x_udc.h"
|
||||
|
||||
|
|
@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
|
|||
*
|
||||
* Find the physical pxa27x ep, and setup its UDCCR
|
||||
*/
|
||||
static __init void pxa_ep_setup(struct pxa_ep *ep)
|
||||
static void pxa_ep_setup(struct pxa_ep *ep)
|
||||
{
|
||||
u32 new_udccr;
|
||||
|
||||
|
|
@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep)
|
|||
*
|
||||
* Setup all pxa physical endpoints, except ep0
|
||||
*/
|
||||
static __init void pxa_eps_setup(struct pxa_udc *dev)
|
||||
static void pxa_eps_setup(struct pxa_udc *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
|
@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc)
|
|||
* Initializes gadget endpoint list, endpoints locks. No action is taken
|
||||
* on the hardware.
|
||||
*/
|
||||
static __init void udc_init_data(struct pxa_udc *dev)
|
||||
static void udc_init_data(struct pxa_udc *dev)
|
||||
{
|
||||
int i;
|
||||
struct pxa_ep *ep;
|
||||
|
|
@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
|
|||
|
||||
/* first hook up the driver ... */
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
dplus_pullup(udc, 1);
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
|
|
@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
|
|||
|
||||
fail:
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g,
|
|||
|
||||
udc->driver = NULL;
|
||||
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return otg_set_peripheral(udc->transceiver->otg, NULL);
|
||||
return 0;
|
||||
|
|
@ -2413,7 +2408,7 @@ static struct pxa_udc memory = {
|
|||
* Perform basic init : allocates udc clock, creates sysfs files, requests
|
||||
* irq.
|
||||
*/
|
||||
static int __init pxa_udc_probe(struct platform_device *pdev)
|
||||
static int pxa_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs;
|
||||
struct pxa_udc *udc = &memory;
|
||||
|
|
@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
goto err_map;
|
||||
}
|
||||
|
||||
device_initialize(&udc->gadget.dev);
|
||||
udc->gadget.dev.parent = &pdev->dev;
|
||||
udc->gadget.dev.dma_mask = NULL;
|
||||
udc->vbus_sensed = 0;
|
||||
|
||||
the_controller = udc;
|
||||
|
|
@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
goto err_irq;
|
||||
}
|
||||
|
||||
retval = device_add(&udc->gadget.dev);
|
||||
if (retval) {
|
||||
dev_err(udc->dev, "device_add error %d\n", retval);
|
||||
goto err_dev_add;
|
||||
}
|
||||
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (retval)
|
||||
goto err_add_udc;
|
||||
|
|
@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err_dev_add:
|
||||
free_irq(udc->irq, udc);
|
||||
err_irq:
|
||||
iounmap(udc->regs);
|
||||
|
|
@ -2506,13 +2490,12 @@ err_clk:
|
|||
* pxa_udc_remove - removes the udc device driver
|
||||
* @_dev: platform device
|
||||
*/
|
||||
static int __exit pxa_udc_remove(struct platform_device *_dev)
|
||||
static int pxa_udc_remove(struct platform_device *_dev)
|
||||
{
|
||||
struct pxa_udc *udc = platform_get_drvdata(_dev);
|
||||
int gpio = udc->mach->gpio_pullup;
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
device_del(&udc->gadget.dev);
|
||||
usb_gadget_unregister_driver(udc->driver);
|
||||
free_irq(udc->irq, udc);
|
||||
pxa_cleanup_debugfs(udc);
|
||||
|
|
@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = {
|
|||
.name = "pxa27x-udc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __exit_p(pxa_udc_remove),
|
||||
.probe = pxa_udc_probe,
|
||||
.remove = pxa_udc_remove,
|
||||
.shutdown = pxa_udc_shutdown,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = pxa_udc_suspend,
|
||||
|
|
@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
{
|
||||
if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
|
||||
return platform_driver_probe(&udc_driver, pxa_udc_probe);
|
||||
}
|
||||
module_init(udc_init);
|
||||
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
}
|
||||
module_exit(udc_exit);
|
||||
module_platform_driver(udc_driver);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("Robert Jarzmik");
|
||||
|
|
|
|||
|
|
@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
|
|||
clk_put(r8a66597->clk);
|
||||
}
|
||||
|
||||
device_unregister(&r8a66597->gadget.dev);
|
||||
kfree(r8a66597);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
|||
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
|
||||
|
||||
r8a66597->gadget.ops = &r8a66597_gadget_ops;
|
||||
dev_set_name(&r8a66597->gadget.dev, "gadget");
|
||||
r8a66597->gadget.max_speed = USB_SPEED_HIGH;
|
||||
r8a66597->gadget.dev.parent = &pdev->dev;
|
||||
r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
r8a66597->gadget.dev.release = pdev->dev.release;
|
||||
r8a66597->gadget.name = udc_name;
|
||||
ret = device_register(&r8a66597->gadget.dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "device_register failed\n");
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
init_timer(&r8a66597->timer);
|
||||
r8a66597->timer.function = r8a66597_timer;
|
||||
|
|
@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
|
||||
clk_name);
|
||||
ret = PTR_ERR(r8a66597->clk);
|
||||
goto clean_up_dev;
|
||||
goto clean_up;
|
||||
}
|
||||
clk_enable(r8a66597->clk);
|
||||
}
|
||||
|
|
@ -2007,8 +1997,6 @@ clean_up2:
|
|||
clk_disable(r8a66597->clk);
|
||||
clk_put(r8a66597->clk);
|
||||
}
|
||||
clean_up_dev:
|
||||
device_unregister(&r8a66597->gadget.dev);
|
||||
clean_up:
|
||||
if (r8a66597) {
|
||||
if (r8a66597->sudmac_reg)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@
|
|||
|
||||
#include "s3c-hsotg.h"
|
||||
|
||||
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
|
||||
|
||||
static const char * const s3c_hsotg_supply_names[] = {
|
||||
"vusb_d", /* digital USB supply, 1.2V */
|
||||
"vusb_a", /* analog USB supply, 1.1V */
|
||||
|
|
@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
|
|||
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
return &req->req;
|
||||
}
|
||||
|
||||
|
|
@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
|
|||
struct s3c_hsotg_req *hs_req)
|
||||
{
|
||||
struct usb_request *req = &hs_req->req;
|
||||
enum dma_data_direction dir;
|
||||
|
||||
dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
|
||||
/* ignore this if we're not moving any data */
|
||||
if (hs_req->req.length == 0)
|
||||
return;
|
||||
|
||||
if (hs_req->mapped) {
|
||||
/* we mapped this, so unmap and remove the dma */
|
||||
|
||||
dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
|
||||
|
||||
req->dma = DMA_ADDR_INVALID;
|
||||
hs_req->mapped = 0;
|
||||
} else {
|
||||
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
|
||||
}
|
||||
usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
|
|||
struct s3c_hsotg_ep *hs_ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
struct s3c_hsotg_req *hs_req = our_req(req);
|
||||
|
||||
dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
int ret;
|
||||
|
||||
/* if the length is zero, ignore the DMA data */
|
||||
if (hs_req->req.length == 0)
|
||||
return 0;
|
||||
|
||||
if (req->dma == DMA_ADDR_INVALID) {
|
||||
dma_addr_t dma;
|
||||
|
||||
dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
|
||||
|
||||
if (unlikely(dma_mapping_error(hsotg->dev, dma)))
|
||||
goto dma_error;
|
||||
|
||||
if (dma & 3) {
|
||||
dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
|
||||
__func__);
|
||||
|
||||
dma_unmap_single(hsotg->dev, dma, req->length, dir);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hs_req->mapped = 1;
|
||||
req->dma = dma;
|
||||
} else {
|
||||
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
|
||||
hs_req->mapped = 0;
|
||||
}
|
||||
ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
|
||||
if (ret)
|
||||
goto dma_error;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
|
|||
|
||||
driver->driver.bus = NULL;
|
||||
hsotg->driver = driver;
|
||||
hsotg->gadget.dev.driver = &driver->driver;
|
||||
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
|
||||
hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
|
||||
|
|
@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
|
|||
|
||||
err:
|
||||
hsotg->driver = NULL;
|
||||
hsotg->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
|
|||
|
||||
hsotg->driver = NULL;
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
hsotg->gadget.dev.driver = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
|
|
@ -3483,16 +3443,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
|
|||
debugfs_remove(hsotg->debug_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_release - release callback for hsotg device
|
||||
* @dev: Device to for which release is called
|
||||
*
|
||||
* Nothing to do as the resource is allocated using devm_ API.
|
||||
*/
|
||||
static void s3c_hsotg_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_probe - probe function for hsotg driver
|
||||
* @pdev: The platform information for the driver
|
||||
|
|
@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(phy)) {
|
||||
if (IS_ERR(phy)) {
|
||||
/* Fallback for pdata */
|
||||
plat = pdev->dev.platform_data;
|
||||
if (!plat) {
|
||||
|
|
@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
|
|||
|
||||
dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
|
||||
|
||||
device_initialize(&hsotg->gadget.dev);
|
||||
|
||||
dev_set_name(&hsotg->gadget.dev, "gadget");
|
||||
|
||||
hsotg->gadget.max_speed = USB_SPEED_HIGH;
|
||||
hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
|
||||
hsotg->gadget.name = dev_name(dev);
|
||||
|
||||
hsotg->gadget.dev.parent = dev;
|
||||
hsotg->gadget.dev.dma_mask = dev->dma_mask;
|
||||
hsotg->gadget.dev.release = s3c_hsotg_release;
|
||||
|
||||
/* reset the system */
|
||||
|
||||
clk_prepare_enable(hsotg->clk);
|
||||
|
|
@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
|
|||
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
|
||||
ret = device_add(&hsotg->gadget.dev);
|
||||
if (ret) {
|
||||
put_device(&hsotg->gadget.dev);
|
||||
goto err_ep_mem;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
|
||||
if (ret)
|
||||
goto err_ep_mem;
|
||||
|
|
@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
|
||||
device_unregister(&hsotg->gadget.dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
|
|||
/**
|
||||
* s3c_hsudc_stop_activity - Stop activity on all endpoints.
|
||||
* @hsudc: Device controller for which EP activity is to be stopped.
|
||||
* @driver: Reference to the gadget driver which is currently active.
|
||||
*
|
||||
* All the endpoints are stopped and any pending transfer requests if any on
|
||||
* the endpoint are terminated.
|
||||
|
|
@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
|
|||
return -EBUSY;
|
||||
|
||||
hsudc->driver = driver;
|
||||
hsudc->gadget.dev.driver = &driver->driver;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
|
||||
hsudc->supplies);
|
||||
|
|
@ -1190,7 +1188,6 @@ err_otg:
|
|||
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
|
||||
err_supplies:
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
|
|||
|
||||
spin_lock_irqsave(&hsudc->lock, flags);
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
s3c_hsudc_uninit_phy();
|
||||
|
||||
|
|
@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
|
||||
spin_lock_init(&hsudc->lock);
|
||||
|
||||
dev_set_name(&hsudc->gadget.dev, "gadget");
|
||||
|
||||
hsudc->gadget.max_speed = USB_SPEED_HIGH;
|
||||
hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
|
||||
hsudc->gadget.name = dev_name(dev);
|
||||
hsudc->gadget.dev.parent = dev;
|
||||
hsudc->gadget.dev.dma_mask = dev->dma_mask;
|
||||
hsudc->gadget.ep0 = &hsudc->ep[0].ep;
|
||||
|
||||
hsudc->gadget.is_otg = 0;
|
||||
hsudc->gadget.is_a_peripheral = 0;
|
||||
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
|
|
@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
disable_irq(hsudc->irq);
|
||||
local_irq_enable();
|
||||
|
||||
ret = device_register(&hsudc->gadget.dev);
|
||||
if (ret) {
|
||||
put_device(&hsudc->gadget.dev);
|
||||
goto err_add_device;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
|
@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
err_add_udc:
|
||||
device_unregister(&hsudc->gadget.dev);
|
||||
err_add_device:
|
||||
clk_disable(hsudc->uclk);
|
||||
err_res:
|
||||
|
|
|
|||
|
|
@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g,
|
|||
|
||||
/* Hook the driver */
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
|
||||
/* Enable udc */
|
||||
s3c2410_udc_enable(udc);
|
||||
|
|
@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
|||
goto err_mem;
|
||||
}
|
||||
|
||||
device_initialize(&udc->gadget.dev);
|
||||
udc->gadget.dev.parent = &pdev->dev;
|
||||
udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
|
||||
|
||||
/* Bind the driver */
|
||||
retval = device_add(&udc->gadget.dev);
|
||||
if (retval) {
|
||||
dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
|
||||
goto err_device_add;
|
||||
}
|
||||
|
||||
the_controller = udc;
|
||||
platform_set_drvdata(pdev, udc);
|
||||
|
||||
|
|
@ -1923,8 +1911,6 @@ err_gpio_claim:
|
|||
err_int:
|
||||
free_irq(IRQ_USBD, udc);
|
||||
err_map:
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err_device_add:
|
||||
iounmap(base_addr);
|
||||
err_mem:
|
||||
release_mem_region(rsrc_start, rsrc_len);
|
||||
|
|
@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
|
|||
return -EBUSY;
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
debugfs_remove(udc->regs_info);
|
||||
|
||||
if (udc_info && !udc_info->udc_command &&
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
|
|
@ -27,18 +28,6 @@
|
|||
#define GS_LONG_NAME "Gadget Serial"
|
||||
#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
#include "f_obex.c"
|
||||
#include "f_serial.c"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
USB_GADGET_COMPOSITE_OPTIONS();
|
||||
|
||||
|
|
@ -126,27 +115,6 @@ module_param(n_ports, uint, 0);
|
|||
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
|
||||
|
||||
static int __init serial_bind_obex_config(struct usb_configuration *c)
|
||||
{
|
||||
unsigned i;
|
||||
int status = 0;
|
||||
|
||||
for (i = 0; i < n_ports && status == 0; i++)
|
||||
status = obex_bind_config(c, tty_lines[i]);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __init serial_bind_gser_config(struct usb_configuration *c)
|
||||
{
|
||||
unsigned i;
|
||||
int status = 0;
|
||||
|
||||
for (i = 0; i < n_ports && status == 0; i++)
|
||||
status = gser_bind_config(c, tty_lines[i]);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration serial_config_driver = {
|
||||
/* .label = f(use_acm) */
|
||||
|
|
@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
|
|||
goto out;
|
||||
|
||||
for (i = 0; i < n_ports; i++) {
|
||||
struct f_serial_opts *opts;
|
||||
|
||||
fi_serial[i] = usb_get_function_instance(f_name);
|
||||
if (IS_ERR(fi_serial[i])) {
|
||||
ret = PTR_ERR(fi_serial[i]);
|
||||
goto fail;
|
||||
}
|
||||
opts = container_of(fi_serial[i], struct f_serial_opts, func_inst);
|
||||
opts->port_num = tty_lines[i];
|
||||
|
||||
f_serial[i] = usb_get_function(fi_serial[i]);
|
||||
if (IS_ERR(f_serial[i])) {
|
||||
|
|
@ -212,13 +177,6 @@ out:
|
|||
static int __init gs_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int status;
|
||||
int cur_line;
|
||||
|
||||
for (cur_line = 0; cur_line < n_ports; cur_line++) {
|
||||
status = gserial_alloc_line(&tty_lines[cur_line]);
|
||||
if (status)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
|
|
@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
|
|||
"acm");
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
} else if (use_obex)
|
||||
status = usb_add_config(cdev, &serial_config_driver,
|
||||
serial_bind_obex_config);
|
||||
else
|
||||
status = usb_add_config(cdev, &serial_config_driver,
|
||||
serial_bind_gser_config);
|
||||
status = serial_register_ports(cdev, &serial_config_driver,
|
||||
"obex");
|
||||
else {
|
||||
status = serial_register_ports(cdev, &serial_config_driver,
|
||||
"gser");
|
||||
}
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
cur_line--;
|
||||
while (cur_line >= 0)
|
||||
gserial_free_line(tty_lines[cur_line--]);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev)
|
|||
for (i = 0; i < n_ports; i++) {
|
||||
usb_put_function(f_serial[i]);
|
||||
usb_put_function_instance(fi_serial[i]);
|
||||
gserial_free_line(tty_lines[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
struct eth_dev {
|
||||
/* lock is held while accessing port_usb
|
||||
* or updating its backlink port_usb->ioport
|
||||
*/
|
||||
spinlock_t lock;
|
||||
struct gether *port_usb;
|
||||
|
|
@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static struct eth_dev *the_dev;
|
||||
|
||||
static const struct net_device_ops eth_netdev_ops = {
|
||||
.ndo_open = eth_open,
|
||||
.ndo_stop = eth_stop,
|
||||
|
|
@ -758,19 +755,16 @@ static struct device_type gadget_type = {
|
|||
*
|
||||
* Returns negative errno, or zero on success
|
||||
*/
|
||||
int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
const char *netname)
|
||||
{
|
||||
struct eth_dev *dev;
|
||||
struct net_device *net;
|
||||
int status;
|
||||
|
||||
if (the_dev)
|
||||
return -EBUSY;
|
||||
|
||||
net = alloc_etherdev(sizeof *dev);
|
||||
if (!net)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dev = netdev_priv(net);
|
||||
spin_lock_init(&dev->lock);
|
||||
|
|
@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
|||
if (status < 0) {
|
||||
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
|
||||
free_netdev(net);
|
||||
dev = ERR_PTR(status);
|
||||
} else {
|
||||
INFO(dev, "MAC %pM\n", net->dev_addr);
|
||||
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
|
||||
|
||||
the_dev = dev;
|
||||
|
||||
/* two kinds of host-initiated state changes:
|
||||
* - iff DATA transfer is active, carrier is "on"
|
||||
* - tx queueing enabled if open *and* carrier is "on"
|
||||
|
|
@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
|||
netif_carrier_off(net);
|
||||
}
|
||||
|
||||
return status;
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
|||
*
|
||||
* This is called to free all resources allocated by @gether_setup().
|
||||
*/
|
||||
void gether_cleanup(void)
|
||||
void gether_cleanup(struct eth_dev *dev)
|
||||
{
|
||||
if (!the_dev)
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
unregister_netdev(the_dev->net);
|
||||
flush_work(&the_dev->work);
|
||||
free_netdev(the_dev->net);
|
||||
|
||||
the_dev = NULL;
|
||||
unregister_netdev(dev->net);
|
||||
flush_work(&dev->work);
|
||||
free_netdev(dev->net);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gether_connect - notify network layer that USB link is active
|
||||
* @link: the USB link, set up with endpoints, descriptors matching
|
||||
|
|
@ -860,7 +850,7 @@ void gether_cleanup(void)
|
|||
*/
|
||||
struct net_device *gether_connect(struct gether *link)
|
||||
{
|
||||
struct eth_dev *dev = the_dev;
|
||||
struct eth_dev *dev = link->ioport;
|
||||
int result = 0;
|
||||
|
||||
if (!dev)
|
||||
|
|
@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link)
|
|||
|
||||
spin_lock(&dev->lock);
|
||||
dev->port_usb = link;
|
||||
link->ioport = dev;
|
||||
if (netif_running(dev->net)) {
|
||||
if (link->open)
|
||||
link->open(link);
|
||||
|
|
@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link)
|
|||
|
||||
spin_lock(&dev->lock);
|
||||
dev->port_usb = NULL;
|
||||
link->ioport = NULL;
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "gadget_chips.h"
|
||||
|
||||
struct eth_dev;
|
||||
|
||||
/*
|
||||
* This represents the USB side of an "ethernet" link, managed by a USB
|
||||
|
|
@ -70,7 +71,7 @@ struct gether {
|
|||
|USB_CDC_PACKET_TYPE_DIRECTED)
|
||||
|
||||
/* variant of gether_setup that allows customizing network device name */
|
||||
int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
const char *netname);
|
||||
|
||||
/* netdev setup/teardown as directed by the gadget driver */
|
||||
|
|
@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
|||
*
|
||||
* Returns negative errno, or zero on success
|
||||
*/
|
||||
static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
|
||||
static inline struct eth_dev *gether_setup(struct usb_gadget *g,
|
||||
u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
return gether_setup_name(g, ethaddr, "usb");
|
||||
}
|
||||
|
||||
void gether_cleanup(void);
|
||||
void gether_cleanup(struct eth_dev *dev);
|
||||
|
||||
/* connect/disconnect is handled by individual functions */
|
||||
struct net_device *gether_connect(struct gether *);
|
||||
|
|
@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
|
|||
}
|
||||
|
||||
/* each configuration may bind one instance of an ethernet link */
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
int eem_bind_config(struct usb_configuration *c);
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
|
||||
|
||||
#ifdef USB_ETH_RNDIS
|
||||
|
||||
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer);
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer)
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
|||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
static inline int rndis_bind_config(struct usb_configuration *c,
|
||||
u8 ethaddr[ETH_ALEN])
|
||||
u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
|
||||
{
|
||||
return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
|
||||
return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num);
|
|||
void gserial_disconnect(struct gserial *);
|
||||
|
||||
/* functions are bound to configurations by a config or gadget driver */
|
||||
int acm_bind_config(struct usb_configuration *c, u8 port_num);
|
||||
int gser_bind_config(struct usb_configuration *c, u8 port_num);
|
||||
int obex_bind_config(struct usb_configuration *c, u8 port_num);
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void usb_gadget_set_state(struct usb_gadget *gadget,
|
||||
enum usb_device_state state)
|
||||
{
|
||||
gadget->state = state;
|
||||
sysfs_notify(&gadget->dev.kobj, NULL, "status");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* usb_gadget_udc_start - tells usb device controller to start up
|
||||
* @gadget: The gadget we want to get started
|
||||
|
|
@ -156,6 +166,87 @@ static void usb_udc_release(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct attribute_group *usb_udc_attr_groups[];
|
||||
|
||||
static void usb_udc_nop_release(struct device *dev)
|
||||
{
|
||||
dev_vdbg(dev, "%s\n", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
|
||||
* @parent: the parent device to this udc. Usually the controller driver's
|
||||
* device.
|
||||
* @gadget: the gadget to be added to the list.
|
||||
* @release: a gadget release function.
|
||||
*
|
||||
* Returns zero on success, negative errno otherwise.
|
||||
*/
|
||||
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
|
||||
void (*release)(struct device *dev))
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
|
||||
if (!udc)
|
||||
goto err1;
|
||||
|
||||
dev_set_name(&gadget->dev, "gadget");
|
||||
gadget->dev.parent = parent;
|
||||
|
||||
dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
|
||||
gadget->dev.dma_parms = parent->dma_parms;
|
||||
gadget->dev.dma_mask = parent->dma_mask;
|
||||
|
||||
if (release)
|
||||
gadget->dev.release = release;
|
||||
else
|
||||
gadget->dev.release = usb_udc_nop_release;
|
||||
|
||||
ret = device_register(&gadget->dev);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
device_initialize(&udc->dev);
|
||||
udc->dev.release = usb_udc_release;
|
||||
udc->dev.class = udc_class;
|
||||
udc->dev.groups = usb_udc_attr_groups;
|
||||
udc->dev.parent = parent;
|
||||
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
udc->gadget = gadget;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
|
||||
ret = device_add(&udc->dev);
|
||||
if (ret)
|
||||
goto err4;
|
||||
|
||||
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
list_del(&udc->list);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
err3:
|
||||
put_device(&udc->dev);
|
||||
|
||||
err2:
|
||||
put_device(&gadget->dev);
|
||||
kfree(udc);
|
||||
|
||||
err1:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
|
||||
|
||||
/**
|
||||
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
|
||||
* @parent: the parent device to this udc. Usually the controller
|
||||
|
|
@ -166,43 +257,7 @@ static const struct attribute_group *usb_udc_attr_groups[];
|
|||
*/
|
||||
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
|
||||
if (!udc)
|
||||
goto err1;
|
||||
|
||||
device_initialize(&udc->dev);
|
||||
udc->dev.release = usb_udc_release;
|
||||
udc->dev.class = udc_class;
|
||||
udc->dev.groups = usb_udc_attr_groups;
|
||||
udc->dev.parent = parent;
|
||||
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
udc->gadget = gadget;
|
||||
|
||||
mutex_lock(&udc_lock);
|
||||
list_add_tail(&udc->list, &udc_list);
|
||||
|
||||
ret = device_add(&udc->dev);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
return 0;
|
||||
err3:
|
||||
list_del(&udc->list);
|
||||
mutex_unlock(&udc_lock);
|
||||
|
||||
err2:
|
||||
put_device(&udc->dev);
|
||||
|
||||
err1:
|
||||
return ret;
|
||||
return usb_add_gadget_udc_release(parent, gadget, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
|
||||
|
||||
|
|
@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
|
|||
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
udc->gadget->dev.driver = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -254,6 +310,7 @@ found:
|
|||
|
||||
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
|
||||
device_unregister(&udc->dev);
|
||||
device_unregister(&gadget->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
|
||||
|
||||
|
|
@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
|
|||
|
||||
udc->driver = driver;
|
||||
udc->dev.driver = &driver->driver;
|
||||
udc->gadget->dev.driver = &driver->driver;
|
||||
|
||||
ret = driver->bind(udc->gadget, driver);
|
||||
if (ret)
|
||||
|
|
@ -286,6 +344,7 @@ err1:
|
|||
udc->driver->function, ret);
|
||||
udc->driver = NULL;
|
||||
udc->dev.driver = NULL;
|
||||
udc->gadget->dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
|
||||
|
||||
static ssize_t usb_gadget_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
|
||||
struct usb_gadget *gadget = udc->gadget;
|
||||
|
||||
return sprintf(buf, "%s\n", usb_state_string(gadget->state));
|
||||
}
|
||||
static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
|
||||
|
||||
#define USB_UDC_SPEED_ATTR(name, param) \
|
||||
ssize_t usb_udc_##param##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
|
|
@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev, \
|
|||
return snprintf(buf, PAGE_SIZE, "%s\n", \
|
||||
usb_speed_string(udc->gadget->param)); \
|
||||
} \
|
||||
static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
|
||||
static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
|
||||
|
||||
static USB_UDC_SPEED_ATTR(current_speed, speed);
|
||||
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
|
||||
|
|
@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support);
|
|||
static struct attribute *usb_udc_attrs[] = {
|
||||
&dev_attr_srp.attr,
|
||||
&dev_attr_soft_connect.attr,
|
||||
&dev_attr_state.attr,
|
||||
&dev_attr_current_speed.attr,
|
||||
&dev_attr_maximum_speed.attr,
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param;
|
|||
#define DRIVER_VERSION "0.1.0"
|
||||
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#define UVC_NUM_REQUESTS 4
|
||||
#define UVC_MAX_REQUEST_SIZE 64
|
||||
#define UVC_MAX_EVENTS 4
|
||||
|
|
@ -190,6 +188,7 @@ struct uvc_file_handle
|
|||
* Functions
|
||||
*/
|
||||
|
||||
extern void uvc_function_setup_continue(struct uvc_device *uvc);
|
||||
extern void uvc_endpoint_stream(struct uvc_device *dev);
|
||||
|
||||
extern void uvc_function_connect(struct uvc_device *uvc);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
|
|
@ -18,7 +19,8 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include <media/videobuf2-vmalloc.h>
|
||||
|
||||
#include "uvc.h"
|
||||
|
||||
|
|
@ -28,330 +30,175 @@
|
|||
* Video queues is initialized by uvc_queue_init(). The function performs
|
||||
* basic initialization of the uvc_video_queue struct and never fails.
|
||||
*
|
||||
* Video buffer allocation and freeing are performed by uvc_alloc_buffers and
|
||||
* uvc_free_buffers respectively. The former acquires the video queue lock,
|
||||
* while the later must be called with the lock held (so that allocation can
|
||||
* free previously allocated buffers). Trying to free buffers that are mapped
|
||||
* to user space will return -EBUSY.
|
||||
*
|
||||
* Video buffers are managed using two queues. However, unlike most USB video
|
||||
* drivers that use an in queue and an out queue, we use a main queue to hold
|
||||
* all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
|
||||
* hold empty buffers. This design (copied from video-buf) minimizes locking
|
||||
* in interrupt, as only one queue is shared between interrupt and user
|
||||
* contexts.
|
||||
*
|
||||
* Use cases
|
||||
* ---------
|
||||
*
|
||||
* Unless stated otherwise, all operations that modify the irq buffers queue
|
||||
* are protected by the irq spinlock.
|
||||
*
|
||||
* 1. The user queues the buffers, starts streaming and dequeues a buffer.
|
||||
*
|
||||
* The buffers are added to the main and irq queues. Both operations are
|
||||
* protected by the queue lock, and the later is protected by the irq
|
||||
* spinlock as well.
|
||||
*
|
||||
* The completion handler fetches a buffer from the irq queue and fills it
|
||||
* with video data. If no buffer is available (irq queue empty), the handler
|
||||
* returns immediately.
|
||||
*
|
||||
* When the buffer is full, the completion handler removes it from the irq
|
||||
* queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
|
||||
* At that point, any process waiting on the buffer will be woken up. If a
|
||||
* process tries to dequeue a buffer after it has been marked ready, the
|
||||
* dequeing will succeed immediately.
|
||||
*
|
||||
* 2. Buffers are queued, user is waiting on a buffer and the device gets
|
||||
* disconnected.
|
||||
*
|
||||
* When the device is disconnected, the kernel calls the completion handler
|
||||
* with an appropriate status code. The handler marks all buffers in the
|
||||
* irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
|
||||
* that any process waiting on a buffer gets woken up.
|
||||
*
|
||||
* Waking up up the first buffer on the irq list is not enough, as the
|
||||
* process waiting on the buffer might restart the dequeue operation
|
||||
* immediately.
|
||||
*
|
||||
* Video buffers are managed by videobuf2. The driver uses a mutex to protect
|
||||
* the videobuf2 queue operations by serializing calls to videobuf2 and a
|
||||
* spinlock to protect the IRQ queue that holds the buffers to be processed by
|
||||
* the driver.
|
||||
*/
|
||||
|
||||
static void
|
||||
uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
|
||||
/* -----------------------------------------------------------------------------
|
||||
* videobuf2 queue operations
|
||||
*/
|
||||
|
||||
static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
||||
unsigned int *nbuffers, unsigned int *nplanes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
mutex_init(&queue->mutex);
|
||||
spin_lock_init(&queue->irqlock);
|
||||
INIT_LIST_HEAD(&queue->mainqueue);
|
||||
INIT_LIST_HEAD(&queue->irqqueue);
|
||||
queue->type = type;
|
||||
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
|
||||
struct uvc_video *video = container_of(queue, struct uvc_video, queue);
|
||||
|
||||
if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
|
||||
*nbuffers = UVC_MAX_VIDEO_BUFFERS;
|
||||
|
||||
*nplanes = 1;
|
||||
|
||||
sizes[0] = video->imagesize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the video buffers.
|
||||
*
|
||||
* This function must be called with the queue lock held.
|
||||
*/
|
||||
static int uvc_free_buffers(struct uvc_video_queue *queue)
|
||||
static int uvc_buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
unsigned int i;
|
||||
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
|
||||
|
||||
for (i = 0; i < queue->count; ++i) {
|
||||
if (queue->buffer[i].vma_use_count != 0)
|
||||
return -EBUSY;
|
||||
if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
||||
vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (queue->count) {
|
||||
vfree(queue->mem);
|
||||
queue->count = 0;
|
||||
if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
|
||||
return -ENODEV;
|
||||
|
||||
buf->state = UVC_BUF_STATE_QUEUED;
|
||||
buf->mem = vb2_plane_vaddr(vb, 0);
|
||||
buf->length = vb2_plane_size(vb, 0);
|
||||
if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
buf->bytesused = 0;
|
||||
else
|
||||
buf->bytesused = vb2_get_plane_payload(vb, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uvc_buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
|
||||
if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
|
||||
list_add_tail(&buf->queue, &queue->irqqueue);
|
||||
} else {
|
||||
/* If the device is disconnected return the buffer to userspace
|
||||
* directly. The next QBUF call will fail with -ENODEV.
|
||||
*/
|
||||
buf->state = UVC_BUF_STATE_ERROR;
|
||||
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
}
|
||||
|
||||
static struct vb2_ops uvc_queue_qops = {
|
||||
.queue_setup = uvc_queue_setup,
|
||||
.buf_prepare = uvc_buffer_prepare,
|
||||
.buf_queue = uvc_buffer_queue,
|
||||
};
|
||||
|
||||
static int uvc_queue_init(struct uvc_video_queue *queue,
|
||||
enum v4l2_buf_type type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
queue->queue.type = type;
|
||||
queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
|
||||
queue->queue.drv_priv = queue;
|
||||
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
|
||||
queue->queue.ops = &uvc_queue_qops;
|
||||
queue->queue.mem_ops = &vb2_vmalloc_memops;
|
||||
ret = vb2_queue_init(&queue->queue);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&queue->mutex);
|
||||
spin_lock_init(&queue->irqlock);
|
||||
INIT_LIST_HEAD(&queue->irqqueue);
|
||||
queue->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the video buffers.
|
||||
*
|
||||
* Pages are reserved to make sure they will not be swapped, as they will be
|
||||
* filled in the URB completion handler.
|
||||
*
|
||||
* Buffers will be individually mapped, so they must all be page aligned.
|
||||
* Free the video buffers.
|
||||
*/
|
||||
static int
|
||||
uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
|
||||
unsigned int buflength)
|
||||
static void uvc_free_buffers(struct uvc_video_queue *queue)
|
||||
{
|
||||
unsigned int bufsize = PAGE_ALIGN(buflength);
|
||||
unsigned int i;
|
||||
void *mem = NULL;
|
||||
int ret;
|
||||
|
||||
if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
|
||||
nbuffers = UVC_MAX_VIDEO_BUFFERS;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
|
||||
if ((ret = uvc_free_buffers(queue)) < 0)
|
||||
goto done;
|
||||
|
||||
/* Bail out if no buffers should be allocated. */
|
||||
if (nbuffers == 0)
|
||||
goto done;
|
||||
|
||||
/* Decrement the number of buffers until allocation succeeds. */
|
||||
for (; nbuffers > 0; --nbuffers) {
|
||||
mem = vmalloc_32(nbuffers * bufsize);
|
||||
if (mem != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < nbuffers; ++i) {
|
||||
memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
|
||||
queue->buffer[i].buf.index = i;
|
||||
queue->buffer[i].buf.m.offset = i * bufsize;
|
||||
queue->buffer[i].buf.length = buflength;
|
||||
queue->buffer[i].buf.type = queue->type;
|
||||
queue->buffer[i].buf.sequence = 0;
|
||||
queue->buffer[i].buf.field = V4L2_FIELD_NONE;
|
||||
queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
|
||||
queue->buffer[i].buf.flags = 0;
|
||||
init_waitqueue_head(&queue->buffer[i].wait);
|
||||
}
|
||||
|
||||
queue->mem = mem;
|
||||
queue->count = nbuffers;
|
||||
queue->buf_size = bufsize;
|
||||
ret = nbuffers;
|
||||
|
||||
done:
|
||||
vb2_queue_release(&queue->queue);
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __uvc_query_buffer(struct uvc_buffer *buf,
|
||||
struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
|
||||
|
||||
if (buf->vma_use_count)
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
|
||||
|
||||
switch (buf->state) {
|
||||
case UVC_BUF_STATE_ERROR:
|
||||
case UVC_BUF_STATE_DONE:
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
|
||||
break;
|
||||
case UVC_BUF_STATE_QUEUED:
|
||||
case UVC_BUF_STATE_ACTIVE:
|
||||
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
|
||||
break;
|
||||
case UVC_BUF_STATE_IDLE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (v4l2_buf->index >= queue->count) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
|
||||
|
||||
done:
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue a video buffer. Attempting to queue a buffer that has already been
|
||||
* queued will return -EINVAL.
|
||||
* Allocate the video buffers.
|
||||
*/
|
||||
static int
|
||||
uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
|
||||
static int uvc_alloc_buffers(struct uvc_video_queue *queue,
|
||||
struct v4l2_requestbuffers *rb)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
|
||||
|
||||
if (v4l2_buf->type != queue->type ||
|
||||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
|
||||
"and/or memory (%u).\n", v4l2_buf->type,
|
||||
v4l2_buf->memory);
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (v4l2_buf->index >= queue->count) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf = &queue->buffer[v4l2_buf->index];
|
||||
if (buf->state != UVC_BUF_STATE_IDLE) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
|
||||
"(%u).\n", buf->state);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
||||
v4l2_buf->bytesused > buf->buf.length) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
buf->buf.bytesused = 0;
|
||||
else
|
||||
buf->buf.bytesused = v4l2_buf->bytesused;
|
||||
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
if (queue->flags & UVC_QUEUE_DISCONNECTED) {
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
buf->state = UVC_BUF_STATE_QUEUED;
|
||||
|
||||
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
|
||||
queue->flags &= ~UVC_QUEUE_PAUSED;
|
||||
|
||||
list_add_tail(&buf->stream, &queue->mainqueue);
|
||||
list_add_tail(&buf->queue, &queue->irqqueue);
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
|
||||
done:
|
||||
ret = vb2_reqbufs(&queue->queue, rb);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return ret ? ret : rb->count;
|
||||
}
|
||||
|
||||
static int uvc_query_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
ret = vb2_querybuf(&queue->queue, buf);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
|
||||
static int uvc_queue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
if (nonblocking) {
|
||||
return (buf->state != UVC_BUF_STATE_QUEUED &&
|
||||
buf->state != UVC_BUF_STATE_ACTIVE)
|
||||
? 0 : -EAGAIN;
|
||||
}
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
return wait_event_interruptible(buf->wait,
|
||||
buf->state != UVC_BUF_STATE_QUEUED &&
|
||||
buf->state != UVC_BUF_STATE_ACTIVE);
|
||||
mutex_lock(&queue->mutex);
|
||||
ret = vb2_qbuf(&queue->queue, buf);
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
|
||||
queue->flags &= ~UVC_QUEUE_PAUSED;
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dequeue a video buffer. If nonblocking is false, block until a buffer is
|
||||
* available.
|
||||
*/
|
||||
static int
|
||||
uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf,
|
||||
int nonblocking)
|
||||
static int uvc_dequeue_buffer(struct uvc_video_queue *queue,
|
||||
struct v4l2_buffer *buf, int nonblocking)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
int ret = 0;
|
||||
|
||||
if (v4l2_buf->type != queue->type ||
|
||||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
|
||||
"and/or memory (%u).\n", v4l2_buf->type,
|
||||
v4l2_buf->memory);
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (list_empty(&queue->mainqueue)) {
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
|
||||
if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
|
||||
goto done;
|
||||
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
|
||||
buf->buf.index, buf->state, buf->buf.bytesused);
|
||||
|
||||
switch (buf->state) {
|
||||
case UVC_BUF_STATE_ERROR:
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
|
||||
"(transmission error).\n");
|
||||
ret = -EIO;
|
||||
case UVC_BUF_STATE_DONE:
|
||||
buf->state = UVC_BUF_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case UVC_BUF_STATE_IDLE:
|
||||
case UVC_BUF_STATE_QUEUED:
|
||||
case UVC_BUF_STATE_ACTIVE:
|
||||
default:
|
||||
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
|
||||
"(driver bug?).\n", buf->state);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
list_del(&buf->stream);
|
||||
__uvc_query_buffer(buf, v4l2_buf);
|
||||
|
||||
done:
|
||||
ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -361,105 +208,47 @@ done:
|
|||
* This function implements video queue polling and is intended to be used by
|
||||
* the device poll handler.
|
||||
*/
|
||||
static unsigned int
|
||||
uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
|
||||
poll_table *wait)
|
||||
static unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
|
||||
struct file *file, poll_table *wait)
|
||||
{
|
||||
struct uvc_buffer *buf;
|
||||
unsigned int mask = 0;
|
||||
unsigned int ret;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (list_empty(&queue->mainqueue))
|
||||
goto done;
|
||||
|
||||
buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
|
||||
|
||||
poll_wait(file, &buf->wait, wait);
|
||||
if (buf->state == UVC_BUF_STATE_DONE ||
|
||||
buf->state == UVC_BUF_STATE_ERROR)
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
|
||||
done:
|
||||
ret = vb2_poll(&queue->queue, file, wait);
|
||||
mutex_unlock(&queue->mutex);
|
||||
return mask;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* VMA operations.
|
||||
*/
|
||||
static void uvc_vm_open(struct vm_area_struct *vma)
|
||||
static int uvc_queue_mmap(struct uvc_video_queue *queue,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *buffer = vma->vm_private_data;
|
||||
buffer->vma_use_count++;
|
||||
}
|
||||
|
||||
static void uvc_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *buffer = vma->vm_private_data;
|
||||
buffer->vma_use_count--;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct uvc_vm_ops = {
|
||||
.open = uvc_vm_open,
|
||||
.close = uvc_vm_close,
|
||||
};
|
||||
|
||||
/*
|
||||
* Memory-map a buffer.
|
||||
*
|
||||
* This function implements video buffer memory mapping and is intended to be
|
||||
* used by the device mmap handler.
|
||||
*/
|
||||
static int
|
||||
uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
|
||||
{
|
||||
struct uvc_buffer *uninitialized_var(buffer);
|
||||
struct page *page;
|
||||
unsigned long addr, start, size;
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
start = vma->vm_start;
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
ret = vb2_mmap(&queue->queue, vma);
|
||||
mutex_unlock(&queue->mutex);
|
||||
|
||||
for (i = 0; i < queue->count; ++i) {
|
||||
buffer = &queue->buffer[i];
|
||||
if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i == queue->count || size != queue->buf_size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
#ifndef CONFIG_MMU
|
||||
/*
|
||||
* Get unmapped area.
|
||||
*
|
||||
* NO-MMU arch need this function to make mmap() work correctly.
|
||||
*/
|
||||
static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
|
||||
unsigned long pgoff)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
/*
|
||||
* VM_IO marks the area as being an mmaped region for I/O to a
|
||||
* device. It also prevents the region from being core dumped.
|
||||
*/
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
|
||||
while (size > 0) {
|
||||
page = vmalloc_to_page((void *)addr);
|
||||
if ((ret = vm_insert_page(vma, start, page)) < 0)
|
||||
goto done;
|
||||
|
||||
start += PAGE_SIZE;
|
||||
addr += PAGE_SIZE;
|
||||
size -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
vma->vm_ops = &uvc_vm_ops;
|
||||
vma->vm_private_data = buffer;
|
||||
uvc_vm_open(vma);
|
||||
|
||||
done:
|
||||
mutex_lock(&queue->mutex);
|
||||
ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
|
||||
mutex_unlock(&queue->mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Cancel the video buffers queue.
|
||||
|
|
@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
|
|||
queue);
|
||||
list_del(&buf->queue);
|
||||
buf->state = UVC_BUF_STATE_ERROR;
|
||||
wake_up(&buf->wait);
|
||||
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
/* This must be protected by the irqlock spinlock to avoid race
|
||||
* conditions between uvc_queue_buffer and the disconnection event that
|
||||
|
|
@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
|
|||
*/
|
||||
static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&queue->mutex);
|
||||
if (enable) {
|
||||
if (uvc_queue_streaming(queue)) {
|
||||
ret = -EBUSY;
|
||||
ret = vb2_streamon(&queue->queue, queue->queue.type);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
queue->sequence = 0;
|
||||
queue->flags |= UVC_QUEUE_STREAMING;
|
||||
queue->buf_used = 0;
|
||||
} else {
|
||||
uvc_queue_cancel(queue, 0);
|
||||
INIT_LIST_HEAD(&queue->mainqueue);
|
||||
ret = vb2_streamoff(&queue->queue, queue->queue.type);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < queue->count; ++i)
|
||||
queue->buffer[i].state = UVC_BUF_STATE_IDLE;
|
||||
spin_lock_irqsave(&queue->irqlock, flags);
|
||||
INIT_LIST_HEAD(&queue->irqqueue);
|
||||
|
||||
queue->flags &= ~UVC_QUEUE_STREAMING;
|
||||
/*
|
||||
* FIXME: We need to clear the DISCONNECTED flag to ensure that
|
||||
* applications will be able to queue buffers for the next
|
||||
* streaming run. However, clearing it here doesn't guarantee
|
||||
* that the device will be reconnected in the meantime.
|
||||
*/
|
||||
queue->flags &= ~UVC_QUEUE_DISCONNECTED;
|
||||
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
@ -544,15 +340,15 @@ done:
|
|||
}
|
||||
|
||||
/* called with &queue_irqlock held.. */
|
||||
static struct uvc_buffer *
|
||||
uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
|
||||
static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
|
||||
struct uvc_buffer *buf)
|
||||
{
|
||||
struct uvc_buffer *nextbuf;
|
||||
|
||||
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
|
||||
buf->buf.length != buf->buf.bytesused) {
|
||||
buf->length != buf->bytesused) {
|
||||
buf->state = UVC_BUF_STATE_QUEUED;
|
||||
buf->buf.bytesused = 0;
|
||||
vb2_set_plane_payload(&buf->buf, 0, 0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
|
|||
else
|
||||
nextbuf = NULL;
|
||||
|
||||
buf->buf.sequence = queue->sequence++;
|
||||
do_gettimeofday(&buf->buf.timestamp);
|
||||
/*
|
||||
* FIXME: with videobuf2, the sequence number or timestamp fields
|
||||
* are valid only for video capture devices and the UVC gadget usually
|
||||
* is a video output device. Keeping these until the specs are clear on
|
||||
* this aspect.
|
||||
*/
|
||||
buf->buf.v4l2_buf.sequence = queue->sequence++;
|
||||
do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
|
||||
|
||||
vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
|
||||
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
|
||||
|
||||
wake_up(&buf->wait);
|
||||
return nextbuf;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue