mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge tag 'usb-for-v3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes: usb: patches for v3.17 merge window Surprisingly enough, while a big set of patches, the majority is composed of cleanups (using devm_*, fixing sparse errors, moving code around, adding const, etc). The highlights are addition of new support for PLX USB338x devices, and support for USB 2.0-only configurations of the DWC3 IP core. Signed-of-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
@@ -556,11 +556,11 @@ been converted to this framework.
|
||||
Near-term plans include converting all of them, except for "gadgetfs".
|
||||
</para>
|
||||
|
||||
!Edrivers/usb/gadget/f_acm.c
|
||||
!Edrivers/usb/gadget/f_ecm.c
|
||||
!Edrivers/usb/gadget/f_subset.c
|
||||
!Edrivers/usb/gadget/f_obex.c
|
||||
!Edrivers/usb/gadget/f_serial.c
|
||||
!Edrivers/usb/gadget/function/f_acm.c
|
||||
!Edrivers/usb/gadget/function/f_ecm.c
|
||||
!Edrivers/usb/gadget/function/f_subset.c
|
||||
!Edrivers/usb/gadget/function/f_obex.c
|
||||
!Edrivers/usb/gadget/function/f_serial.c
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
+32
-19
@@ -386,6 +386,13 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
}
|
||||
dwc->revision = reg;
|
||||
|
||||
/* Handle USB2.0-only core configuration */
|
||||
if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
|
||||
DWC3_GHWPARAMS3_SSPHY_IFC_DIS) {
|
||||
if (dwc->maximum_speed == USB_SPEED_SUPER)
|
||||
dwc->maximum_speed = USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
/* issue device SoftReset too */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
|
||||
@@ -656,6 +663,31 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dwc->xhci_resources[0].start = res->start;
|
||||
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
|
||||
DWC3_XHCI_REGS_END;
|
||||
dwc->xhci_resources[0].flags = res->flags;
|
||||
dwc->xhci_resources[0].name = res->name;
|
||||
|
||||
res->start += DWC3_GLOBALS_REGS_START;
|
||||
|
||||
/*
|
||||
* Request memory region but exclude xHCI regs,
|
||||
* since it will be requested by the xhci-plat driver.
|
||||
*/
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
dwc->regs = regs;
|
||||
dwc->regs_size = resource_size(res);
|
||||
/*
|
||||
* restore res->start back to its original value so that,
|
||||
* in case the probe is deferred, we don't end up getting error in
|
||||
* request the memory region the next time probe is called.
|
||||
*/
|
||||
res->start -= DWC3_GLOBALS_REGS_START;
|
||||
|
||||
if (node) {
|
||||
dwc->maximum_speed = of_usb_get_maximum_speed(node);
|
||||
|
||||
@@ -676,28 +708,9 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwc->xhci_resources[0].start = res->start;
|
||||
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
|
||||
DWC3_XHCI_REGS_END;
|
||||
dwc->xhci_resources[0].flags = res->flags;
|
||||
dwc->xhci_resources[0].name = res->name;
|
||||
|
||||
res->start += DWC3_GLOBALS_REGS_START;
|
||||
|
||||
/*
|
||||
* Request memory region but exclude xHCI regs,
|
||||
* since it will be requested by the xhci-plat driver.
|
||||
*/
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
spin_lock_init(&dwc->lock);
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
|
||||
dwc->regs = regs;
|
||||
dwc->regs_size = resource_size(res);
|
||||
|
||||
dev->dma_mask = dev->parent->dma_mask;
|
||||
dev->dma_parms = dev->parent->dma_parms;
|
||||
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
|
||||
|
||||
@@ -191,6 +191,19 @@
|
||||
#define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24)
|
||||
#define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3)
|
||||
|
||||
/* Global HWPARAMS3 Register */
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3)
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS 0
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_ENA 1
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC(n) (((n) & (3 << 2)) >> 2)
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS 0
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI 1
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_ULPI 2
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI 3
|
||||
#define DWC3_GHWPARAMS3_FSPHY_IFC(n) (((n) & (3 << 4)) >> 4)
|
||||
#define DWC3_GHWPARAMS3_FSPHY_IFC_DIS 0
|
||||
#define DWC3_GHWPARAMS3_FSPHY_IFC_ENA 1
|
||||
|
||||
/* Global HWPARAMS4 Register */
|
||||
#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13)
|
||||
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
|
||||
|
||||
@@ -77,10 +77,6 @@
|
||||
#define USBOTGSS_DEV_EBC_EN 0x0110
|
||||
#define USBOTGSS_DEBUG_OFFSET 0x0600
|
||||
|
||||
/* REVISION REGISTER */
|
||||
#define USBOTGSS_REVISION_XMAJOR(reg) ((reg >> 8) & 0x7)
|
||||
#define USBOTGSS_REVISION_XMAJOR1 1
|
||||
#define USBOTGSS_REVISION_XMAJOR2 2
|
||||
/* SYSCONFIG REGISTER */
|
||||
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
|
||||
|
||||
@@ -129,7 +125,6 @@ struct dwc3_omap {
|
||||
u32 irq_eoi_offset;
|
||||
u32 debug_offset;
|
||||
u32 irq0_offset;
|
||||
u32 revision;
|
||||
|
||||
u32 dma_status:1;
|
||||
|
||||
@@ -383,6 +378,87 @@ static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void dwc3_omap_map_offset(struct dwc3_omap *omap)
|
||||
{
|
||||
struct device_node *node = omap->dev->of_node;
|
||||
|
||||
/*
|
||||
* Differentiate between OMAP5 and AM437x.
|
||||
*
|
||||
* For OMAP5(ES2.0) and AM437x wrapper revision is same, even
|
||||
* though there are changes in wrapper register offsets.
|
||||
*
|
||||
* Using dt compatible to differentiate AM437x.
|
||||
*/
|
||||
if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
|
||||
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
|
||||
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
|
||||
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
|
||||
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
|
||||
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
|
||||
{
|
||||
u32 reg;
|
||||
struct device_node *node = omap->dev->of_node;
|
||||
int utmi_mode = 0;
|
||||
|
||||
reg = dwc3_omap_read_utmi_status(omap);
|
||||
|
||||
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(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
|
||||
}
|
||||
|
||||
dwc3_omap_write_utmi_status(omap, reg);
|
||||
}
|
||||
|
||||
static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
|
||||
{
|
||||
u32 ret;
|
||||
struct device_node *node = omap->dev->of_node;
|
||||
struct extcon_dev *edev;
|
||||
|
||||
if (of_property_read_bool(node, "extcon")) {
|
||||
edev = extcon_get_edev_by_phandle(omap->dev, 0);
|
||||
if (IS_ERR(edev)) {
|
||||
dev_vdbg(omap->dev, "couldn't get extcon device\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_vbus_dev,
|
||||
edev->name, "USB",
|
||||
&omap->vbus_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(omap->dev, "failed to register notifier for USB\n");
|
||||
|
||||
omap->id_nb.notifier_call = dwc3_omap_id_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_id_dev,
|
||||
edev->name, "USB-HOST",
|
||||
&omap->id_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n");
|
||||
|
||||
if (extcon_get_cable_state(edev, "USB") == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
|
||||
if (extcon_get_cable_state(edev, "USB-HOST") == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
@@ -390,15 +466,11 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
struct dwc3_omap *omap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct extcon_dev *edev;
|
||||
struct regulator *vbus_reg = NULL;
|
||||
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
int utmi_mode = 0;
|
||||
int x_major;
|
||||
|
||||
u32 reg;
|
||||
|
||||
void __iomem *base;
|
||||
@@ -448,58 +520,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_REVISION);
|
||||
omap->revision = reg;
|
||||
x_major = USBOTGSS_REVISION_XMAJOR(reg);
|
||||
|
||||
/* Differentiate between OMAP5 and AM437x */
|
||||
switch (x_major) {
|
||||
case USBOTGSS_REVISION_XMAJOR1:
|
||||
case USBOTGSS_REVISION_XMAJOR2:
|
||||
omap->irq_eoi_offset = 0;
|
||||
omap->irq0_offset = 0;
|
||||
omap->irqmisc_offset = 0;
|
||||
omap->utmi_otg_offset = 0;
|
||||
omap->debug_offset = 0;
|
||||
break;
|
||||
default:
|
||||
/* Default to the latest revision */
|
||||
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
|
||||
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
|
||||
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
|
||||
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
|
||||
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
/* For OMAP5(ES2.0) and AM437x x_major is 2 even though there are
|
||||
* changes in wrapper registers, Using dt compatible for aegis
|
||||
*/
|
||||
|
||||
if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
|
||||
omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
|
||||
omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
|
||||
omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
|
||||
omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
|
||||
omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
|
||||
}
|
||||
|
||||
reg = dwc3_omap_read_utmi_status(omap);
|
||||
|
||||
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_write_utmi_status(omap, reg);
|
||||
dwc3_omap_map_offset(omap);
|
||||
dwc3_omap_set_utmi_mode(omap);
|
||||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
@@ -515,31 +537,9 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
|
||||
dwc3_omap_enable_irqs(omap);
|
||||
|
||||
if (of_property_read_bool(node, "extcon")) {
|
||||
edev = extcon_get_edev_by_phandle(dev, 0);
|
||||
if (IS_ERR(edev)) {
|
||||
dev_vdbg(dev, "couldn't get extcon device\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_vbus_dev,
|
||||
edev->name, "USB", &omap->vbus_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(dev, "failed to register notifier for USB\n");
|
||||
omap->id_nb.notifier_call = dwc3_omap_id_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_id_dev, edev->name,
|
||||
"USB-HOST", &omap->id_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(dev,
|
||||
"failed to register notifier for USB-HOST\n");
|
||||
|
||||
if (extcon_get_cable_state(edev, "USB") == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
|
||||
if (extcon_get_cable_state(edev, "USB-HOST") == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
|
||||
}
|
||||
ret = dwc3_omap_extcon_register(omap);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
|
||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
|
||||
@@ -1971,8 +1971,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
}
|
||||
|
||||
static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
|
||||
int start_new)
|
||||
struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
|
||||
{
|
||||
unsigned status = 0;
|
||||
int clean_busy;
|
||||
@@ -2039,7 +2038,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
return;
|
||||
}
|
||||
|
||||
dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
|
||||
dwc3_endpoint_transfer_complete(dwc, dep, event);
|
||||
break;
|
||||
case DWC3_DEPEVT_XFERINPROGRESS:
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
@@ -2048,7 +2047,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
return;
|
||||
}
|
||||
|
||||
dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
|
||||
dwc3_endpoint_transfer_complete(dwc, dep, event);
|
||||
break;
|
||||
case DWC3_DEPEVT_XFERNOTREADY:
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
|
||||
+2
-822
File diff suppressed because it is too large
Load Diff
@@ -1,105 +1,12 @@
|
||||
#
|
||||
# USB peripheral controller drivers
|
||||
#
|
||||
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
|
||||
ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG
|
||||
subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
|
||||
subdir-ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG
|
||||
ccflags-y += -I$(PWD)/drivers/usb/gadget/udc
|
||||
|
||||
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 configfs.o u_f.o
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
|
||||
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
|
||||
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
|
||||
obj-$(CONFIG_USB_GOKU) += goku_udc.o
|
||||
obj-$(CONFIG_USB_OMAP) += omap_udc.o
|
||||
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
|
||||
obj-$(CONFIG_USB_AT91) += at91_udc.o
|
||||
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
|
||||
obj-$(CONFIG_USB_BCM63XX_UDC) += bcm63xx_udc.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
|
||||
fsl_usb2_udc-y := fsl_udc_core.o
|
||||
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
|
||||
obj-$(CONFIG_USB_M66592) += m66592-udc.o
|
||||
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
||||
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
|
||||
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
|
||||
obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
|
||||
obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
|
||||
mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
|
||||
|
||||
# USB Functions
|
||||
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
|
||||
obj-$(CONFIG_USB_U_ETHER) += u_ether.o
|
||||
usb_f_ncm-y := f_ncm.o
|
||||
obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o
|
||||
usb_f_ecm-y := f_ecm.o
|
||||
obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o
|
||||
usb_f_phonet-y := f_phonet.o
|
||||
obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o
|
||||
usb_f_eem-y := f_eem.o
|
||||
obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o
|
||||
usb_f_ecm_subset-y := f_subset.o
|
||||
obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o
|
||||
usb_f_rndis-y := f_rndis.o rndis.o
|
||||
obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o
|
||||
usb_f_mass_storage-y := f_mass_storage.o storage_common.o
|
||||
obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
|
||||
usb_f_fs-y := f_fs.o
|
||||
obj-$(CONFIG_USB_F_FS) += usb_f_fs.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
#
|
||||
g_zero-y := zero.o
|
||||
g_audio-y := audio.o
|
||||
g_ether-y := ether.o
|
||||
g_serial-y := serial.o
|
||||
g_midi-y := gmidi.o
|
||||
gadgetfs-y := inode.o
|
||||
g_mass_storage-y := mass_storage.o
|
||||
g_printer-y := printer.o
|
||||
g_cdc-y := cdc2.o
|
||||
g_multi-y := multi.o
|
||||
g_hid-y := hid.o
|
||||
g_dbgp-y := dbgp.o
|
||||
g_nokia-y := nokia.o
|
||||
g_webcam-y := webcam.o
|
||||
g_ncm-y := ncm.o
|
||||
g_acm_ms-y := acm_ms.o
|
||||
g_tcm_usb_gadget-y := tcm_usb_gadget.o
|
||||
|
||||
obj-$(CONFIG_USB_ZERO) += g_zero.o
|
||||
obj-$(CONFIG_USB_AUDIO) += g_audio.o
|
||||
obj-$(CONFIG_USB_ETH) += g_ether.o
|
||||
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
|
||||
obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o
|
||||
obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
|
||||
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
|
||||
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
|
||||
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
|
||||
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
|
||||
obj-$(CONFIG_USB_G_HID) += g_hid.o
|
||||
obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o
|
||||
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
|
||||
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
|
||||
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
|
||||
obj-$(CONFIG_USB_G_NCM) += g_ncm.o
|
||||
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
|
||||
obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
|
||||
obj-$(CONFIG_USB_GADGET) += udc/ function/ legacy/
|
||||
|
||||
@@ -1956,6 +1956,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
|
||||
}
|
||||
if (cdev->req) {
|
||||
kfree(cdev->req->buf);
|
||||
usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
|
||||
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
|
||||
}
|
||||
cdev->next_string_id = 0;
|
||||
|
||||
@@ -1021,12 +1021,10 @@ static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop,
|
||||
|
||||
if (page[len - 1] == '\n' || page[len - 1] == '\0')
|
||||
--len;
|
||||
new_data = kzalloc(len, GFP_KERNEL);
|
||||
new_data = kmemdup(page, len, GFP_KERNEL);
|
||||
if (!new_data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(new_data, page, len);
|
||||
|
||||
if (desc->opts_mutex)
|
||||
mutex_lock(desc->opts_mutex);
|
||||
kfree(ext_prop->data);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# USB peripheral controller drivers
|
||||
#
|
||||
|
||||
ccflags-y := -I$(PWD)/drivers/usb/gadget/
|
||||
ccflags-y += -I$(PWD)/drivers/usb/gadget/udc/
|
||||
|
||||
# USB Functions
|
||||
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
|
||||
obj-$(CONFIG_USB_U_ETHER) += u_ether.o
|
||||
usb_f_ncm-y := f_ncm.o
|
||||
obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o
|
||||
usb_f_ecm-y := f_ecm.o
|
||||
obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o
|
||||
usb_f_phonet-y := f_phonet.o
|
||||
obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o
|
||||
usb_f_eem-y := f_eem.o
|
||||
obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o
|
||||
usb_f_ecm_subset-y := f_subset.o
|
||||
obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o
|
||||
usb_f_rndis-y := f_rndis.o rndis.o
|
||||
obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o
|
||||
usb_f_mass_storage-y := f_mass_storage.o storage_common.o
|
||||
obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
|
||||
usb_f_fs-y := f_fs.o
|
||||
obj-$(CONFIG_USB_F_FS) += usb_f_fs.o
|
||||
@@ -355,20 +355,18 @@ static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb)
|
||||
int padlen = 0;
|
||||
u16 len = skb->len;
|
||||
|
||||
if (!skb_cloned(skb)) {
|
||||
int headroom = skb_headroom(skb);
|
||||
int tailroom = skb_tailroom(skb);
|
||||
int headroom = skb_headroom(skb);
|
||||
int tailroom = skb_tailroom(skb);
|
||||
|
||||
/* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0,
|
||||
* stick two bytes of zero-length EEM packet on the end.
|
||||
*/
|
||||
if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0)
|
||||
padlen += 2;
|
||||
/* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0,
|
||||
* stick two bytes of zero-length EEM packet on the end.
|
||||
*/
|
||||
if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0)
|
||||
padlen += 2;
|
||||
|
||||
if ((tailroom >= (ETH_FCS_LEN + padlen)) &&
|
||||
(headroom >= EEM_HLEN))
|
||||
goto done;
|
||||
}
|
||||
if ((tailroom >= (ETH_FCS_LEN + padlen)) &&
|
||||
(headroom >= EEM_HLEN) && !skb_cloned(skb))
|
||||
goto done;
|
||||
|
||||
skb2 = skb_copy_expand(skb, EEM_HLEN, ETH_FCS_LEN + padlen, GFP_ATOMIC);
|
||||
dev_kfree_skb_any(skb);
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "u_fs.h"
|
||||
#include "u_f.h"
|
||||
#include "u_os_desc.h"
|
||||
#include "configfs.h"
|
||||
|
||||
#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
|
||||
@@ -1646,13 +1647,22 @@ enum ffs_entity_type {
|
||||
FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
|
||||
};
|
||||
|
||||
enum ffs_os_desc_type {
|
||||
FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
|
||||
};
|
||||
|
||||
typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
|
||||
u8 *valuep,
|
||||
struct usb_descriptor_header *desc,
|
||||
void *priv);
|
||||
|
||||
static int __must_check ffs_do_desc(char *data, unsigned len,
|
||||
ffs_entity_callback entity, void *priv)
|
||||
typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
|
||||
struct usb_os_desc_header *h, void *data,
|
||||
unsigned len, void *priv);
|
||||
|
||||
static int __must_check ffs_do_single_desc(char *data, unsigned len,
|
||||
ffs_entity_callback entity,
|
||||
void *priv)
|
||||
{
|
||||
struct usb_descriptor_header *_ds = (void *)data;
|
||||
u8 length;
|
||||
@@ -1804,7 +1814,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
|
||||
if (!data)
|
||||
return _len - len;
|
||||
|
||||
ret = ffs_do_desc(data, len, entity, priv);
|
||||
ret = ffs_do_single_desc(data, len, entity, priv);
|
||||
if (unlikely(ret < 0)) {
|
||||
pr_debug("%s returns %d\n", __func__, ret);
|
||||
return ret;
|
||||
@@ -1857,11 +1867,191 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
|
||||
struct usb_os_desc_header *desc)
|
||||
{
|
||||
u16 bcd_version = le16_to_cpu(desc->bcdVersion);
|
||||
u16 w_index = le16_to_cpu(desc->wIndex);
|
||||
|
||||
if (bcd_version != 1) {
|
||||
pr_vdebug("unsupported os descriptors version: %d",
|
||||
bcd_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (w_index) {
|
||||
case 0x4:
|
||||
*next_type = FFS_OS_DESC_EXT_COMPAT;
|
||||
break;
|
||||
case 0x5:
|
||||
*next_type = FFS_OS_DESC_EXT_PROP;
|
||||
break;
|
||||
default:
|
||||
pr_vdebug("unsupported os descriptor type: %d", w_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sizeof(*desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process all extended compatibility/extended property descriptors
|
||||
* of a feature descriptor
|
||||
*/
|
||||
static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
|
||||
enum ffs_os_desc_type type,
|
||||
u16 feature_count,
|
||||
ffs_os_desc_callback entity,
|
||||
void *priv,
|
||||
struct usb_os_desc_header *h)
|
||||
{
|
||||
int ret;
|
||||
const unsigned _len = len;
|
||||
|
||||
ENTER();
|
||||
|
||||
/* loop over all ext compat/ext prop descriptors */
|
||||
while (feature_count--) {
|
||||
ret = entity(type, h, data, len, priv);
|
||||
if (unlikely(ret < 0)) {
|
||||
pr_debug("bad OS descriptor, type: %d\n", type);
|
||||
return ret;
|
||||
}
|
||||
data += ret;
|
||||
len -= ret;
|
||||
}
|
||||
return _len - len;
|
||||
}
|
||||
|
||||
/* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
|
||||
static int __must_check ffs_do_os_descs(unsigned count,
|
||||
char *data, unsigned len,
|
||||
ffs_os_desc_callback entity, void *priv)
|
||||
{
|
||||
const unsigned _len = len;
|
||||
unsigned long num = 0;
|
||||
|
||||
ENTER();
|
||||
|
||||
for (num = 0; num < count; ++num) {
|
||||
int ret;
|
||||
enum ffs_os_desc_type type;
|
||||
u16 feature_count;
|
||||
struct usb_os_desc_header *desc = (void *)data;
|
||||
|
||||
if (len < sizeof(*desc))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Record "descriptor" entity.
|
||||
* Process dwLength, bcdVersion, wIndex, get b/wCount.
|
||||
* Move the data pointer to the beginning of extended
|
||||
* compatibilities proper or extended properties proper
|
||||
* portions of the data
|
||||
*/
|
||||
if (le32_to_cpu(desc->dwLength) > len)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __ffs_do_os_desc_header(&type, desc);
|
||||
if (unlikely(ret < 0)) {
|
||||
pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
|
||||
num, ret);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
|
||||
*/
|
||||
feature_count = le16_to_cpu(desc->wCount);
|
||||
if (type == FFS_OS_DESC_EXT_COMPAT &&
|
||||
(feature_count > 255 || desc->Reserved))
|
||||
return -EINVAL;
|
||||
len -= ret;
|
||||
data += ret;
|
||||
|
||||
/*
|
||||
* Process all function/property descriptors
|
||||
* of this Feature Descriptor
|
||||
*/
|
||||
ret = ffs_do_single_os_desc(data, len, type,
|
||||
feature_count, entity, priv, desc);
|
||||
if (unlikely(ret < 0)) {
|
||||
pr_debug("%s returns %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= ret;
|
||||
data += ret;
|
||||
}
|
||||
return _len - len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate contents of the buffer from userspace related to OS descriptors.
|
||||
*/
|
||||
static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
|
||||
struct usb_os_desc_header *h, void *data,
|
||||
unsigned len, void *priv)
|
||||
{
|
||||
struct ffs_data *ffs = priv;
|
||||
u8 length;
|
||||
|
||||
ENTER();
|
||||
|
||||
switch (type) {
|
||||
case FFS_OS_DESC_EXT_COMPAT: {
|
||||
struct usb_ext_compat_desc *d = data;
|
||||
int i;
|
||||
|
||||
if (len < sizeof(*d) ||
|
||||
d->bFirstInterfaceNumber >= ffs->interfaces_count ||
|
||||
d->Reserved1)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
|
||||
if (d->Reserved2[i])
|
||||
return -EINVAL;
|
||||
|
||||
length = sizeof(struct usb_ext_compat_desc);
|
||||
}
|
||||
break;
|
||||
case FFS_OS_DESC_EXT_PROP: {
|
||||
struct usb_ext_prop_desc *d = data;
|
||||
u32 type, pdl;
|
||||
u16 pnl;
|
||||
|
||||
if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
|
||||
return -EINVAL;
|
||||
length = le32_to_cpu(d->dwSize);
|
||||
type = le32_to_cpu(d->dwPropertyDataType);
|
||||
if (type < USB_EXT_PROP_UNICODE ||
|
||||
type > USB_EXT_PROP_UNICODE_MULTI) {
|
||||
pr_vdebug("unsupported os descriptor property type: %d",
|
||||
type);
|
||||
return -EINVAL;
|
||||
}
|
||||
pnl = le16_to_cpu(d->wPropertyNameLength);
|
||||
pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
|
||||
if (length != 14 + pnl + pdl) {
|
||||
pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
|
||||
length, pnl, pdl, type);
|
||||
return -EINVAL;
|
||||
}
|
||||
++ffs->ms_os_descs_ext_prop_count;
|
||||
/* property name reported to the host as "WCHAR"s */
|
||||
ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
|
||||
ffs->ms_os_descs_ext_prop_data_len += pdl;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_vdebug("unknown descriptor: %d\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
char *const _data, size_t len)
|
||||
{
|
||||
char *data = _data, *raw_descs;
|
||||
unsigned counts[3], flags;
|
||||
unsigned os_descs_count = 0, counts[3], flags;
|
||||
int ret = -EINVAL, i;
|
||||
|
||||
ENTER();
|
||||
@@ -1879,7 +2069,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
flags = get_unaligned_le32(data + 8);
|
||||
if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
|
||||
FUNCTIONFS_HAS_HS_DESC |
|
||||
FUNCTIONFS_HAS_SS_DESC)) {
|
||||
FUNCTIONFS_HAS_SS_DESC |
|
||||
FUNCTIONFS_HAS_MS_OS_DESC)) {
|
||||
ret = -ENOSYS;
|
||||
goto error;
|
||||
}
|
||||
@@ -1902,6 +2093,11 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
len -= 4;
|
||||
}
|
||||
}
|
||||
if (flags & (1 << i)) {
|
||||
os_descs_count = get_unaligned_le32(data);
|
||||
data += 4;
|
||||
len -= 4;
|
||||
};
|
||||
|
||||
/* Read descriptors */
|
||||
raw_descs = data;
|
||||
@@ -1915,6 +2111,14 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
data += ret;
|
||||
len -= ret;
|
||||
}
|
||||
if (os_descs_count) {
|
||||
ret = ffs_do_os_descs(os_descs_count, data, len,
|
||||
__ffs_data_do_os_desc, ffs);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
data += ret;
|
||||
len -= ret;
|
||||
}
|
||||
|
||||
if (raw_descs == data || len) {
|
||||
ret = -EINVAL;
|
||||
@@ -1927,6 +2131,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
||||
ffs->fs_descs_count = counts[0];
|
||||
ffs->hs_descs_count = counts[1];
|
||||
ffs->ss_descs_count = counts[2];
|
||||
ffs->ms_os_descs_count = os_descs_count;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2268,6 +2473,85 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
|
||||
struct usb_os_desc_header *h, void *data,
|
||||
unsigned len, void *priv)
|
||||
{
|
||||
struct ffs_function *func = priv;
|
||||
u8 length = 0;
|
||||
|
||||
switch (type) {
|
||||
case FFS_OS_DESC_EXT_COMPAT: {
|
||||
struct usb_ext_compat_desc *desc = data;
|
||||
struct usb_os_desc_table *t;
|
||||
|
||||
t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
|
||||
t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
|
||||
memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
|
||||
ARRAY_SIZE(desc->CompatibleID) +
|
||||
ARRAY_SIZE(desc->SubCompatibleID));
|
||||
length = sizeof(*desc);
|
||||
}
|
||||
break;
|
||||
case FFS_OS_DESC_EXT_PROP: {
|
||||
struct usb_ext_prop_desc *desc = data;
|
||||
struct usb_os_desc_table *t;
|
||||
struct usb_os_desc_ext_prop *ext_prop;
|
||||
char *ext_prop_name;
|
||||
char *ext_prop_data;
|
||||
|
||||
t = &func->function.os_desc_table[h->interface];
|
||||
t->if_id = func->interfaces_nums[h->interface];
|
||||
|
||||
ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
|
||||
func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
|
||||
|
||||
ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
|
||||
ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
|
||||
ext_prop->data_len = le32_to_cpu(*(u32 *)
|
||||
usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
|
||||
length = ext_prop->name_len + ext_prop->data_len + 14;
|
||||
|
||||
ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
|
||||
func->ffs->ms_os_descs_ext_prop_name_avail +=
|
||||
ext_prop->name_len;
|
||||
|
||||
ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
|
||||
func->ffs->ms_os_descs_ext_prop_data_avail +=
|
||||
ext_prop->data_len;
|
||||
memcpy(ext_prop_data,
|
||||
usb_ext_prop_data_ptr(data, ext_prop->name_len),
|
||||
ext_prop->data_len);
|
||||
/* unicode data reported to the host as "WCHAR"s */
|
||||
switch (ext_prop->type) {
|
||||
case USB_EXT_PROP_UNICODE:
|
||||
case USB_EXT_PROP_UNICODE_ENV:
|
||||
case USB_EXT_PROP_UNICODE_LINK:
|
||||
case USB_EXT_PROP_UNICODE_MULTI:
|
||||
ext_prop->data_len *= 2;
|
||||
break;
|
||||
}
|
||||
ext_prop->data = ext_prop_data;
|
||||
|
||||
memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
|
||||
ext_prop->name_len);
|
||||
/* property name reported to the host as "WCHAR"s */
|
||||
ext_prop->name_len *= 2;
|
||||
ext_prop->name = ext_prop_name;
|
||||
|
||||
t->os_desc->ext_prop_len +=
|
||||
ext_prop->name_len + ext_prop->data_len + 14;
|
||||
++t->os_desc->ext_prop_count;
|
||||
list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_vdebug("unknown descriptor: %d\n", type);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
|
||||
struct usb_configuration *c)
|
||||
{
|
||||
@@ -2329,7 +2613,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
const int super = gadget_is_superspeed(func->gadget) &&
|
||||
func->ffs->ss_descs_count;
|
||||
|
||||
int fs_len, hs_len, ret;
|
||||
int fs_len, hs_len, ss_len, ret, i;
|
||||
|
||||
/* Make it a single chunk, less management later on */
|
||||
vla_group(d);
|
||||
@@ -2341,6 +2625,18 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
|
||||
super ? ffs->ss_descs_count + 1 : 0);
|
||||
vla_item_with_sz(d, short, inums, ffs->interfaces_count);
|
||||
vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
|
||||
c->cdev->use_os_string ? ffs->interfaces_count : 0);
|
||||
vla_item_with_sz(d, char[16], ext_compat,
|
||||
c->cdev->use_os_string ? ffs->interfaces_count : 0);
|
||||
vla_item_with_sz(d, struct usb_os_desc, os_desc,
|
||||
c->cdev->use_os_string ? ffs->interfaces_count : 0);
|
||||
vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
|
||||
ffs->ms_os_descs_ext_prop_count);
|
||||
vla_item_with_sz(d, char, ext_prop_name,
|
||||
ffs->ms_os_descs_ext_prop_name_len);
|
||||
vla_item_with_sz(d, char, ext_prop_data,
|
||||
ffs->ms_os_descs_ext_prop_data_len);
|
||||
vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
|
||||
char *vlabuf;
|
||||
|
||||
@@ -2351,12 +2647,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* Allocate a single chunk, less management later on */
|
||||
vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
|
||||
vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
|
||||
if (unlikely(!vlabuf))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Zero */
|
||||
memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
|
||||
ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
|
||||
ffs->ms_os_descs_ext_prop_name_avail =
|
||||
vla_ptr(vlabuf, d, ext_prop_name);
|
||||
ffs->ms_os_descs_ext_prop_data_avail =
|
||||
vla_ptr(vlabuf, d, ext_prop_data);
|
||||
|
||||
/* Copy descriptors */
|
||||
memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
|
||||
ffs->raw_descs_length);
|
||||
@@ -2410,12 +2710,16 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
|
||||
if (likely(super)) {
|
||||
func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
|
||||
ret = ffs_do_descs(ffs->ss_descs_count,
|
||||
ss_len = ffs_do_descs(ffs->ss_descs_count,
|
||||
vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
|
||||
d_raw_descs__sz - fs_len - hs_len,
|
||||
__ffs_func_bind_do_descs, func);
|
||||
if (unlikely(ret < 0))
|
||||
if (unlikely(ss_len < 0)) {
|
||||
ret = ss_len;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
ss_len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2431,6 +2735,28 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
|
||||
func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
|
||||
if (c->cdev->use_os_string)
|
||||
for (i = 0; i < ffs->interfaces_count; ++i) {
|
||||
struct usb_os_desc *desc;
|
||||
|
||||
desc = func->function.os_desc_table[i].os_desc =
|
||||
vla_ptr(vlabuf, d, os_desc) +
|
||||
i * sizeof(struct usb_os_desc);
|
||||
desc->ext_compat_id =
|
||||
vla_ptr(vlabuf, d, ext_compat) + i * 16;
|
||||
INIT_LIST_HEAD(&desc->ext_prop);
|
||||
}
|
||||
ret = ffs_do_os_descs(ffs->ms_os_descs_count,
|
||||
vla_ptr(vlabuf, d, raw_descs) +
|
||||
fs_len + hs_len + ss_len,
|
||||
d_raw_descs__sz - fs_len - hs_len - ss_len,
|
||||
__ffs_func_bind_do_os_desc, func);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
func->function.os_desc_n =
|
||||
c->cdev->use_os_string ? ffs->interfaces_count : 0;
|
||||
|
||||
/* And we're done */
|
||||
ffs_event_add(ffs, FUNCTIONFS_BIND);
|
||||
return 0;
|
||||
@@ -2901,12 +3227,12 @@ static void *ffs_acquire_dev(const char *dev_name)
|
||||
|
||||
ffs_dev = _ffs_find_dev(dev_name);
|
||||
if (!ffs_dev)
|
||||
ffs_dev = ERR_PTR(-ENODEV);
|
||||
ffs_dev = ERR_PTR(-ENOENT);
|
||||
else if (ffs_dev->mounted)
|
||||
ffs_dev = ERR_PTR(-EBUSY);
|
||||
else if (ffs_dev->ffs_acquire_dev_callback &&
|
||||
ffs_dev->ffs_acquire_dev_callback(ffs_dev))
|
||||
ffs_dev = ERR_PTR(-ENODEV);
|
||||
ffs_dev = ERR_PTR(-ENOENT);
|
||||
else
|
||||
ffs_dev->mounted = true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user