Merge 3.3-rc7 into usb-next

This resolves the conflict with drivers/usb/host/ehci-fsl.h that
happened with changes in Linus's and this branch at the same time.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2012-03-12 09:13:31 -07:00
commit f7a0d426f3
253 changed files with 8202 additions and 4856 deletions

View File

@ -182,3 +182,14 @@ Description:
USB2 hardware LPM is enabled for the device. Developer can
write y/Y/1 or n/N/0 to the file to enable/disable the
feature.
What: /sys/bus/usb/devices/.../removable
Date: February 2012
Contact: Matthew Garrett <mjg@redhat.com>
Description:
Some information about whether a given USB device is
physically fixed to the platform can be inferred from a
combination of hub decriptor bits and platform-specific data
such as ACPI. This file will read either "removable" or
"fixed" if the information is available, and "unknown"
otherwise.

View File

@ -158,7 +158,7 @@ static int devboard_usbh1_hw_init(struct platform_device *pdev)
#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
#define USBH1_MODE IOMUX_TO_GPIO(MX31_PIN_NFALE)
static int devboard_isp1105_init(struct otg_transceiver *otg)
static int devboard_isp1105_init(struct usb_phy *otg)
{
int ret = gpio_request(USBH1_MODE, "usbh1-mode");
if (ret)
@ -177,7 +177,7 @@ static int devboard_isp1105_init(struct otg_transceiver *otg)
}
static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
static int devboard_isp1105_set_vbus(struct usb_otg *otg, bool on)
{
if (on)
gpio_set_value(USBH1_VBUSEN_B, 0);
@ -194,18 +194,24 @@ static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
static int __init devboard_usbh1_init(void)
{
struct otg_transceiver *otg;
struct usb_phy *phy;
struct platform_device *pdev;
otg = kzalloc(sizeof(*otg), GFP_KERNEL);
if (!otg)
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
if (!phy)
return -ENOMEM;
otg->label = "ISP1105";
otg->init = devboard_isp1105_init;
otg->set_vbus = devboard_isp1105_set_vbus;
phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
if (!phy->otg) {
kfree(phy);
return -ENOMEM;
}
usbh1_pdata.otg = otg;
phy->label = "ISP1105";
phy->init = devboard_isp1105_init;
phy->otg->set_vbus = devboard_isp1105_set_vbus;
usbh1_pdata.otg = phy;
pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
if (IS_ERR(pdev))

View File

@ -272,7 +272,7 @@ static int marxbot_usbh1_hw_init(struct platform_device *pdev)
#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
#define USBH1_MODE IOMUX_TO_GPIO(MX31_PIN_NFALE)
static int marxbot_isp1105_init(struct otg_transceiver *otg)
static int marxbot_isp1105_init(struct usb_phy *otg)
{
int ret = gpio_request(USBH1_MODE, "usbh1-mode");
if (ret)
@ -291,7 +291,7 @@ static int marxbot_isp1105_init(struct otg_transceiver *otg)
}
static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
static int marxbot_isp1105_set_vbus(struct usb_otg *otg, bool on)
{
if (on)
gpio_set_value(USBH1_VBUSEN_B, 0);
@ -308,18 +308,24 @@ static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
static int __init marxbot_usbh1_init(void)
{
struct otg_transceiver *otg;
struct usb_phy *phy;
struct platform_device *pdev;
otg = kzalloc(sizeof(*otg), GFP_KERNEL);
if (!otg)
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
if (!phy)
return -ENOMEM;
otg->label = "ISP1105";
otg->init = marxbot_isp1105_init;
otg->set_vbus = marxbot_isp1105_set_vbus;
phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
if (!phy->otg) {
kfree(phy);
return -ENOMEM;
}
usbh1_pdata.otg = otg;
phy->label = "ISP1105";
phy->init = marxbot_isp1105_init;
phy->otg->set_vbus = marxbot_isp1105_set_vbus;
usbh1_pdata.otg = phy;
pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
if (IS_ERR(pdev))

View File

@ -33,7 +33,7 @@ struct pxa3xx_u2d_ulpi {
struct clk *clk;
void __iomem *mmio_base;
struct otg_transceiver *otg;
struct usb_phy *otg;
unsigned int ulpi_mode;
};
@ -79,7 +79,7 @@ static int pxa310_ulpi_poll(void)
return -ETIMEDOUT;
}
static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
{
int err;
@ -98,7 +98,7 @@ static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
}
static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
{
if (pxa310_ulpi_get_phymode() != SYNCH) {
pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
@ -111,7 +111,7 @@ static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
return pxa310_ulpi_poll();
}
struct otg_io_access_ops pxa310_ulpi_access_ops = {
struct usb_phy_io_ops pxa310_ulpi_access_ops = {
.read = pxa310_ulpi_read,
.write = pxa310_ulpi_write,
};
@ -139,19 +139,19 @@ static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
pxa310_otg_transceiver_rtsm();
err = otg_init(u2d->otg);
err = usb_phy_init(u2d->otg);
if (err) {
pr_err("OTG transceiver init failed");
return err;
}
err = otg_set_vbus(u2d->otg, 1);
err = otg_set_vbus(u2d->otg->otg, 1);
if (err) {
pr_err("OTG transceiver VBUS set failed");
return err;
}
err = otg_set_host(u2d->otg, host);
err = otg_set_host(u2d->otg->otg, host);
if (err)
pr_err("OTG transceiver Host mode set failed");
@ -189,9 +189,9 @@ static void pxa310_stop_otg_hc(void)
{
pxa310_otg_transceiver_rtsm();
otg_set_host(u2d->otg, NULL);
otg_set_vbus(u2d->otg, 0);
otg_shutdown(u2d->otg);
otg_set_host(u2d->otg->otg, NULL);
otg_set_vbus(u2d->otg->otg, 0);
usb_phy_shutdown(u2d->otg);
}
static void pxa310_u2d_setup_otg_hc(void)

View File

@ -58,7 +58,7 @@ struct tegra_usb_phy {
struct clk *pad_clk;
enum tegra_usb_phy_mode mode;
void *config;
struct otg_transceiver *ulpi;
struct usb_phy *ulpi;
};
struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,

View File

@ -608,13 +608,13 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
writel(val, base + ULPI_TIMING_CTRL_1);
/* Fix VbusInvalid due to floating VBUS */
ret = otg_io_write(phy->ulpi, 0x40, 0x08);
ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
return ret;
}
ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
if (ret) {
pr_err("%s: ulpi write failed\n", __func__);
return ret;

View File

@ -44,7 +44,7 @@ struct mxc_usbh_platform_data {
int (*exit)(struct platform_device *pdev);
unsigned int portsc;
struct otg_transceiver *otg;
struct usb_phy *otg;
};
int mx51_initialize_usb_hw(int port, unsigned int flags);

View File

@ -2,15 +2,15 @@
#define __MACH_ULPI_H
#ifdef CONFIG_USB_ULPI
struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags);
struct usb_phy *imx_otg_ulpi_create(unsigned int flags);
#else
static inline struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
static inline struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
{
return NULL;
}
#endif
extern struct otg_io_access_ops mxc_ulpi_access_ops;
extern struct usb_phy_io_ops mxc_ulpi_access_ops;
#endif /* __MACH_ULPI_H */

View File

@ -58,7 +58,7 @@ static int ulpi_poll(void __iomem *view, u32 bit)
return -ETIMEDOUT;
}
static int ulpi_read(struct otg_transceiver *otg, u32 reg)
static int ulpi_read(struct usb_phy *otg, u32 reg)
{
int ret;
void __iomem *view = otg->io_priv;
@ -84,7 +84,7 @@ static int ulpi_read(struct otg_transceiver *otg, u32 reg)
return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
}
static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
static int ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
{
int ret;
void __iomem *view = otg->io_priv;
@ -106,13 +106,13 @@ static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
return ulpi_poll(view, ULPIVW_RUN);
}
struct otg_io_access_ops mxc_ulpi_access_ops = {
struct usb_phy_io_ops mxc_ulpi_access_ops = {
.read = ulpi_read,
.write = ulpi_write,
};
EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
{
return otg_ulpi_create(&mxc_ulpi_access_ops, flags);
}

View File

@ -117,43 +117,6 @@
#define UB_SENSE_SIZE 18
/*
*/
/* command block wrapper */
struct bulk_cb_wrap {
__le32 Signature; /* contains 'USBC' */
u32 Tag; /* unique per command id */
__le32 DataTransferLength; /* size of data */
u8 Flags; /* direction in bit 0 */
u8 Lun; /* LUN */
u8 Length; /* of of the CDB */
u8 CDB[UB_MAX_CDB_SIZE]; /* max command */
};
#define US_BULK_CB_WRAP_LEN 31
#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
#define US_BULK_FLAG_IN 1
#define US_BULK_FLAG_OUT 0
/* command status wrapper */
struct bulk_cs_wrap {
__le32 Signature; /* should = 'USBS' */
u32 Tag; /* same as original command */
__le32 Residue; /* amount not transferred */
u8 Status; /* see below */
};
#define US_BULK_CS_WRAP_LEN 13
#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
#define US_BULK_STAT_OK 0
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
/* bulk-only class specific requests */
#define US_BULK_RESET_REQUEST 0xff
#define US_BULK_GET_MAX_LUN 0xfe
/*
*/
struct ub_dev;

View File

@ -398,6 +398,27 @@ config USB_NET_KALMIA
To compile this driver as a module, choose M here: the
module will be called kalmia.
config USB_NET_QMI_WWAN
tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems"
depends on USB_USBNET
help
Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem
(MDM) chipsets. Examples of such devices are
* Huawei E392/E398
This driver will only drive the ethernet part of the chips.
The devices require additional configuration to be usable.
Multiple management interfaces with linux drivers are
available:
* option: AT commands on /dev/ttyUSBx
* cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx
A modem manager with support for QMI is recommended.
To compile this driver as a module, choose M here: the
module will be called qmi_wwan.
config USB_HSO
tristate "Option USB High Speed Mobile Devices"
depends on USB && RFKILL
@ -461,4 +482,5 @@ config USB_VL600
http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
endmenu

View File

@ -29,4 +29,5 @@ obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o
obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o
obj-$(CONFIG_USB_VL600) += lg-vl600.o
obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o

444
drivers/net/usb/qmi_wwan.c Normal file
View File

@ -0,0 +1,444 @@
/*
* Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc-wdm.h>
/* The name of the CDC Device Management driver */
#define DM_DRIVER "cdc_wdm"
/*
* This driver supports wwan (3G/LTE/?) devices using a vendor
* specific management protocol called Qualcomm MSM Interface (QMI) -
* in addition to the more common AT commands over serial interface
* management
*
* QMI is wrapped in CDC, using CDC encapsulated commands on the
* control ("master") interface of a two-interface CDC Union
* resembling standard CDC ECM. The devices do not use the control
* interface for any other CDC messages. Most likely because the
* management protocol is used in place of the standard CDC
* notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
*
* Handling a protocol like QMI is out of the scope for any driver.
* It can be exported as a character device using the cdc-wdm driver,
* which will enable userspace applications ("modem managers") to
* handle it. This may be required to use the network interface
* provided by the driver.
*
* These devices may alternatively/additionally be configured using AT
* commands on any of the serial interfaces driven by the option driver
*
* This driver binds only to the data ("slave") interface to enable
* the cdc-wdm driver to bind to the control interface. It still
* parses the CDC functional descriptors on the control interface to
* a) verify that this is indeed a handled interface (CDC Union
* header lists it as slave)
* b) get MAC address and other ethernet config from the CDC Ethernet
* header
* c) enable user bind requests against the control interface, which
* is the common way to bind to CDC Ethernet Control Model type
* interfaces
* d) provide a hint to the user about which interface is the
* corresponding management interface
*/
static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status = -1;
struct usb_interface *control = NULL;
u8 *buf = intf->cur_altsetting->extra;
int len = intf->cur_altsetting->extralen;
struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
struct usb_cdc_union_desc *cdc_union = NULL;
struct usb_cdc_ether_desc *cdc_ether = NULL;
u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE;
u32 found = 0;
atomic_t *pmcount = (void *)&dev->data[1];
atomic_set(pmcount, 0);
/*
* assume a data interface has no additional descriptors and
* that the control and data interface are numbered
* consecutively - this holds for the Huawei device at least
*/
if (len == 0 && desc->bInterfaceNumber > 0) {
control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1);
if (!control)
goto err;
buf = control->cur_altsetting->extra;
len = control->cur_altsetting->extralen;
dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n",
dev_name(&control->dev));
}
while (len > 3) {
struct usb_descriptor_header *h = (void *)buf;
/* ignore any misplaced descriptors */
if (h->bDescriptorType != USB_DT_CS_INTERFACE)
goto next_desc;
/* buf[2] is CDC descriptor subtype */
switch (buf[2]) {
case USB_CDC_HEADER_TYPE:
if (found & 1 << USB_CDC_HEADER_TYPE) {
dev_dbg(&intf->dev, "extra CDC header\n");
goto err;
}
if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
dev_dbg(&intf->dev, "CDC header len %u\n", h->bLength);
goto err;
}
break;
case USB_CDC_UNION_TYPE:
if (found & 1 << USB_CDC_UNION_TYPE) {
dev_dbg(&intf->dev, "extra CDC union\n");
goto err;
}
if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
dev_dbg(&intf->dev, "CDC union len %u\n", h->bLength);
goto err;
}
cdc_union = (struct usb_cdc_union_desc *)buf;
break;
case USB_CDC_ETHERNET_TYPE:
if (found & 1 << USB_CDC_ETHERNET_TYPE) {
dev_dbg(&intf->dev, "extra CDC ether\n");
goto err;
}
if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
dev_dbg(&intf->dev, "CDC ether len %u\n", h->bLength);
goto err;
}
cdc_ether = (struct usb_cdc_ether_desc *)buf;
break;
}
/*
* Remember which CDC functional descriptors we've seen. Works
* for all types we care about, of which USB_CDC_ETHERNET_TYPE
* (0x0f) is the highest numbered
*/
if (buf[2] < 32)
found |= 1 << buf[2];
next_desc:
len -= h->bLength;
buf += h->bLength;
}
/* did we find all the required ones? */
if ((found & required) != required) {
dev_err(&intf->dev, "CDC functional descriptors missing\n");
goto err;
}
/* give the user a helpful hint if trying to bind to the wrong interface */
if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) {
dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n",
dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev));
goto err;
}
/* errors aren't fatal - we can live with the dynamic address */
if (cdc_ether) {
dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
}
/* success! point the user to the management interface */
if (control)
dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n",
dev_name(&control->dev));
/* XXX: add a sysfs symlink somewhere to help management applications find it? */
/* collect bulk endpoints now that we know intf == "data" interface */
status = usbnet_get_endpoints(dev, intf);
err:
return status;
}
/* using a counter to merge subdriver requests with our own into a combined state */
static int qmi_wwan_manage_power(struct usbnet *dev, int on)
{
atomic_t *pmcount = (void *)&dev->data[1];
int rv = 0;
dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on);
if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) {
/* need autopm_get/put here to ensure the usbcore sees the new value */
rv = usb_autopm_get_interface(dev->intf);
if (rv < 0)
goto err;
dev->intf->needs_remote_wakeup = on;
usb_autopm_put_interface(dev->intf);
}
err:
return rv;
}
static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
{
struct usbnet *dev = usb_get_intfdata(intf);
return qmi_wwan_manage_power(dev, on);
}
/* Some devices combine the "control" and "data" functions into a
* single interface with all three endpoints: interrupt + bulk in and
* out
*
* Setting up cdc-wdm as a subdriver owning the interrupt endpoint
* will let it provide userspace access to the encapsulated QMI
* protocol without interfering with the usbnet operations.
*/
static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
{
int rv;
struct usb_driver *subdriver = NULL;
atomic_t *pmcount = (void *)&dev->data[1];
atomic_set(pmcount, 0);
/* collect all three endpoints */
rv = usbnet_get_endpoints(dev, intf);
if (rv < 0)
goto err;
/* require interrupt endpoint for subdriver */
if (!dev->status) {
rv = -EINVAL;
goto err;
}
subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
if (IS_ERR(subdriver)) {
rv = PTR_ERR(subdriver);
goto err;
}
/* can't let usbnet use the interrupt endpoint */
dev->status = NULL;
/* save subdriver struct for suspend/resume wrappers */
dev->data[0] = (unsigned long)subdriver;
err:
return rv;
}
/* Gobi devices uses identical class/protocol codes for all interfaces regardless
* of function. Some of these are CDC ACM like and have the exact same endpoints
* we are looking for. This leaves two possible strategies for identifying the
* correct interface:
* a) hardcoding interface number, or
* b) use the fact that the wwan interface is the only one lacking additional
* (CDC functional) descriptors
*
* Let's see if we can get away with the generic b) solution.
*/
static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf)
{
int rv = -EINVAL;
/* ignore any interface with additional descriptors */
if (intf->cur_altsetting->extralen)
goto err;
rv = qmi_wwan_bind_shared(dev, intf);
err:
return rv;
}
static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf)
{
struct usb_driver *subdriver = (void *)dev->data[0];
if (subdriver && subdriver->disconnect)
subdriver->disconnect(intf);
dev->data[0] = (unsigned long)NULL;
}
/* suspend/resume wrappers calling both usbnet and the cdc-wdm
* subdriver if present.
*
* NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
* wrappers for those without adding usbnet reset support first.
*/
static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
struct usb_driver *subdriver = (void *)dev->data[0];
int ret;
ret = usbnet_suspend(intf, message);
if (ret < 0)
goto err;
if (subdriver && subdriver->suspend)
ret = subdriver->suspend(intf, message);
if (ret < 0)
usbnet_resume(intf);
err:
return ret;
}
static int qmi_wwan_resume(struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
struct usb_driver *subdriver = (void *)dev->data[0];
int ret = 0;
if (subdriver && subdriver->resume)
ret = subdriver->resume(intf);
if (ret < 0)
goto err;
ret = usbnet_resume(intf);
if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend)
subdriver->suspend(intf, PMSG_SUSPEND);
err:
return ret;
}
static const struct driver_info qmi_wwan_info = {
.description = "QMI speaking wwan device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind,
.manage_power = qmi_wwan_manage_power,
};
static const struct driver_info qmi_wwan_shared = {
.description = "QMI speaking wwan device with combined interface",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind_shared,
.manage_power = qmi_wwan_manage_power,
};
static const struct driver_info qmi_wwan_gobi = {
.description = "Qualcomm Gobi wwan/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_gobi,
.unbind = qmi_wwan_unbind_shared,
.manage_power = qmi_wwan_manage_power,
};
#define HUAWEI_VENDOR_ID 0x12D1
#define QMI_GOBI_DEVICE(vend, prod) \
USB_DEVICE(vend, prod), \
.driver_info = (unsigned long)&qmi_wwan_gobi
static const struct usb_device_id products[] = {
{ /* Huawei E392, E398 and possibly others sharing both device id and more... */
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
.driver_info = (unsigned long)&qmi_wwan_info,
},
{ /* Huawei E392, E398 and possibly others in "Windows mode"
* using a combined control and data interface without any CDC
* functional descriptors
*/
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 17,
.driver_info = (unsigned long)&qmi_wwan_shared,
},
{ /* Pantech UML290 */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x106c,
.idProduct = 0x3718,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xf0,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_shared,
},
{QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
{QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
{QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
{QMI_GOBI_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */
{QMI_GOBI_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */
{QMI_GOBI_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */
{QMI_GOBI_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */
{QMI_GOBI_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
{QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
{QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
{QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */
{QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */
{QMI_GOBI_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9004)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9005)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9006)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9007)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */
{QMI_GOBI_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
{QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */
{QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
{QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
{ } /* END */
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver qmi_wwan_driver = {
.name = "qmi_wwan",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = qmi_wwan_suspend,
.resume = qmi_wwan_resume,
.reset_resume = qmi_wwan_resume,
.supports_autosuspend = 1,
};
static int __init qmi_wwan_init(void)
{
return usb_register(&qmi_wwan_driver);
}
module_init(qmi_wwan_init);
static void __exit qmi_wwan_exit(void)
{
usb_deregister(&qmi_wwan_driver);
}
module_exit(qmi_wwan_exit);
MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
MODULE_LICENSE("GPL");

View File

@ -56,7 +56,7 @@ static u16 isp170x_id[] = {
struct isp1704_charger {
struct device *dev;
struct power_supply psy;
struct otg_transceiver *otg;
struct usb_phy *phy;
struct notifier_block nb;
struct work_struct work;
@ -71,6 +71,16 @@ struct isp1704_charger {
unsigned max_power;
};
static inline int isp1704_read(struct isp1704_charger *isp, u32 reg)
{
return usb_phy_io_read(isp->phy, reg);
}
static inline int isp1704_write(struct isp1704_charger *isp, u32 val, u32 reg)
{
return usb_phy_io_write(isp->phy, val, reg);
}
/*
* Disable/enable the power from the isp1704 if a function for it
* has been provided with platform data.
@ -97,31 +107,31 @@ static inline int isp1704_charger_type(struct isp1704_charger *isp)
u8 otg_ctrl;
int type = POWER_SUPPLY_TYPE_USB_DCP;
func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
func_ctrl = isp1704_read(isp, ULPI_FUNC_CTRL);
otg_ctrl = isp1704_read(isp, ULPI_OTG_CTRL);
/* disable pulldowns */
reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), reg);
/* full speed */
otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
ULPI_FUNC_CTRL_XCVRSEL_MASK);
otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL),
ULPI_FUNC_CTRL_FULL_SPEED);
/* Enable strong pull-up on DP (1.5K) and reset */
reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), reg);
usleep_range(1000, 2000);
reg = otg_io_read(isp->otg, ULPI_DEBUG);
reg = isp1704_read(isp, ULPI_DEBUG);
if ((reg & 3) != 3)
type = POWER_SUPPLY_TYPE_USB_CDP;
/* recover original state */
otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
isp1704_write(isp, ULPI_FUNC_CTRL, func_ctrl);
isp1704_write(isp, ULPI_OTG_CTRL, otg_ctrl);
return type;
}
@ -136,28 +146,28 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
u8 r;
/* Reset the transceiver */
r = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
r = isp1704_read(isp, ULPI_FUNC_CTRL);
r |= ULPI_FUNC_CTRL_RESET;
otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
isp1704_write(isp, ULPI_FUNC_CTRL, r);
usleep_range(1000, 2000);
/* Set normal mode */
r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK);
otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
isp1704_write(isp, ULPI_FUNC_CTRL, r);
/* Clear the DP and DM pull-down bits */
r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN;
otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r);
isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), r);
/* Enable strong pull-up on DP (1.5K) and reset */
r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r);
isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), r);
usleep_range(1000, 2000);
/* Read the line state */
if (!otg_io_read(isp->otg, ULPI_DEBUG)) {
if (!isp1704_read(isp, ULPI_DEBUG)) {
/* Disable strong pull-up on DP (1.5K) */
otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
ULPI_FUNC_CTRL_TERMSELECT);
return 1;
}
@ -165,23 +175,23 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
/* Is it a charger or PS/2 connection */
/* Enable weak pull-up resistor on DP */
otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
ISP1704_PWR_CTRL_DP_WKPU_EN);
/* Disable strong pull-up on DP (1.5K) */
otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
ULPI_FUNC_CTRL_TERMSELECT);
/* Enable weak pull-down resistor on DM */
otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL),
isp1704_write(isp, ULPI_SET(ULPI_OTG_CTRL),
ULPI_OTG_CTRL_DM_PULLDOWN);
/* It's a charger if the line states are clear */
if (!(otg_io_read(isp->otg, ULPI_DEBUG)))
if (!(isp1704_read(isp, ULPI_DEBUG)))
ret = 1;
/* Disable weak pull-up resistor on DP */
otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL),
isp1704_write(isp, ULPI_CLR(ISP1704_PWR_CTRL),
ISP1704_PWR_CTRL_DP_WKPU_EN);
return ret;
@ -193,14 +203,14 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
u8 pwr_ctrl;
int ret = 0;
pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
pwr_ctrl = isp1704_read(isp, ISP1704_PWR_CTRL);
/* set SW control bit in PWR_CTRL register */
otg_io_write(isp->otg, ISP1704_PWR_CTRL,
isp1704_write(isp, ISP1704_PWR_CTRL,
ISP1704_PWR_CTRL_SWCTRL);
/* enable manual charger detection */
otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
ISP1704_PWR_CTRL_SWCTRL
| ISP1704_PWR_CTRL_DPVSRC_EN);
usleep_range(1000, 2000);
@ -208,7 +218,7 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
timeout = jiffies + msecs_to_jiffies(300);
do {
/* Check if there is a charger */
if (otg_io_read(isp->otg, ISP1704_PWR_CTRL)
if (isp1704_read(isp, ISP1704_PWR_CTRL)
& ISP1704_PWR_CTRL_VDAT_DET) {
ret = isp1704_charger_verify(isp);
break;
@ -216,7 +226,7 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
} while (!time_after(jiffies, timeout) && isp->online);
/* recover original state */
otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
isp1704_write(isp, ISP1704_PWR_CTRL, pwr_ctrl);
return ret;
}
@ -264,8 +274,8 @@ static void isp1704_charger_work(struct work_struct *data)
case POWER_SUPPLY_TYPE_USB:
default:
/* enable data pullups */
if (isp->otg->gadget)
usb_gadget_connect(isp->otg->gadget);
if (isp->phy->otg->gadget)
usb_gadget_connect(isp->phy->otg->gadget);
}
break;
case USB_EVENT_NONE:
@ -283,8 +293,8 @@ static void isp1704_charger_work(struct work_struct *data)
* chargers. The pullups may be enabled elsewhere, so this can
* not be the final solution.
*/
if (isp->otg->gadget)
usb_gadget_disconnect(isp->otg->gadget);
if (isp->phy->otg->gadget)
usb_gadget_disconnect(isp->phy->otg->gadget);
isp1704_charger_set_power(isp, 0);
break;
@ -364,11 +374,11 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
int ret = -ENODEV;
/* Test ULPI interface */
ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa);
ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa);
if (ret < 0)
return ret;
ret = otg_io_read(isp->otg, ULPI_SCRATCH);
ret = isp1704_read(isp, ULPI_SCRATCH);
if (ret < 0)
return ret;
@ -376,13 +386,13 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
return -ENODEV;
/* Verify the product and vendor id matches */
vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW);
vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8;
vendor = isp1704_read(isp, ULPI_VENDOR_ID_LOW);
vendor |= isp1704_read(isp, ULPI_VENDOR_ID_HIGH) << 8;
if (vendor != NXP_VENDOR_ID)
return -ENODEV;
product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW);
product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8;
product = isp1704_read(isp, ULPI_PRODUCT_ID_LOW);
product |= isp1704_read(isp, ULPI_PRODUCT_ID_HIGH) << 8;
for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) {
if (product == isp170x_id[i]) {
@ -405,8 +415,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
if (!isp)
return -ENOMEM;
isp->otg = otg_get_transceiver();
if (!isp->otg)
isp->phy = usb_get_transceiver();
if (!isp->phy)
goto fail0;
isp->dev = &pdev->dev;
@ -429,14 +439,14 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
goto fail1;
/*
* REVISIT: using work in order to allow the otg notifications to be
* REVISIT: using work in order to allow the usb notifications to be
* made atomically in the future.
*/
INIT_WORK(&isp->work, isp1704_charger_work);
isp->nb.notifier_call = isp1704_notifier_call;
ret = otg_register_notifier(isp->otg, &isp->nb);
ret = usb_register_notifier(isp->phy, &isp->nb);
if (ret)
goto fail2;
@ -449,13 +459,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
* enumerated. The charger driver should be always loaded before any
* gadget is loaded.
*/
if (isp->otg->gadget)
usb_gadget_disconnect(isp->otg->gadget);
if (isp->phy->otg->gadget)
usb_gadget_disconnect(isp->phy->otg->gadget);
/* Detect charger if VBUS is valid (the cable was already plugged). */
ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
ret = isp1704_read(isp, ULPI_USB_INT_STS);
isp1704_charger_set_power(isp, 0);
if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
if ((ret & ULPI_INT_VBUS_VALID) && !isp->phy->otg->default_a) {
isp->event = USB_EVENT_VBUS;
schedule_work(&isp->work);
}
@ -464,7 +474,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
fail2:
power_supply_unregister(&isp->psy);
fail1:
otg_put_transceiver(isp->otg);
usb_put_transceiver(isp->phy);
fail0:
kfree(isp);
@ -477,9 +487,9 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
{
struct isp1704_charger *isp = platform_get_drvdata(pdev);
otg_unregister_notifier(isp->otg, &isp->nb);
usb_unregister_notifier(isp->phy, &isp->nb);
power_supply_unregister(&isp->psy);
otg_put_transceiver(isp->otg);
usb_put_transceiver(isp->phy);
isp1704_charger_set_power(isp, 0);
kfree(isp);

View File

@ -40,7 +40,7 @@ static struct timer_list polling_timer;
static int polling;
#ifdef CONFIG_USB_OTG_UTILS
static struct otg_transceiver *transceiver;
static struct usb_phy *transceiver;
static struct notifier_block otg_nb;
#endif
@ -321,7 +321,7 @@ static int pda_power_probe(struct platform_device *pdev)
}
#ifdef CONFIG_USB_OTG_UTILS
transceiver = otg_get_transceiver();
transceiver = usb_get_transceiver();
if (transceiver && !pdata->is_usb_online) {
pdata->is_usb_online = otg_is_usb_online;
}
@ -375,7 +375,7 @@ static int pda_power_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG_UTILS
if (transceiver && pdata->use_otg_notifier) {
otg_nb.notifier_call = otg_handle_notification;
ret = otg_register_notifier(transceiver, &otg_nb);
ret = usb_register_notifier(transceiver, &otg_nb);
if (ret) {
dev_err(dev, "failure to register otg notifier\n");
goto otg_reg_notifier_failed;
@ -409,7 +409,7 @@ usb_supply_failed:
free_irq(ac_irq->start, &pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS
if (transceiver)
otg_put_transceiver(transceiver);
usb_put_transceiver(transceiver);
#endif
ac_irq_failed:
if (pdata->is_ac_online)
@ -444,7 +444,7 @@ static int pda_power_remove(struct platform_device *pdev)
power_supply_unregister(&pda_psy_ac);
#ifdef CONFIG_USB_OTG_UTILS
if (transceiver)
otg_put_transceiver(transceiver);
usb_put_transceiver(transceiver);
#endif
if (ac_draw) {
regulator_put(ac_draw);

View File

@ -69,8 +69,8 @@ struct twl4030_bci {
struct device *dev;
struct power_supply ac;
struct power_supply usb;
struct otg_transceiver *transceiver;
struct notifier_block otg_nb;
struct usb_phy *transceiver;
struct notifier_block usb_nb;
struct work_struct work;
int irq_chg;
int irq_bci;
@ -279,7 +279,7 @@ static void twl4030_bci_usb_work(struct work_struct *data)
static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
void *priv)
{
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, usb_nb);
dev_dbg(bci->dev, "OTG notify %lu\n", val);
@ -479,10 +479,10 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
INIT_WORK(&bci->work, twl4030_bci_usb_work);
bci->transceiver = otg_get_transceiver();
bci->transceiver = usb_get_transceiver();
if (bci->transceiver != NULL) {
bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
otg_register_notifier(bci->transceiver, &bci->otg_nb);
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
usb_register_notifier(bci->transceiver, &bci->usb_nb);
}
/* Enable interrupts now. */
@ -508,8 +508,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
fail_unmask_interrupts:
if (bci->transceiver != NULL) {
otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
otg_put_transceiver(bci->transceiver);
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_transceiver(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
fail_bci_irq:
@ -539,8 +539,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
TWL4030_INTERRUPTS_BCIIMR2A);
if (bci->transceiver != NULL) {
otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
otg_put_transceiver(bci->transceiver);
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_transceiver(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
free_irq(bci->irq_chg, bci);

View File

@ -1295,6 +1295,7 @@ EXPORT_SYMBOL(int_to_scsilun);
* LUNs even if it's older than SCSI-3.
* If BLIST_NOREPORTLUN is set, return 1 always.
* If BLIST_NOLUN is set, return 0 always.
* If starget->no_report_luns is set, return 1 always.
*
* Return:
* 0: scan completed (or no memory, so further scanning is futile)
@ -1321,6 +1322,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
* Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
* support more than 8 LUNs.
* Don't attempt if the target doesn't support REPORT LUNS.
*/
if (bflags & BLIST_NOREPORTLUN)
return 1;
@ -1332,6 +1334,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
return 1;
if (bflags & BLIST_NOLUN)
return 0;
if (starget->no_report_luns)
return 1;
if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
sdev = scsi_alloc_sdev(starget, 0, NULL);

View File

@ -2349,7 +2349,7 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
* some USB ones crash on receiving them, and the pages
* we currently ask for are for SPC-3 and beyond
*/
if (sdp->scsi_level > SCSI_SPC_2)
if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
return 1;
return 0;
}

View File

@ -3,43 +3,6 @@
#include <linux/blkdev.h>
/* Bulk only data structures */
/* command block wrapper */
struct bulk_cb_wrap {
__le32 Signature; /* contains 'USBC' */
__u32 Tag; /* unique per command id */
__le32 DataTransferLength; /* size of data */
__u8 Flags; /* direction in bit 0 */
__u8 Lun; /* LUN normally 0 */
__u8 Length; /* of of the CDB */
__u8 CDB[16]; /* max command */
};
#define US_BULK_CB_WRAP_LEN 31
#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
#define US_BULK_FLAG_IN 1
#define US_BULK_FLAG_OUT 0
/* command status wrapper */
struct bulk_cs_wrap {
__le32 Signature; /* should = 'USBS' */
__u32 Tag; /* same as original command */
__le32 Residue; /* amount not transferred */
__u8 Status; /* see below */
__u8 Filler[18];
};
#define US_BULK_CS_WRAP_LEN 13
#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
#define US_BULK_STAT_OK 0
#define US_BULK_STAT_FAIL 1
#define US_BULK_STAT_PHASE 2
/* bulk-only class specific requests */
#define US_BULK_RESET_REQUEST 0xff
#define US_BULK_GET_MAX_LUN 0xfe
/* usb_stor_bulk_transfer_xxx() return codes, in order of severity */
#define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */

View File

@ -135,7 +135,6 @@ static struct usb_driver quausb2_usb_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = quausb2_id_table,
.no_dynamic_id = 1,
};
/**
@ -1942,7 +1941,6 @@ static struct usb_serial_driver quatech2_device = {
.name = "quatech_usb2",
},
.description = DRIVER_DESC,
.usb_driver = &quausb2_usb_driver,
.id_table = quausb2_id_table,
.num_ports = 8,
.open = qt2_open,
@ -1964,41 +1962,11 @@ static struct usb_serial_driver quatech2_device = {
.write_bulk_callback = qt2_write_bulk_callback,
};
static int __init quausb2_usb_init(void)
{
int retval;
static struct usb_serial_driver * const serial_drivers[] = {
&quatech2_device, NULL
};
dbg("%s\n", __func__);
/* register with usb-serial */
retval = usb_serial_register(&quatech2_device);
if (retval)
goto failed_usb_serial_register;
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
/* register with usb */
retval = usb_register(&quausb2_usb_driver);
if (retval == 0)
return 0;
/* if we're here, usb_register() failed */
usb_serial_deregister(&quatech2_device);
failed_usb_serial_register:
return retval;
}
static void __exit quausb2_usb_exit(void)
{
usb_deregister(&quausb2_usb_driver);
usb_serial_deregister(&quatech2_device);
}
module_init(quausb2_usb_init);
module_exit(quausb2_usb_exit);
module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -200,7 +200,6 @@ static struct usb_driver serqt_usb_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = serqt_id_table,
.no_dynamic_id = 1,
};
static int port_paranoia_check(struct usb_serial_port *port,
@ -1590,7 +1589,6 @@ static struct usb_serial_driver quatech_device = {
.name = "serqt",
},
.description = DRIVER_DESC,
.usb_driver = &serqt_usb_driver,
.id_table = serqt_id_table,
.num_ports = 8,
.open = qt_open,
@ -1610,41 +1608,11 @@ static struct usb_serial_driver quatech_device = {
.release = qt_release,
};
static int __init serqt_usb_init(void)
{
int retval;
static struct usb_serial_driver * const serial_drivers[] = {
&quatech_device, NULL
};
dbg("%s\n", __func__);
/* register with usb-serial */
retval = usb_serial_register(&quatech_device);
if (retval)
goto failed_usb_serial_register;
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
/* register with usb */
retval = usb_register(&serqt_usb_driver);
if (retval == 0)
return 0;
/* if we're here, usb_register() failed */
usb_serial_deregister(&quatech_device);
failed_usb_serial_register:
return retval;
}
static void __exit serqt_usb_exit(void)
{
usb_deregister(&serqt_usb_driver);
usb_serial_deregister(&quatech_device);
}
module_init(serqt_usb_init);
module_exit(serqt_usb_exit);
module_usb_serial_driver(serqt_usb_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI
default y if MICROBLAZE
default y if SPARC_LEON
default y if ARCH_MMP
default y if MACH_LOONGSON1
default PCI
# some non-PCI HCDs implement xHCI

View File

@ -39,6 +39,7 @@
#include <linux/serial.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
@ -773,10 +774,37 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
return acm_set_control(acm, acm->ctrlout = newctrl);
}
static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
{
struct serial_struct tmp;
if (!info)
return -EINVAL;
memset(&tmp, 0, sizeof(tmp));
tmp.flags = ASYNC_LOW_LATENCY;
tmp.xmit_fifo_size = acm->writesize;
tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
if (copy_to_user(info, &tmp, sizeof(tmp)))
return -EFAULT;
else
return 0;
}
static int acm_tty_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
struct acm *acm = tty->driver_data;
int rv = -ENOIOCTLCMD;
switch (cmd) {
case TIOCGSERIAL: /* gets serial port data */
rv = get_serial_info(acm, (struct serial_struct __user *) arg);
break;
}
return rv;
}
static const __u32 acm_tty_speed[] = {

View File

@ -23,6 +23,7 @@
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/usb/cdc-wdm.h>
/*
* Version Information
@ -31,6 +32,8 @@
#define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
#define HUAWEI_VENDOR_ID 0x12D1
static const struct usb_device_id wdm_ids[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@ -38,6 +41,20 @@ static const struct usb_device_id wdm_ids[] = {
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
},
{
/*
* Huawei E392, E398 and possibly other Qualcomm based modems
* embed the Qualcomm QMI protocol inside CDC on CDC ECM like
* control interfaces. Userspace access to this is required
* to configure the accompanying data interface
*/
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
},
{ }
};
@ -54,6 +71,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_MAX 16
@ -61,6 +79,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_DEFAULT_BUFSIZE 256
static DEFINE_MUTEX(wdm_mutex);
static DEFINE_SPINLOCK(wdm_device_list_lock);
static LIST_HEAD(wdm_device_list);
/* --- method tables --- */
@ -82,7 +102,6 @@ struct wdm_device {
u16 bufsize;
u16 wMaxCommand;
u16 wMaxPacketSize;
u16 bMaxPacketSize0;
__le16 inum;
int reslength;
int length;
@ -96,10 +115,40 @@ struct wdm_device {
struct work_struct rxwork;
int werr;
int rerr;
struct list_head device_list;
int (*manage_power)(struct usb_interface *, int);
};
static struct usb_driver wdm_driver;
/* return intfdata if we own the interface, else look up intf in the list */
static struct wdm_device *wdm_find_device(struct usb_interface *intf)
{
struct wdm_device *desc = NULL;
spin_lock(&wdm_device_list_lock);
list_for_each_entry(desc, &wdm_device_list, device_list)
if (desc->intf == intf)
break;
spin_unlock(&wdm_device_list_lock);
return desc;
}
static struct wdm_device *wdm_find_device_by_minor(int minor)
{
struct wdm_device *desc = NULL;
spin_lock(&wdm_device_list_lock);
list_for_each_entry(desc, &wdm_device_list, device_list)
if (desc->intf->minor == minor)
break;
spin_unlock(&wdm_device_list_lock);
return desc;
}
/* --- callbacks --- */
static void wdm_out_callback(struct urb *urb)
{
@ -162,11 +211,9 @@ static void wdm_int_callback(struct urb *urb)
int rv = 0;
int status = urb->status;
struct wdm_device *desc;
struct usb_ctrlrequest *req;
struct usb_cdc_notification *dr;
desc = urb->context;
req = desc->irq;
dr = (struct usb_cdc_notification *)desc->sbuf;
if (status) {
@ -213,24 +260,6 @@ static void wdm_int_callback(struct urb *urb)
goto exit;
}
req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
req->wValue = 0;
req->wIndex = desc->inum;
req->wLength = cpu_to_le16(desc->wMaxCommand);
usb_fill_control_urb(
desc->response,
interface_to_usbdev(desc->intf),
/* using common endpoint 0 */
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
(unsigned char *)req,
desc->inbuf,
desc->wMaxCommand,
wdm_in_callback,
desc
);
desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags);
@ -279,14 +308,11 @@ static void free_urbs(struct wdm_device *desc)
static void cleanup(struct wdm_device *desc)
{
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->wMaxPacketSize,
desc->sbuf,
desc->validity->transfer_dma);
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->bMaxPacketSize0,
desc->inbuf,
desc->response->transfer_dma);
spin_lock(&wdm_device_list_lock);
list_del(&desc->device_list);
spin_unlock(&wdm_device_list_lock);
kfree(desc->sbuf);
kfree(desc->inbuf);
kfree(desc->orq);
kfree(desc->irq);
kfree(desc->ubuf);
@ -351,6 +377,10 @@ static ssize_t wdm_write
else
if (test_bit(WDM_IN_USE, &desc->flags))
r = -EAGAIN;
if (test_bit(WDM_RESETTING, &desc->flags))
r = -EIO;
if (r < 0) {
kfree(buf);
goto out;
@ -397,7 +427,7 @@ outnl:
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
int rv, cntr = 0;
int rv, cntr;
int i = 0;
struct wdm_device *desc = file->private_data;
@ -406,7 +436,8 @@ static ssize_t wdm_read
if (rv < 0)
return -ERESTARTSYS;
if (desc->length == 0) {
cntr = ACCESS_ONCE(desc->length);
if (cntr == 0) {
desc->read = 0;
retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
@ -430,6 +461,10 @@ retry:
rv = -ENODEV;
goto err;
}
if (test_bit(WDM_RESETTING, &desc->flags)) {
rv = -EIO;
goto err;
}
usb_mark_last_busy(interface_to_usbdev(desc->intf));
if (rv < 0) {
rv = -ERESTARTSYS;
@ -456,26 +491,30 @@ retry:
spin_unlock_irq(&desc->iuspin);
goto retry;
}
clear_bit(WDM_READ, &desc->flags);
cntr = desc->length;
spin_unlock_irq(&desc->iuspin);
}
cntr = count > desc->length ? desc->length : count;
if (cntr > count)
cntr = count;
rv = copy_to_user(buffer, desc->ubuf, cntr);
if (rv > 0) {
rv = -EFAULT;
goto err;
}
spin_lock_irq(&desc->iuspin);
for (i = 0; i < desc->length - cntr; i++)
desc->ubuf[i] = desc->ubuf[i + cntr];
spin_lock_irq(&desc->iuspin);
desc->length -= cntr;
spin_unlock_irq(&desc->iuspin);
/* in case we had outstanding data */
if (!desc->length)
clear_bit(WDM_READ, &desc->flags);
spin_unlock_irq(&desc->iuspin);
rv = cntr;
err:
@ -529,11 +568,11 @@ static int wdm_open(struct inode *inode, struct file *file)
struct wdm_device *desc;
mutex_lock(&wdm_mutex);
intf = usb_find_interface(&wdm_driver, minor);
if (!intf)
desc = wdm_find_device_by_minor(minor);
if (!desc)
goto out;
desc = usb_get_intfdata(intf);
intf = desc->intf;
if (test_bit(WDM_DISCONNECTING, &desc->flags))
goto out;
file->private_data = desc;
@ -543,7 +582,6 @@ static int wdm_open(struct inode *inode, struct file *file)
dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
goto out;
}
intf->needs_remote_wakeup = 1;
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
@ -560,6 +598,8 @@ static int wdm_open(struct inode *inode, struct file *file)
rv = 0;
}
mutex_unlock(&desc->wlock);
if (desc->count == 1)
desc->manage_power(intf, 1);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
@ -581,7 +621,7 @@ static int wdm_release(struct inode *inode, struct file *file)
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
kill_urbs(desc);
if (!test_bit(WDM_DISCONNECTING, &desc->flags))
desc->intf->needs_remote_wakeup = 0;
desc->manage_power(desc->intf, 0);
}
mutex_unlock(&wdm_mutex);
return 0;
@ -628,71 +668,31 @@ static void wdm_rxwork(struct work_struct *work)
/* --- hotplug --- */
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
u16 bufsize, int (*manage_power)(struct usb_interface *, int))
{
int rv = -EINVAL;
struct usb_device *udev = interface_to_usbdev(intf);
int rv = -ENOMEM;
struct wdm_device *desc;
struct usb_host_interface *iface;
struct usb_endpoint_descriptor *ep;
struct usb_cdc_dmm_desc *dmhd;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
u16 maxcom = WDM_DEFAULT_BUFSIZE;
if (!buffer)
goto out;
while (buflen > 2) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer [2]) {
case USB_CDC_HEADER_TYPE:
break;
case USB_CDC_DMM_TYPE:
dmhd = (struct usb_cdc_dmm_desc *)buffer;
maxcom = le16_to_cpu(dmhd->wMaxCommand);
dev_dbg(&intf->dev,
"Finding maximum buffer length: %d", maxcom);
break;
default:
dev_err(&intf->dev,
"Ignoring extra header, type %d, length %d\n",
buffer[2], buffer[0]);
break;
}
next_desc:
buflen -= buffer[0];
buffer += buffer[0];
}
rv = -ENOMEM;
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
INIT_LIST_HEAD(&desc->device_list);
mutex_init(&desc->rlock);
mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
desc->wMaxCommand = maxcom;
desc->wMaxCommand = bufsize;
/* this will be expanded and needed in hardware endianness */
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
desc->intf = intf;
INIT_WORK(&desc->rxwork, wdm_rxwork);
rv = -EINVAL;
iface = intf->cur_altsetting;
if (iface->desc.bNumEndpoints != 1)
goto err;
ep = &iface->endpoint[0].desc;
if (!ep || !usb_endpoint_is_int_in(ep))
if (!usb_endpoint_is_int_in(ep))
goto err;
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!desc->orq)
@ -717,19 +717,13 @@ next_desc:
if (!desc->ubuf)
goto err;
desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
desc->wMaxPacketSize,
GFP_KERNEL,
&desc->validity->transfer_dma);
desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
if (!desc->sbuf)
goto err;
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
desc->wMaxCommand,
GFP_KERNEL,
&desc->response->transfer_dma);
desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
if (!desc->inbuf)
goto err2;
goto err;
usb_fill_int_urb(
desc->validity,
@ -741,45 +735,149 @@ next_desc:
desc,
ep->bInterval
);
desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_set_intfdata(intf, desc);
desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
desc->irq->wValue = 0;
desc->irq->wIndex = desc->inum;
desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
usb_fill_control_urb(
desc->response,
interface_to_usbdev(intf),
/* using common endpoint 0 */
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
(unsigned char *)desc->irq,
desc->inbuf,
desc->wMaxCommand,
wdm_in_callback,
desc
);
desc->manage_power = manage_power;
spin_lock(&wdm_device_list_lock);
list_add(&desc->device_list, &wdm_device_list);
spin_unlock(&wdm_device_list_lock);
rv = usb_register_dev(intf, &wdm_class);
if (rv < 0)
goto err3;
goto err;
else
dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
intf->minor - WDM_MINOR_BASE);
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
out:
return rv;
err3:
usb_set_intfdata(intf, NULL);
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->bMaxPacketSize0,
desc->inbuf,
desc->response->transfer_dma);
err2:
usb_free_coherent(interface_to_usbdev(desc->intf),
desc->wMaxPacketSize,
desc->sbuf,
desc->validity->transfer_dma);
err:
free_urbs(desc);
kfree(desc->ubuf);
kfree(desc->orq);
kfree(desc->irq);
kfree(desc);
cleanup(desc);
return rv;
}
static int wdm_manage_power(struct usb_interface *intf, int on)
{
/* need autopm_get/put here to ensure the usbcore sees the new value */
int rv = usb_autopm_get_interface(intf);
if (rv < 0)
goto err;
intf->needs_remote_wakeup = on;
usb_autopm_put_interface(intf);
err:
return rv;
}
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int rv = -EINVAL;
struct usb_host_interface *iface;
struct usb_endpoint_descriptor *ep;
struct usb_cdc_dmm_desc *dmhd;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
u16 maxcom = WDM_DEFAULT_BUFSIZE;
if (!buffer)
goto err;
while (buflen > 2) {
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_HEADER_TYPE:
break;
case USB_CDC_DMM_TYPE:
dmhd = (struct usb_cdc_dmm_desc *)buffer;
maxcom = le16_to_cpu(dmhd->wMaxCommand);
dev_dbg(&intf->dev,
"Finding maximum buffer length: %d", maxcom);
break;
default:
dev_err(&intf->dev,
"Ignoring extra header, type %d, length %d\n",
buffer[2], buffer[0]);
break;
}
next_desc:
buflen -= buffer[0];
buffer += buffer[0];
}
iface = intf->cur_altsetting;
if (iface->desc.bNumEndpoints != 1)
goto err;
ep = &iface->endpoint[0].desc;
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
err:
return rv;
}
/**
* usb_cdc_wdm_register - register a WDM subdriver
* @intf: usb interface the subdriver will associate with
* @ep: interrupt endpoint to monitor for notifications
* @bufsize: maximum message size to support for read/write
*
* Create WDM usb class character device and associate it with intf
* without binding, allowing another driver to manage the interface.
*
* The subdriver will manage the given interrupt endpoint exclusively
* and will issue control requests referring to the given intf. It
* will otherwise avoid interferring, and in particular not do
* usb_set_intfdata/usb_get_intfdata on intf.
*
* The return value is a pointer to the subdriver's struct usb_driver.
* The registering driver is responsible for calling this subdriver's
* disconnect, suspend, resume, pre_reset and post_reset methods from
* its own.
*/
struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
int bufsize,
int (*manage_power)(struct usb_interface *, int))
{
int rv = -EINVAL;
rv = wdm_create(intf, ep, bufsize, manage_power);
if (rv < 0)
goto err;
return &wdm_driver;
err:
return ERR_PTR(rv);
}
EXPORT_SYMBOL(usb_cdc_wdm_register);
static void wdm_disconnect(struct usb_interface *intf)
{
struct wdm_device *desc;
unsigned long flags;
usb_deregister_dev(intf, &wdm_class);
desc = wdm_find_device(intf);
mutex_lock(&wdm_mutex);
desc = usb_get_intfdata(intf);
/* the spinlock makes sure no new urbs are generated in the callbacks */
spin_lock_irqsave(&desc->iuspin, flags);
@ -803,7 +901,7 @@ static void wdm_disconnect(struct usb_interface *intf)
#ifdef CONFIG_PM
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
{
struct wdm_device *desc = usb_get_intfdata(intf);
struct wdm_device *desc = wdm_find_device(intf);
int rv = 0;
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
@ -853,7 +951,7 @@ static int recover_from_urb_loss(struct wdm_device *desc)
#ifdef CONFIG_PM
static int wdm_resume(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
struct wdm_device *desc = wdm_find_device(intf);
int rv;
dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
@ -867,11 +965,7 @@ static int wdm_resume(struct usb_interface *intf)
static int wdm_pre_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
struct wdm_device *desc = wdm_find_device(intf);
/*
* we notify everybody using poll of
@ -880,17 +974,25 @@ static int wdm_pre_reset(struct usb_interface *intf)
* message from the device is lost
*/
spin_lock_irq(&desc->iuspin);
set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
set_bit(WDM_READ, &desc->flags); /* unblock read */
clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
desc->rerr = -EINTR;
spin_unlock_irq(&desc->iuspin);
wake_up_all(&desc->wait);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
return 0;
}
static int wdm_post_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);
struct wdm_device *desc = wdm_find_device(intf);
int rv;
clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);

View File

@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf)
int rc;
/* Delayed unbind of an existing driver */
if (intf->dev.driver) {
struct usb_driver *driver =
to_usb_driver(intf->dev.driver);
dev_dbg(&intf->dev, "forced unbind\n");
usb_driver_release_interface(driver, intf);
}
if (intf->dev.driver)
usb_forced_unbind_intf(intf);
/* Try to rebind the interface */
if (!intf->dev.power.is_prepared) {
@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf)
#ifdef CONFIG_PM
#define DO_UNBIND 0
#define DO_REBIND 1
/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
* or rebind interfaces that have been unbound, according to @action.
/* Unbind drivers for @udev's interfaces that don't support suspend/resume
* There is no check for reset_resume here because it can be determined
* only during resume whether reset_resume is needed.
*
* The caller must hold @udev's device lock.
*/
static void do_unbind_rebind(struct usb_device *udev, int action)
static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
@ -996,23 +989,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
switch (action) {
case DO_UNBIND:
if (intf->dev.driver) {
drv = to_usb_driver(intf->dev.driver);
if (!drv->suspend || !drv->resume)
usb_forced_unbind_intf(intf);
}
break;
case DO_REBIND:
if (intf->needs_binding)
usb_rebind_intf(intf);
break;
if (intf->dev.driver) {
drv = to_usb_driver(intf->dev.driver);
if (!drv->suspend || !drv->resume)
usb_forced_unbind_intf(intf);
}
}
}
}
/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
* These interfaces have the needs_binding flag set by usb_resume_interface().
*
* The caller must hold @udev's device lock.
*/
static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->dev.driver && intf->needs_binding)
usb_forced_unbind_intf(intf);
}
}
}
static void do_rebind_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
struct usb_interface *intf;
config = udev->actconfig;
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
if (intf->needs_binding)
usb_rebind_intf(intf);
}
}
}
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
@ -1302,35 +1325,48 @@ int usb_suspend(struct device *dev, pm_message_t msg)
{
struct usb_device *udev = to_usb_device(dev);
do_unbind_rebind(udev, DO_UNBIND);
unbind_no_pm_drivers_interfaces(udev);
/* From now on we are sure all drivers support suspend/resume
* but not necessarily reset_resume()
* so we may still need to unbind and rebind upon resume
*/
choose_wakeup(udev, msg);
return usb_suspend_both(udev, msg);
}
/* The device lock is held by the PM core */
int usb_resume_complete(struct device *dev)
{
struct usb_device *udev = to_usb_device(dev);
/* For PM complete calls, all we do is rebind interfaces
* whose needs_binding flag is set
*/
if (udev->state != USB_STATE_NOTATTACHED)
do_rebind_interfaces(udev);
return 0;
}
/* The device lock is held by the PM core */
int usb_resume(struct device *dev, pm_message_t msg)
{
struct usb_device *udev = to_usb_device(dev);
int status;
/* For PM complete calls, all we do is rebind interfaces */
if (msg.event == PM_EVENT_ON) {
if (udev->state != USB_STATE_NOTATTACHED)
do_unbind_rebind(udev, DO_REBIND);
status = 0;
/* For all other calls, take the device back to full power and
/* For all calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously.
* Unbind the interfaces that will need rebinding later.
* Unbind the interfaces that will need rebinding later,
* because they fail to support reset_resume.
* (This can't be done in usb_resume_interface()
* above because it doesn't own the right set of locks.)
*/
} else {
status = usb_resume_both(udev, msg);
if (status == 0) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
do_unbind_rebind(udev, DO_REBIND);
}
status = usb_resume_both(udev, msg);
if (status == 0) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
unbind_no_reset_resume_drivers_interfaces(udev);
}
/* Avoid PM error messages for devices disconnected while suspended

View File

@ -380,6 +380,7 @@ static int check_root_hub_suspended(struct device *dev)
return 0;
}
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
static int suspend_common(struct device *dev, bool do_wakeup)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@ -471,6 +472,7 @@ static int resume_common(struct device *dev, int event)
}
return retval;
}
#endif /* SLEEP || RUNTIME */
#ifdef CONFIG_PM_SLEEP

View File

@ -2352,7 +2352,7 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
} else {
hcd->irq = -1;
hcd->irq = 0;
if (hcd->rsrc_start)
dev_info(hcd->self.controller, "%s 0x%08llx\n",
(hcd->driver->flags & HCD_MEMORY) ?
@ -2508,7 +2508,7 @@ err_register_root_hub:
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
err_hcd_driver_start:
if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
@ -2573,7 +2573,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
del_timer_sync(&hcd->rh_timer);
if (usb_hcd_is_primary_hcd(hcd)) {
if (hcd->irq >= 0)
if (hcd->irq > 0)
free_irq(hcd->irq, hcd);
}

View File

@ -62,6 +62,8 @@ struct usb_hub {
resumed */
unsigned long removed_bits[1]; /* ports with a "removed"
device present */
unsigned long wakeup_bits[1]; /* ports that have signaled
remote wakeup */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
@ -411,6 +413,29 @@ void usb_kick_khubd(struct usb_device *hdev)
kick_khubd(hub);
}
/*
* Let the USB core know that a USB 3.0 device has sent a Function Wake Device
* Notification, which indicates it had initiated remote wakeup.
*
* USB 3.0 hubs do not report the port link state change from U3 to U0 when the
* device initiates resume, so the USB core will not receive notice of the
* resume through the normal hub interrupt URB.
*/
void usb_wakeup_notification(struct usb_device *hdev,
unsigned int portnum)
{
struct usb_hub *hub;
if (!hdev)
return;
hub = hdev_to_hub(hdev);
if (hub) {
set_bit(portnum, hub->wakeup_bits);
kick_khubd(hub);
}
}
EXPORT_SYMBOL_GPL(usb_wakeup_notification);
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb)
@ -823,12 +848,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
}
if (portchange & USB_PORT_STAT_C_LINK_STATE) {
need_debounce_delay = true;
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE);
}
if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
hub_is_superspeed(hub->hdev)) {
need_debounce_delay = true;
@ -850,12 +869,19 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
set_bit(port1, hub->change_bits);
} else if (portstatus & USB_PORT_STAT_ENABLE) {
bool port_resumed = (portstatus &
USB_PORT_STAT_LINK_STATE) ==
USB_SS_PORT_LS_U0;
/* The power session apparently survived the resume.
* If there was an overcurrent or suspend change
* (i.e., remote wakeup request), have khubd
* take care of it.
* take care of it. Look at the port link state
* for USB 3.0 hubs, since they don't have a suspend
* change bit, and they don't set the port link change
* bit on device-initiated resume.
*/
if (portchange)
if (portchange || (hub_is_superspeed(hub->hdev) &&
port_resumed))
set_bit(port1, hub->change_bits);
} else if (udev->persist_enabled) {
@ -1293,14 +1319,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
/* Hubs have proper suspend/resume support. USB 3.0 device suspend is
* different from USB 2.0/1.1 device suspend, and unfortunately we
* don't support it yet. So leave autosuspend disabled for USB 3.0
* external hubs for now. Enable autosuspend for USB 3.0 roothubs,
* since that isn't a "real" hub.
*/
if (!hub_is_superspeed(hdev) || !hdev->parent)
usb_enable_autosuspend(hdev);
/* Hubs have proper suspend/resume support. */
usb_enable_autosuspend(hdev);
if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev,
@ -1842,6 +1862,37 @@ fail:
return err;
}
static void set_usb_port_removable(struct usb_device *udev)
{
struct usb_device *hdev = udev->parent;
struct usb_hub *hub;
u8 port = udev->portnum;
u16 wHubCharacteristics;
bool removable = true;
if (!hdev)
return;
hub = hdev_to_hub(udev->parent);
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
return;
if (hub_is_superspeed(hdev)) {
if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
removable = false;
} else {
if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
removable = false;
}
if (removable)
udev->removable = USB_DEVICE_REMOVABLE;
else
udev->removable = USB_DEVICE_FIXED;
}
/**
* usb_new_device - perform initial device setup (usbcore-internal)
@ -1900,6 +1951,15 @@ int usb_new_device(struct usb_device *udev)
announce_device(udev);
device_enable_async_suspend(&udev->dev);
/*
* check whether the hub marks this port as non-removable. Do it
* now so that platform-specific data can override it in
* device_add()
*/
if (udev->parent)
set_usb_port_removable(udev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
@ -2385,11 +2445,27 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
* we don't explicitly enable it here.
*/
if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (!hub_is_superspeed(hub->hdev)) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
} else {
/* Assume there's only one function on the USB 3.0
* device and enable remote wake for the first
* interface. FIXME if the interface association
* descriptor shows there's more than one function.
*/
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE,
USB_RECIP_INTERFACE,
USB_INTRF_FUNC_SUSPEND,
USB_INTRF_FUNC_SUSPEND_RW |
USB_INTRF_FUNC_SUSPEND_LP,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
if (status) {
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status);
@ -2679,6 +2755,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
int status;
/* Warn if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@ -2691,6 +2768,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
return -EBUSY;
}
}
if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
/* Enable hub to send remote wakeup for all ports. */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
status = set_port_feature(hdev,
port1 |
USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
USB_PORT_FEAT_REMOTE_WAKE_MASK);
}
}
dev_dbg(&intf->dev, "%s\n", __func__);
@ -3424,6 +3512,46 @@ done:
hcd->driver->relinquish_port(hcd, port1);
}
/* Returns 1 if there was a remote wakeup and a connect status change. */
static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
u16 portstatus, u16 portchange)
{
struct usb_device *hdev;
struct usb_device *udev;
int connect_change = 0;
int ret;
hdev = hub->hdev;
udev = hdev->children[port-1];
if (!hub_is_superspeed(hdev)) {
if (!(portchange & USB_PORT_STAT_C_SUSPEND))
return 0;
clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
} else {
if (!udev || udev->state != USB_STATE_SUSPENDED ||
(portstatus & USB_PORT_STAT_LINK_STATE) !=
USB_SS_PORT_LS_U0)
return 0;
}
if (udev) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_lock_device(udev);
ret = usb_remote_wakeup(udev);
usb_unlock_device(udev);
if (ret < 0)
connect_change = 1;
} else {
ret = -ENODEV;
hub_port_disable(hub, port, 1);
}
dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
port, ret);
return connect_change;
}
static void hub_events(void)
{
struct list_head *tmp;
@ -3436,7 +3564,7 @@ static void hub_events(void)
u16 portstatus;
u16 portchange;
int i, ret;
int connect_change;
int connect_change, wakeup_change;
/*
* We restart the list every time to avoid a deadlock with
@ -3515,8 +3643,9 @@ static void hub_events(void)
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits);
wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
if (!test_and_clear_bit(i, hub->event_bits) &&
!connect_change)
!connect_change && !wakeup_change)
continue;
ret = hub_port_status(hub, i,
@ -3557,31 +3686,10 @@ static void hub_events(void)
}
}
if (portchange & USB_PORT_STAT_C_SUSPEND) {
struct usb_device *udev;
if (hub_handle_remote_wakeup(hub, i,
portstatus, portchange))
connect_change = 1;
clear_port_feature(hdev, i,
USB_PORT_FEAT_C_SUSPEND);
udev = hdev->children[i-1];
if (udev) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_lock_device(udev);
ret = usb_remote_wakeup(hdev->
children[i-1]);
usb_unlock_device(udev);
if (ret < 0)
connect_change = 1;
} else {
ret = -ENODEV;
hub_port_disable(hub, i, 1);
}
dev_dbg (hub_dev,
"resume on port %d, status %d\n",
i, ret);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
u16 status = 0;
u16 unused;

View File

@ -230,6 +230,28 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
static ssize_t
show_removable(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *state;
udev = to_usb_device(dev);
switch (udev->removable) {
case USB_DEVICE_REMOVABLE:
state = "removable";
break;
case USB_DEVICE_FIXED:
state = "fixed";
break;
default:
state = "unknown";
}
return sprintf(buf, "%s\n", state);
}
static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
#ifdef CONFIG_PM
@ -626,6 +648,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
&dev_attr_removable.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {

View File

@ -403,20 +403,17 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* cause problems in HCDs if they get it wrong.
*/
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
/* Check that the pipe's type matches the endpoint's type */
if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]);
return -EPIPE; /* The most suitable error code :-) */
}
/* enforce simple/standard policy */
/* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER);
switch (xfertype) {
@ -435,14 +432,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
allowed |= URB_ISO_ASAP;
break;
}
urb->transfer_flags &= allowed;
allowed &= urb->transfer_flags;
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
/* warn if submitter gave bogus flags */
if (allowed != urb->transfer_flags)
dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
urb->transfer_flags, allowed);
}
#endif
/*
@ -532,10 +527,13 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
* a driver's I/O routines to insure that all URB-related activity has
* completed before it returns.
*
* This request is always asynchronous. Success is indicated by
* returning -EINPROGRESS, at which time the URB will probably not yet
* have been given back to the device driver. When it is eventually
* called, the completion function will see @urb->status == -ECONNRESET.
* This request is asynchronous, however the HCD might call the ->complete()
* callback during unlink. Therefore when drivers call usb_unlink_urb(), they
* must not hold any locks that may be taken by the completion function.
* Success is indicated by returning -EINPROGRESS, at which time the URB will
* probably not yet have been given back to the device driver. When it is
* eventually called, the completion function will see @urb->status ==
* -ECONNRESET.
* Failure is indicated by usb_unlink_urb() returning any other value.
* Unlinking will fail when @urb is not currently "linked" (i.e., it was
* never submitted, or it was unlinked before, or the hardware is already

View File

@ -274,7 +274,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev)
{
/* Currently used only for rebinding interfaces */
usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
usb_resume_complete(dev);
}
static int usb_dev_suspend(struct device *dev)

View File

@ -56,6 +56,7 @@ extern void usb_major_cleanup(void);
extern int usb_suspend(struct device *dev, pm_message_t msg);
extern int usb_resume(struct device *dev, pm_message_t msg);
extern int usb_resume_complete(struct device *dev);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);

View File

@ -28,6 +28,19 @@ endif
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
##
# REVISIT Samsung Exynos platform needs the clk API which isn't
# defined on all architectures. If we allow dwc3-exynos.c compile
# always we will fail the linking phase on those architectures
# which don't provide clk api implementation and that's unnaceptable.
#
# When Samsung's platform start supporting pm_runtime, this check
# for HAVE_CLK should be removed.
##
ifneq ($(CONFIG_HAVE_CLK),)
obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
endif
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
endif

View File

@ -48,10 +48,10 @@
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/module.h>
#include "core.h"
#include "gadget.h"
@ -86,7 +86,7 @@ again:
id = -ENOMEM;
}
return 0;
return id;
}
EXPORT_SYMBOL_GPL(dwc3_get_device_id);
@ -167,11 +167,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
}
/**
* dwc3_alloc_one_event_buffer - Allocated one event buffer structure
* dwc3_alloc_one_event_buffer - Allocates one event buffer structure
* @dwc: Pointer to our controller context structure
* @length: size of the event buffer
*
* Returns a pointer to the allocated event buffer structure on succes
* Returns a pointer to the allocated event buffer structure on success
* otherwise ERR_PTR(errno).
*/
static struct dwc3_event_buffer *__devinit
@ -215,10 +215,10 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
/**
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
* @dwc: Pointer to out controller context structure
* @dwc: pointer to our controller context structure
* @length: size of event buffer
*
* Returns 0 on success otherwise negative errno. In error the case, dwc
* Returns 0 on success otherwise negative errno. In the error case, dwc
* may contain some buffers allocated but not all which were requested.
*/
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
@ -251,7 +251,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
/**
* dwc3_event_buffers_setup - setup our allocated event buffers
* @dwc: Pointer to out controller context structure
* @dwc: pointer to our controller context structure
*
* Returns 0 on success otherwise negative errno.
*/
@ -350,7 +350,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
dwc3_cache_hwparams(dwc);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN(3);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
@ -363,9 +363,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
* when The device fails to connect at SuperSpeed
* where the device can fail to connect at SuperSpeed
* and falls back to high-speed mode which causes
* the device to enter in a Connect/Disconnect loop
* the device to enter a Connect/Disconnect loop
*/
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
@ -404,8 +404,10 @@ static void dwc3_core_exit(struct dwc3 *dwc)
static int __devinit dwc3_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct resource *res;
struct dwc3 *dwc;
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
int irq;
@ -415,39 +417,39 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
u8 mode;
mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
dev_err(&pdev->dev, "not enough memory\n");
goto err0;
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing resource\n");
goto err1;
dev_err(dev, "missing resource\n");
return -ENODEV;
}
dwc->res = res;
res = request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev));
res = devm_request_mem_region(dev, res->start, resource_size(res),
dev_name(dev));
if (!res) {
dev_err(&pdev->dev, "can't request mem region\n");
goto err1;
dev_err(dev, "can't request mem region\n");
return -ENOMEM;
}
regs = ioremap(res->start, resource_size(res));
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs) {
dev_err(&pdev->dev, "ioremap failed\n");
goto err2;
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "missing IRQ\n");
goto err3;
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
spin_lock_init(&dwc->lock);
@ -455,7 +457,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = &pdev->dev;
dwc->dev = dev;
dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
@ -469,14 +471,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
else
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_forbid(&pdev->dev);
if (of_get_property(node, "tx-fifo-resize", NULL))
dwc->needs_fifo_resize = true;
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
pm_runtime_forbid(dev);
ret = dwc3_core_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize core\n");
goto err3;
dev_err(dev, "failed to initialize core\n");
return ret;
}
mode = DWC3_MODE(dwc->hwparams.hwparams0);
@ -486,49 +491,49 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize gadget\n");
goto err4;
dev_err(dev, "failed to initialize gadget\n");
goto err1;
}
break;
case DWC3_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize host\n");
goto err4;
dev_err(dev, "failed to initialize host\n");
goto err1;
}
break;
case DWC3_MODE_DRD:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize host\n");
goto err4;
dev_err(dev, "failed to initialize host\n");
goto err1;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize gadget\n");
goto err4;
dev_err(dev, "failed to initialize gadget\n");
goto err1;
}
break;
default:
dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
goto err4;
dev_err(dev, "Unsupported mode of operation %d\n", mode);
goto err1;
}
dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
dev_err(&pdev->dev, "failed to initialize debugfs\n");
goto err5;
dev_err(dev, "failed to initialize debugfs\n");
goto err2;
}
pm_runtime_allow(&pdev->dev);
pm_runtime_allow(dev);
return 0;
err5:
err2:
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
@ -545,19 +550,9 @@ err5:
break;
}
err4:
err1:
dwc3_core_exit(dwc);
err3:
iounmap(regs);
err2:
release_mem_region(res->start, resource_size(res));
err1:
kfree(dwc->mem);
err0:
return ret;
}
@ -590,9 +585,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
}
dwc3_core_exit(dwc);
release_mem_region(res->start, resource_size(res));
iounmap(dwc->regs);
kfree(dwc->mem);
return 0;
}
@ -605,19 +597,9 @@ static struct platform_driver dwc3_driver = {
},
};
module_platform_driver(dwc3_driver);
MODULE_ALIAS("platform:dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
static int __devinit dwc3_init(void)
{
return platform_driver_register(&dwc3_driver);
}
module_init(dwc3_init);
static void __exit dwc3_exit(void)
{
platform_driver_unregister(&dwc3_driver);
}
module_exit(dwc3_exit);

View File

@ -145,22 +145,23 @@
/* Bit fields */
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN (1 << 16)
#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS (0)
#define DWC3_GCTL_CLK_PIPE (1)
#define DWC3_GCTL_CLK_PIPEHALF (2)
#define DWC3_GCTL_CLK_MASK (3)
#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12)
#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
#define DWC3_GCTL_PRTCAP_HOST 1
#define DWC3_GCTL_PRTCAP_DEVICE 2
#define DWC3_GCTL_PRTCAP_OTG 3
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
@ -172,8 +173,12 @@
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
/* Global HWPARAMS1 Register */
#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
@ -198,6 +203,15 @@
#define DWC3_DCTL_APPL1RES (1 << 23)
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
#define DWC3_DCTL_TRGTULST(n) ((n) << 17)
#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2))
#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3))
#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
#define DWC3_DCTL_INITU2ENA (1 << 12)
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
#define DWC3_DCTL_INITU1ENA (1 << 10)
@ -260,10 +274,10 @@
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8)
@ -288,7 +302,7 @@
/* Structures */
struct dwc3_trb_hw;
struct dwc3_trb;
/**
* struct dwc3_event_buffer - Software event buffer representation
@ -343,7 +357,7 @@ struct dwc3_ep {
struct list_head request_list;
struct list_head req_queued;
struct dwc3_trb_hw *trb_pool;
struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
@ -418,102 +432,49 @@ enum dwc3_device_state {
DWC3_CONFIGURED_STATE,
};
/**
* struct dwc3_trb - transfer request block
* @bpl: lower 32bit of the buffer
* @bph: higher 32bit of the buffer
* @length: buffer size (up to 16mb - 1)
* @pcm1: packet count m1
* @trbsts: trb status
* 0 = ok
* 1 = missed isoc
* 2 = setup pending
* @hwo: hardware owner of descriptor
* @lst: last trb
* @chn: chain buffers
* @csp: continue on short packets (only supported on isoc eps)
* @trbctl: trb control
* 1 = normal
* 2 = control-setup
* 3 = control-status-2
* 4 = control-status-3
* 5 = control-data (first trb of data stage)
* 6 = isochronous-first (first trb of service interval)
* 7 = isochronous
* 8 = link trb
* others = reserved
* @isp_imi: interrupt on short packet / interrupt on missed isoc
* @ioc: interrupt on complete
* @sid_sofn: Stream ID / SOF Number
*/
struct dwc3_trb {
u64 bplh;
/* TRB Length, PCM and Status */
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24)
#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28))
union {
struct {
u32 length:24;
u32 pcm1:2;
u32 reserved27_26:2;
u32 trbsts:4;
#define DWC3_TRB_STS_OKAY 0
#define DWC3_TRB_STS_MISSED_ISOC 1
#define DWC3_TRB_STS_SETUP_PENDING 2
};
u32 len_pcm;
};
#define DWC3_TRBSTS_OK 0
#define DWC3_TRBSTS_MISSED_ISOC 1
#define DWC3_TRBSTS_SETUP_PENDING 2
union {
struct {
u32 hwo:1;
u32 lst:1;
u32 chn:1;
u32 csp:1;
u32 trbctl:6;
u32 isp_imi:1;
u32 ioc:1;
u32 reserved13_12:2;
u32 sid_sofn:16;
u32 reserved31_30:2;
};
u32 control;
};
} __packed;
/* TRB Control */
#define DWC3_TRB_CTRL_HWO (1 << 0)
#define DWC3_TRB_CTRL_LST (1 << 1)
#define DWC3_TRB_CTRL_CHN (1 << 2)
#define DWC3_TRB_CTRL_CSP (1 << 3)
#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
#define DWC3_TRB_CTRL_ISP_IMI (1 << 10)
#define DWC3_TRB_CTRL_IOC (1 << 11)
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
#define DWC3_TRBCTL_CONTROL_STATUS3 DWC3_TRB_CTRL_TRBCTL(4)
#define DWC3_TRBCTL_CONTROL_DATA DWC3_TRB_CTRL_TRBCTL(5)
#define DWC3_TRBCTL_ISOCHRONOUS_FIRST DWC3_TRB_CTRL_TRBCTL(6)
#define DWC3_TRBCTL_ISOCHRONOUS DWC3_TRB_CTRL_TRBCTL(7)
#define DWC3_TRBCTL_LINK_TRB DWC3_TRB_CTRL_TRBCTL(8)
/**
* struct dwc3_trb_hw - transfer request block (hw format)
* struct dwc3_trb - transfer request block (hw format)
* @bpl: DW0-3
* @bph: DW4-7
* @size: DW8-B
* @trl: DWC-F
*/
struct dwc3_trb_hw {
__le32 bpl;
__le32 bph;
__le32 size;
__le32 ctrl;
struct dwc3_trb {
u32 bpl;
u32 bph;
u32 size;
u32 ctrl;
} __packed;
static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
{
hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
hw->size = cpu_to_le32p(&nat->len_pcm);
/* HWO is written last */
hw->ctrl = cpu_to_le32p(&nat->control);
}
static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
{
u64 bplh;
bplh = le32_to_cpup(&hw->bpl);
bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
nat->bplh = bplh;
nat->len_pcm = le32_to_cpup(&hw->size);
nat->control = le32_to_cpup(&hw->ctrl);
}
/**
* dwc3_hwparams - copy of HWPARAMS registers
* @hwparams0 - GHWPARAMS0
@ -546,8 +507,13 @@ struct dwc3_hwparams {
#define DWC3_MODE_DRD 2
#define DWC3_MODE_HUB 3
#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8)
/* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
struct dwc3_request {
struct usb_request request;
@ -555,7 +521,7 @@ struct dwc3_request {
struct dwc3_ep *dep;
u8 epnum;
struct dwc3_trb_hw *trb;
struct dwc3_trb *trb;
dma_addr_t trb_dma;
unsigned direction:1;
@ -572,7 +538,6 @@ struct dwc3_request {
* @ctrl_req_addr: dma address of ctrl_req
* @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests
* @setup_buf_addr: dma address of setup_buf
* @ep0_bounce_addr: dma address of ep0_bounce
* @lock: for synchronizing
* @dev: pointer to our struct device
@ -594,6 +559,8 @@ struct dwc3_request {
* @ep0_expect_in: true when we expect a DATA IN transfer
* @start_config_issued: true when StartConfig command has been issued
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@ -604,12 +571,11 @@ struct dwc3_request {
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
struct dwc3_trb_hw *ep0_trb;
struct dwc3_trb *ep0_trb;
void *ep0_bounce;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
dma_addr_t ep0_trb_addr;
dma_addr_t setup_buf_addr;
dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req;
/* device lock */
@ -651,6 +617,8 @@ struct dwc3 {
unsigned start_config_issued:1;
unsigned setup_packet_pending:1;
unsigned delayed_status:1;
unsigned needs_fifo_resize:1;
unsigned resize_fifos:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@ -662,23 +630,13 @@ struct dwc3 {
struct dwc3_hwparams hwparams;
struct dentry *root;
u8 test_mode;
u8 test_mode_nr;
};
/* -------------------------------------------------------------------------- */
#define DWC3_TRBSTS_OK 0
#define DWC3_TRBSTS_MISSED_ISOC 1
#define DWC3_TRBSTS_SETUP_PENDING 2
#define DWC3_TRBCTL_NORMAL 1
#define DWC3_TRBCTL_CONTROL_SETUP 2
#define DWC3_TRBCTL_CONTROL_STATUS2 3
#define DWC3_TRBCTL_CONTROL_STATUS3 4
#define DWC3_TRBCTL_CONTROL_DATA 5
#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
#define DWC3_TRBCTL_ISOCHRONOUS 7
#define DWC3_TRBCTL_LINK_TRB 8
/* -------------------------------------------------------------------------- */
struct dwc3_event_type {
@ -719,9 +677,14 @@ struct dwc3_event_depevt {
u32 endpoint_event:4;
u32 reserved11_10:2;
u32 status:4;
#define DEPEVT_STATUS_BUSERR (1 << 0)
#define DEPEVT_STATUS_SHORT (1 << 1)
#define DEPEVT_STATUS_IOC (1 << 2)
/* Within XferNotReady */
#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3)
/* Within XferComplete */
#define DEPEVT_STATUS_BUSERR (1 << 0)
#define DEPEVT_STATUS_SHORT (1 << 1)
#define DEPEVT_STATUS_IOC (1 << 2)
#define DEPEVT_STATUS_LST (1 << 3)
/* Stream event only */
@ -807,6 +770,7 @@ union dwc3_event {
/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);

View File

@ -46,6 +46,8 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include "core.h"
#include "gadget.h"
#include "io.h"
@ -464,6 +466,192 @@ static const struct file_operations dwc3_mode_fops = {
.release = single_release,
};
static int dwc3_testmode_show(struct seq_file *s, void *unused)
{
struct dwc3 *dwc = s->private;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= DWC3_DCTL_TSTCTRL_MASK;
reg >>= 1;
spin_unlock_irqrestore(&dwc->lock, flags);
switch (reg) {
case 0:
seq_printf(s, "no test\n");
break;
case TEST_J:
seq_printf(s, "test_j\n");
break;
case TEST_K:
seq_printf(s, "test_k\n");
break;
case TEST_SE0_NAK:
seq_printf(s, "test_se0_nak\n");
break;
case TEST_PACKET:
seq_printf(s, "test_packet\n");
break;
case TEST_FORCE_EN:
seq_printf(s, "test_force_enable\n");
break;
default:
seq_printf(s, "UNKNOWN %d\n", reg);
}
return 0;
}
static int dwc3_testmode_open(struct inode *inode, struct file *file)
{
return single_open(file, dwc3_testmode_show, inode->i_private);
}
static ssize_t dwc3_testmode_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
unsigned long flags;
u32 testmode = 0;
char buf[32];
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (!strncmp(buf, "test_j", 6))
testmode = TEST_J;
else if (!strncmp(buf, "test_k", 6))
testmode = TEST_K;
else if (!strncmp(buf, "test_se0_nak", 12))
testmode = TEST_SE0_NAK;
else if (!strncmp(buf, "test_packet", 11))
testmode = TEST_PACKET;
else if (!strncmp(buf, "test_force_enable", 17))
testmode = TEST_FORCE_EN;
else
testmode = 0;
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_set_test_mode(dwc, testmode);
spin_unlock_irqrestore(&dwc->lock, flags);
return count;
}
static const struct file_operations dwc3_testmode_fops = {
.open = dwc3_testmode_open,
.write = dwc3_testmode_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int dwc3_link_state_show(struct seq_file *s, void *unused)
{
struct dwc3 *dwc = s->private;
unsigned long flags;
enum dwc3_link_state state;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
state = DWC3_DSTS_USBLNKST(reg);
spin_unlock_irqrestore(&dwc->lock, flags);
switch (state) {
case DWC3_LINK_STATE_U0:
seq_printf(s, "U0\n");
break;
case DWC3_LINK_STATE_U1:
seq_printf(s, "U1\n");
break;
case DWC3_LINK_STATE_U2:
seq_printf(s, "U2\n");
break;
case DWC3_LINK_STATE_U3:
seq_printf(s, "U3\n");
break;
case DWC3_LINK_STATE_SS_DIS:
seq_printf(s, "SS.Disabled\n");
break;
case DWC3_LINK_STATE_RX_DET:
seq_printf(s, "Rx.Detect\n");
break;
case DWC3_LINK_STATE_SS_INACT:
seq_printf(s, "SS.Inactive\n");
break;
case DWC3_LINK_STATE_POLL:
seq_printf(s, "Poll\n");
break;
case DWC3_LINK_STATE_RECOV:
seq_printf(s, "Recovery\n");
break;
case DWC3_LINK_STATE_HRESET:
seq_printf(s, "HRESET\n");
break;
case DWC3_LINK_STATE_CMPLY:
seq_printf(s, "Compliance\n");
break;
case DWC3_LINK_STATE_LPBK:
seq_printf(s, "Loopback\n");
break;
default:
seq_printf(s, "UNKNOWN %d\n", reg);
}
return 0;
}
static int dwc3_link_state_open(struct inode *inode, struct file *file)
{
return single_open(file, dwc3_link_state_show, inode->i_private);
}
static ssize_t dwc3_link_state_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
unsigned long flags;
enum dwc3_link_state state = 0;
char buf[32];
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (!strncmp(buf, "SS.Disabled", 11))
state = DWC3_LINK_STATE_SS_DIS;
else if (!strncmp(buf, "Rx.Detect", 9))
state = DWC3_LINK_STATE_RX_DET;
else if (!strncmp(buf, "SS.Inactive", 11))
state = DWC3_LINK_STATE_SS_INACT;
else if (!strncmp(buf, "Recovery", 8))
state = DWC3_LINK_STATE_RECOV;
else if (!strncmp(buf, "Compliance", 10))
state = DWC3_LINK_STATE_CMPLY;
else if (!strncmp(buf, "Loopback", 8))
state = DWC3_LINK_STATE_LPBK;
else
return -EINVAL;
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_set_link_state(dwc, state);
spin_unlock_irqrestore(&dwc->lock, flags);
return count;
}
static const struct file_operations dwc3_link_state_fops = {
.open = dwc3_link_state_open,
.write = dwc3_link_state_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
@ -471,8 +659,8 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
int ret;
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
if (IS_ERR(root)) {
ret = PTR_ERR(root);
if (!root) {
ret = -ENOMEM;
goto err0;
}
@ -480,15 +668,29 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
&dwc3_regdump_fops);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
if (!file) {
ret = -ENOMEM;
goto err1;
}
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
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;
}
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_link_state_fops);
if (!file) {
ret = -ENOMEM;
goto err1;
}

View File

@ -0,0 +1,151 @@
/**
* dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dwc3-exynos.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/clk.h>
#include "core.h"
struct dwc3_exynos {
struct platform_device *dwc3;
struct device *dev;
struct clk *clk;
};
static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
struct platform_device *dwc3;
struct dwc3_exynos *exynos;
struct clk *clk;
int devid;
int ret = -ENOMEM;
exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
if (!exynos) {
dev_err(&pdev->dev, "not enough memory\n");
goto err0;
}
platform_set_drvdata(pdev, exynos);
devid = dwc3_get_device_id();
if (devid < 0)
goto err1;
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
goto err2;
}
clk = clk_get(&pdev->dev, "usbdrd30");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "couldn't get clock\n");
ret = -EINVAL;
goto err3;
}
dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
dwc3->dev.parent = &pdev->dev;
dwc3->dev.dma_mask = pdev->dev.dma_mask;
dwc3->dev.dma_parms = pdev->dev.dma_parms;
exynos->dwc3 = dwc3;
exynos->dev = &pdev->dev;
exynos->clk = clk;
clk_enable(exynos->clk);
/* PHY initialization */
if (!pdata) {
dev_dbg(&pdev->dev, "missing platform data\n");
} else {
if (pdata->phy_init)
pdata->phy_init(pdev, pdata->phy_type);
}
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
goto err4;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
goto err4;
}
return 0;
err4:
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, pdata->phy_type);
clk_disable(clk);
clk_put(clk);
err3:
platform_device_put(dwc3);
err2:
dwc3_put_device_id(devid);
err1:
kfree(exynos);
err0:
return ret;
}
static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
platform_device_unregister(exynos->dwc3);
dwc3_put_device_id(exynos->dwc3->id);
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, pdata->phy_type);
clk_disable(exynos->clk);
clk_put(exynos->clk);
kfree(exynos);
return 0;
}
static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe,
.remove = __devexit_p(dwc3_exynos_remove),
.driver = {
.name = "exynos-dwc3",
},
};
module_platform_driver(dwc3_exynos_driver);
MODULE_ALIAS("platform:exynos-dwc3");
MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");

View File

@ -46,7 +46,7 @@
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include "core.h"
#include "io.h"
@ -197,91 +197,99 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
static int __devinit dwc3_omap_probe(struct platform_device *pdev)
{
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct platform_device *dwc3;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
int devid;
int size;
int ret = -ENOMEM;
int irq;
const u32 *utmi_mode;
u32 reg;
void __iomem *base;
void *context;
omap = kzalloc(sizeof(*omap), GFP_KERNEL);
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
dev_err(&pdev->dev, "not enough memory\n");
goto err0;
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(&pdev->dev, "missing IRQ resource\n");
ret = -EINVAL;
goto err1;
dev_err(dev, "missing IRQ resource\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "missing memory base resource\n");
ret = -EINVAL;
goto err1;
dev_err(dev, "missing memory base resource\n");
return -EINVAL;
}
base = ioremap_nocache(res->start, resource_size(res));
base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!base) {
dev_err(&pdev->dev, "ioremap failed\n");
goto err1;
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
}
devid = dwc3_get_device_id();
if (devid < 0)
goto err2;
return -ENODEV;
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
goto err3;
dev_err(dev, "couldn't allocate dwc3 device\n");
goto err1;
}
context = kzalloc(resource_size(res), GFP_KERNEL);
context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
if (!context) {
dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
goto err4;
dev_err(dev, "couldn't allocate dwc3 context memory\n");
goto err2;
}
spin_lock_init(&omap->lock);
dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dwc3->dev.parent = &pdev->dev;
dwc3->dev.dma_mask = pdev->dev.dma_mask;
dwc3->dev.dma_parms = pdev->dev.dma_parms;
dwc3->dev.parent = dev;
dwc3->dev.dma_mask = dev->dma_mask;
dwc3->dev.dma_parms = dev->dma_parms;
omap->resource_size = resource_size(res);
omap->context = context;
omap->dev = &pdev->dev;
omap->dev = dev;
omap->irq = irq;
omap->base = base;
omap->dwc3 = dwc3;
reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
if (!pdata) {
dev_dbg(&pdev->dev, "missing platform data\n");
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
reg |= *utmi_mode;
} 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(&pdev->dev, "UNKNOWN utmi mode %d\n",
pdata->utmi_mode);
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);
}
}
}
@ -300,12 +308,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
goto err5;
goto err2;
}
/* enable all IRQs */
@ -327,37 +335,24 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
goto err6;
dev_err(dev, "couldn't add resources to dwc3 device\n");
goto err2;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
goto err6;
dev_err(dev, "failed to register dwc3 device\n");
goto err2;
}
return 0;
err6:
free_irq(omap->irq, omap);
err5:
kfree(omap->context);
err4:
err2:
platform_device_put(dwc3);
err3:
err1:
dwc3_put_device_id(devid);
err2:
iounmap(base);
err1:
kfree(omap);
err0:
return ret;
}
@ -368,11 +363,6 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
platform_device_unregister(omap->dwc3);
dwc3_put_device_id(omap->dwc3->id);
free_irq(omap->irq, omap);
iounmap(omap->base);
kfree(omap->context);
kfree(omap);
return 0;
}

View File

@ -61,32 +61,35 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
struct dwc3_pci *glue;
int ret = -ENOMEM;
int devid;
struct device *dev = &pci->dev;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pci->dev, "not enough memory\n");
goto err0;
dev_err(dev, "not enough memory\n");
return -ENOMEM;
}
glue->dev = &pci->dev;
glue->dev = dev;
ret = pci_enable_device(pci);
if (ret) {
dev_err(&pci->dev, "failed to enable pci device\n");
goto err1;
dev_err(dev, "failed to enable pci device\n");
return -ENODEV;
}
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
devid = dwc3_get_device_id();
if (devid < 0)
goto err2;
if (devid < 0) {
ret = -ENOMEM;
goto err1;
}
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
goto err3;
dev_err(dev, "couldn't allocate dwc3 device\n");
goto err1;
}
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@ -102,41 +105,37 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
goto err4;
dev_err(dev, "couldn't add resources to dwc3 device\n");
goto err2;
}
pci_set_drvdata(pci, glue);
dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dwc3->dev.dma_mask = pci->dev.dma_mask;
dwc3->dev.dma_parms = pci->dev.dma_parms;
dwc3->dev.parent = &pci->dev;
glue->dwc3 = dwc3;
dwc3->dev.dma_mask = dev->dma_mask;
dwc3->dev.dma_parms = dev->dma_parms;
dwc3->dev.parent = dev;
glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pci->dev, "failed to register dwc3 device\n");
goto err4;
dev_err(dev, "failed to register dwc3 device\n");
goto err3;
}
return 0;
err4:
err3:
pci_set_drvdata(pci, NULL);
platform_device_put(dwc3);
err3:
err2:
dwc3_put_device_id(devid);
err2:
err1:
pci_disable_device(pci);
err1:
kfree(glue);
err0:
return ret;
}
@ -148,7 +147,6 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
pci_disable_device(pci);
kfree(glue);
}
static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {

View File

@ -76,8 +76,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
u32 len, u32 type)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_trb_hw *trb_hw;
struct dwc3_trb trb;
struct dwc3_trb *trb;
struct dwc3_ep *dep;
int ret;
@ -88,19 +87,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
return 0;
}
trb_hw = dwc->ep0_trb;
memset(&trb, 0, sizeof(trb));
trb = dwc->ep0_trb;
trb.trbctl = type;
trb.bplh = buf_dma;
trb.length = len;
trb->bpl = lower_32_bits(buf_dma);
trb->bph = upper_32_bits(buf_dma);
trb->size = len;
trb->ctrl = type;
trb.hwo = 1;
trb.lst = 1;
trb.ioc = 1;
trb.isp_imi = 1;
dwc3_trb_to_hw(&trb, trb_hw);
trb->ctrl |= (DWC3_TRB_CTRL_HWO
| DWC3_TRB_CTRL_LST
| DWC3_TRB_CTRL_IOC
| DWC3_TRB_CTRL_ISP_IMI);
memset(&params, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
@ -302,7 +299,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
dep = dwc->eps[0];
dwc->ep0_usb_req.dep = dep;
dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
dwc->ep0_usb_req.request.buf = dwc->setup_buf;
dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@ -315,9 +312,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip;
u32 wValue;
u32 wIndex;
u32 reg;
int ret;
u32 mode;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
@ -356,25 +351,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (!set)
return -EINVAL;
mode = wIndex >> 8;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
switch (mode) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
reg |= mode << 1;
break;
default:
return -EINVAL;
}
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
default:
return -EINVAL;
dwc->test_mode_nr = wIndex >> 8;
dwc->test_mode = true;
}
break;
@ -396,7 +374,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_RECIP_ENDPOINT:
switch (wValue) {
case USB_ENDPOINT_HALT:
dep = dwc3_wIndex_to_dep(dwc, wIndex);
dep = dwc3_wIndex_to_dep(dwc, wIndex);
if (!dep)
return -EINVAL;
ret = __dwc3_gadget_ep_set_halt(dep, set);
@ -470,8 +448,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
case DWC3_ADDRESS_STATE:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
if (!ret && cfg)
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
dwc->dev_state = DWC3_CONFIGURED_STATE;
dwc->resize_fifos = true;
dev_dbg(dwc->dev, "resize fifos flag SET\n");
}
break;
case DWC3_CONFIGURED_STATE:
@ -560,9 +541,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
{
struct dwc3_request *r = NULL;
struct usb_request *ur;
struct dwc3_trb trb;
struct dwc3_trb *trb;
struct dwc3_ep *ep0;
u32 transferred;
u32 length;
u8 epnum;
epnum = event->endpoint_number;
@ -573,16 +555,16 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
r = next_request(&ep0->request_list);
ur = &r->request;
dwc3_trb_to_nat(dwc->ep0_trb, &trb);
trb = dwc->ep0_trb;
length = trb->size & DWC3_TRB_SIZE_MASK;
if (dwc->ep0_bounced) {
transferred = min_t(u32, ur->length,
ep0->endpoint.maxpacket - trb.length);
ep0->endpoint.maxpacket - length);
memcpy(ur->buf, dwc->ep0_bounce, transferred);
dwc->ep0_bounced = false;
} else {
transferred = ur->length - trb.length;
transferred = ur->length - length;
ur->actual += transferred;
}
@ -614,6 +596,17 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
dwc3_gadget_giveback(dep, r, 0);
}
if (dwc->test_mode) {
int ret;
ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
if (ret < 0) {
dev_dbg(dwc->dev, "Invalid Test #%d\n",
dwc->test_mode_nr);
dwc3_ep0_stall_and_restart(dwc);
}
}
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
}
@ -624,6 +617,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
dep->flags &= ~DWC3_EP_BUSY;
dep->res_trans_idx = 0;
dwc->setup_packet_pending = false;
switch (dwc->ep0state) {
@ -679,7 +673,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
DWC3_TRBCTL_CONTROL_DATA);
} else if ((req->request.length % dep->endpoint.maxpacket)
&& (event->endpoint_number == 0)) {
dwc3_map_buffer_to_dma(req);
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
event->endpoint_number);
if (ret) {
dev_dbg(dwc->dev, "failed to map request\n");
return;
}
WARN_ON(req->request.length > dep->endpoint.maxpacket);
@ -694,7 +693,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
DWC3_TRBCTL_CONTROL_DATA);
} else {
dwc3_map_buffer_to_dma(req);
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
event->endpoint_number);
if (ret) {
dev_dbg(dwc->dev, "failed to map request\n");
return;
}
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
req->request.dma, req->request.length,
@ -720,6 +724,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
{
struct dwc3_ep *dep = dwc->eps[epnum];
if (dwc->resize_fifos) {
dev_dbg(dwc->dev, "starting to resize fifos\n");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}
WARN_ON(dwc3_ep0_start_control_status(dep));
}

View File

@ -54,68 +54,162 @@
#include "gadget.h"
#include "io.h"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
void dwc3_map_buffer_to_dma(struct dwc3_request *req)
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
* @mode: the mode to set (J, K SE0 NAK, Force Enable)
*
* Caller should take care of locking. This function will
* return 0 on success or -EINVAL if wrong Test Selector
* is passed
*/
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
{
struct dwc3 *dwc = req->dep->dwc;
u32 reg;
if (req->request.length == 0) {
/* req->request.dma = dwc->setup_buf_addr; */
return;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
switch (mode) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
reg |= mode << 1;
break;
default:
return -EINVAL;
}
if (req->request.num_sgs) {
int mapped;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
mapped = dma_map_sg(dwc->dev, req->request.sg,
req->request.num_sgs,
req->direction ? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
if (mapped < 0) {
dev_err(dwc->dev, "failed to map SGs\n");
return;
}
req->request.num_mapped_sgs = mapped;
return;
}
if (req->request.dma == DMA_ADDR_INVALID) {
req->request.dma = dma_map_single(dwc->dev, req->request.buf,
req->request.length, req->direction
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = true;
}
return 0;
}
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
/**
* dwc3_gadget_set_link_state - Sets USB Link to a particular State
* @dwc: pointer to our context structure
* @state: the state to put link into
*
* Caller should take care of locking. This function will
* return 0 on success or -ETIMEDOUT.
*/
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
{
struct dwc3 *dwc = req->dep->dwc;
int retries = 10000;
u32 reg;
if (req->request.length == 0) {
req->request.dma = DMA_ADDR_INVALID;
return;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
/* set requested state */
reg |= DWC3_DCTL_ULSTCHNGREQ(state);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* wait for a change in DSTS */
while (--retries) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
if (DWC3_DSTS_USBLNKST(reg) == state)
return 0;
udelay(5);
}
if (req->request.num_mapped_sgs) {
req->request.dma = DMA_ADDR_INVALID;
dma_unmap_sg(dwc->dev, req->request.sg,
req->request.num_mapped_sgs,
req->direction ? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
dev_vdbg(dwc->dev, "link state change request timed out\n");
req->request.num_mapped_sgs = 0;
return;
return -ETIMEDOUT;
}
/**
* dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
* @dwc: pointer to our context structure
*
* This function will a best effort FIFO allocation in order
* to improve FIFO usage and throughput, while still allowing
* us to enable as many endpoints as possible.
*
* Keep in mind that this operation will be highly dependent
* on the configured size for RAM1 - which contains TxFifo -,
* the amount of endpoints enabled on coreConsultant tool, and
* the width of the Master Bus.
*
* In the ideal world, we would always be able to satisfy the
* following equation:
*
* ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
* (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
*
* Unfortunately, due to many variables that's not always the case.
*/
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
{
int last_fifo_depth = 0;
int ram1_depth;
int fifo_size;
int mdwidth;
int num;
if (!dwc->needs_fifo_resize)
return 0;
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth >>= 3;
/*
* FIXME For now we will only allocate 1 wMaxPacketSize space
* for each enabled endpoint, later patches will come to
* improve this algorithm so that we better use the internal
* FIFO space
*/
for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) {
struct dwc3_ep *dep = dwc->eps[num];
int fifo_number = dep->number >> 1;
int mult = 1;
int tmp;
if (!(dep->number & 1))
continue;
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
if (usb_endpoint_xfer_bulk(dep->desc)
|| usb_endpoint_xfer_isoc(dep->desc))
mult = 3;
/*
* REVISIT: the following assumes we will always have enough
* space available on the FIFO RAM for all possible use cases.
* Make sure that's true somehow and change FIFO allocation
* accordingly.
*
* If we have Bulk or Isochronous endpoints, we want
* them to be able to be very, very fast. So we're giving
* those endpoints a fifo_size which is enough for 3 full
* packets
*/
tmp = mult * (dep->endpoint.maxpacket + mdwidth);
tmp += mdwidth;
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
fifo_size |= (last_fifo_depth << 16);
dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
dep->name, last_fifo_depth, fifo_size & 0xffff);
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
fifo_size);
last_fifo_depth += (fifo_size & 0xffff);
}
if (req->mapped) {
dma_unmap_single(dwc->dev, req->request.dma,
req->request.length, req->direction
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 0;
req->request.dma = DMA_ADDR_INVALID;
}
return 0;
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@ -144,14 +238,15 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS)
req->request.status = status;
dwc3_unmap_buffer_from_dma(req);
usb_gadget_unmap_request(&dwc->gadget, &req->request,
req->direction);
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
spin_unlock(&dwc->lock);
req->request.complete(&req->dep->endpoint, &req->request);
req->request.complete(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
}
@ -219,7 +314,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb_hw *trb)
struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
@ -368,9 +463,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return ret;
if (!(dep->flags & DWC3_EP_ENABLED)) {
struct dwc3_trb_hw *trb_st_hw;
struct dwc3_trb_hw *trb_link_hw;
struct dwc3_trb trb_link;
struct dwc3_trb *trb_st_hw;
struct dwc3_trb *trb_link;
ret = dwc3_gadget_set_xfer_resource(dwc, dep);
if (ret)
@ -390,15 +484,15 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
memset(&trb_link, 0, sizeof(trb_link));
/* Link TRB for ISOC. The HWO but is never reset */
/* Link TRB for ISOC. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
trb_link.hwo = true;
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
dwc3_trb_to_hw(&trb_link, trb_link_hw);
trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
}
return 0;
@ -440,6 +534,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dep->stream_capable = false;
dep->desc = NULL;
dep->endpoint.desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
dep->flags = 0;
@ -485,16 +580,16 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
strncat(dep->name, "-control", sizeof(dep->name));
strlcat(dep->name, "-control", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_ISOC:
strncat(dep->name, "-isoc", sizeof(dep->name));
strlcat(dep->name, "-isoc", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_BULK:
strncat(dep->name, "-bulk", sizeof(dep->name));
strlcat(dep->name, "-bulk", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_INT:
strncat(dep->name, "-int", sizeof(dep->name));
strlcat(dep->name, "-int", sizeof(dep->name));
break;
default:
dev_err(dwc->dev, "invalid endpoint transfer type\n");
@ -562,7 +657,6 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
req->epnum = dep->number;
req->dep = dep;
req->request.dma = DMA_ADDR_INVALID;
return &req->request;
}
@ -585,8 +679,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
unsigned length, unsigned last, unsigned chain)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb_hw *trb_hw;
struct dwc3_trb trb;
struct dwc3_trb *trb;
unsigned int cur_slot;
@ -595,7 +688,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
length, last ? " last" : "",
chain ? " chain" : "");
trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
cur_slot = dep->free_slot;
dep->free_slot++;
@ -604,40 +697,32 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
usb_endpoint_xfer_isoc(dep->desc))
return;
memset(&trb, 0, sizeof(trb));
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
req->trb = trb_hw;
req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
req->trb = trb;
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
if (usb_endpoint_xfer_isoc(dep->desc)) {
trb.isp_imi = true;
trb.csp = true;
} else {
trb.chn = chain;
trb.lst = last;
}
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
trb.sid_sofn = req->request.stream_id;
trb->size = DWC3_TRB_SIZE_LENGTH(length);
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
switch (usb_endpoint_type(dep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
trb.ioc = last;
trb->ctrl |= DWC3_TRB_CTRL_IOC;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
trb.trbctl = DWC3_TRBCTL_NORMAL;
trb->ctrl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
@ -647,11 +732,21 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
trb.length = length;
trb.bplh = dma;
trb.hwo = true;
if (usb_endpoint_xfer_isoc(dep->desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
} else {
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
dwc3_trb_to_hw(&trb, trb_hw);
if (last)
trb->ctrl |= DWC3_TRB_CTRL_LST;
}
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
}
/*
@ -659,14 +754,15 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
* @dep: endpoint for which requests are being prepared
* @starting: true if the endpoint is idle and no requests are queued.
*
* The functions goes through the requests list and setups TRBs for the
* transfers. The functions returns once there are not more TRBs available or
* it run out of requests.
* The function goes through the requests list and sets up TRBs for the
* transfers. The function returns once there are no more TRBs available or
* it runs out of requests.
*/
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
{
struct dwc3_request *req, *n;
u32 trbs_left;
u32 max;
unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@ -674,9 +770,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
/* the first request must not be queued */
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
/* Can't wrap around on a non-isoc EP since there's no link TRB */
if (!usb_endpoint_xfer_isoc(dep->desc)) {
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
if (trbs_left > max)
trbs_left = max;
}
/*
* if busy & slot are equal than it is either full or empty. If we are
* starting to proceed requests then we are empty. Otherwise we ar
* If busy & slot are equal than it is either full or empty. If we are
* starting to process requests then we are empty. Otherwise we are
* full and don't do anything
*/
if (!trbs_left) {
@ -687,7 +790,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
* In case we start from scratch, we queue the ISOC requests
* starting from slot 1. This is done because we use ring
* buffer and have no LST bit to stop us. Instead, we place
* IOC bit TRB_NUM/4. We try to avoid to having an interrupt
* IOC bit every TRB_NUM/4. We try to avoid having an interrupt
* after the first request so we start at slot 1 and have
* 7 requests proceed before we hit the first IOC.
* Other transfer types don't use the ring buffer and are
@ -723,8 +826,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
length = sg_dma_len(s);
dma = sg_dma_address(s);
if (i == (request->num_mapped_sgs - 1)
|| sg_is_last(s)) {
if (i == (request->num_mapped_sgs - 1) ||
sg_is_last(s)) {
last_one = true;
chain = false;
}
@ -792,8 +895,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
dwc3_prepare_trbs(dep, start_new);
/*
* req points to the first request where HWO changed
* from 0 to 1
* req points to the first request where HWO changed from 0 to 1
*/
req = next_request(&dep->req_queued);
}
@ -819,9 +921,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
/*
* FIXME we need to iterate over the list of requests
* here and stop, unmap, free and del each of the linked
* requests instead of we do now.
* requests instead of what we do now.
*/
dwc3_unmap_buffer_from_dma(req);
usb_gadget_unmap_request(&dwc->gadget, &req->request,
req->direction);
list_del(&req->list);
return ret;
}
@ -837,6 +940,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
int ret;
req->request.actual = 0;
req->request.status = -EINPROGRESS;
req->direction = dep->direction;
@ -852,9 +958,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* particular token from the Host side.
*
* This will also avoid Host cancelling URBs due to too
* many NACKs.
* many NAKs.
*/
dwc3_map_buffer_to_dma(req);
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->direction);
if (ret)
return ret;
list_add_tail(&req->list, &dep->request_list);
/*
@ -874,11 +984,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
int start_trans;
start_trans = 1;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
dep->flags & DWC3_EP_BUSY)
if (usb_endpoint_xfer_isoc(dep->desc) &&
(dep->flags & DWC3_EP_BUSY))
start_trans = 0;
ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
@ -1031,8 +1141,12 @@ out:
static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dep->flags |= DWC3_EP_WEDGE;
spin_unlock_irqrestore(&dwc->lock, flags);
return dwc3_gadget_ep_set_halt(ep, 1);
}
@ -1122,26 +1236,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
goto out;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
/*
* Switch link state to Recovery. In HS/FS/LS this means
* RemoteWakeup Request
*/
reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* wait for at least 2000us */
usleep_range(2000, 2500);
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
if (ret < 0) {
dev_err(dwc->dev, "failed to put link in Recovery\n");
goto out;
}
/* write zeroes to Link Change Request */
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* pool until Link State change to ON */
/* poll until Link State changes to ON */
timeout = jiffies + msecs_to_jiffies(100);
while (!(time_after(jiffies, timeout))) {
while (!time_after(jiffies, timeout)) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
@ -1164,8 +1272,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@ -1176,10 +1287,13 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
u32 timeout = 500;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on)
reg |= DWC3_DCTL_RUN_STOP;
else
if (is_on) {
reg &= ~DWC3_DCTL_TRGTULST_MASK;
reg |= (DWC3_DCTL_RUN_STOP
| DWC3_DCTL_TRGTULST_RX_DET);
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
}
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@ -1386,7 +1500,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
struct dwc3_request *req;
struct dwc3_trb trb;
struct dwc3_trb *trb;
unsigned int count;
unsigned int s_pkt = 0;
@ -1397,20 +1511,20 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
return 1;
}
dwc3_trb_to_nat(req->trb, &trb);
trb = req->trb;
if (trb.hwo && status != -ESHUTDOWN)
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
* can do. If we don't clean in up we loop for ever. If
* we skip the TRB than it gets overwritten reused after
* a while since we use them in a ring buffer. a BUG()
* would help. Lets hope that if this occures, someone
* can do. If we don't clean it up we loop forever. If
* we skip the TRB then it gets overwritten after a
* while since we use them in a ring buffer. A BUG()
* would help. Lets hope that if this occurs, someone
* fixes the root cause instead of looking away :)
*/
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
dep->name, req->trb);
count = trb.length;
count = trb->size & DWC3_TRB_SIZE_MASK;
if (dep->direction) {
if (count) {
@ -1434,13 +1548,16 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
dwc3_gadget_giveback(dep, req, status);
if (s_pkt)
break;
if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
if ((event->status & DEPEVT_STATUS_LST) &&
(trb->ctrl & DWC3_TRB_CTRL_LST))
break;
if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
if ((event->status & DEPEVT_STATUS_IOC) &&
(trb->ctrl & DWC3_TRB_CTRL_IOC))
break;
} while (1);
if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
if ((event->status & DEPEVT_STATUS_IOC) &&
(trb->ctrl & DWC3_TRB_CTRL_IOC))
return 0;
return 1;
}
@ -1455,11 +1572,9 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
if (clean_busy) {
clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
if (clean_busy)
dep->flags &= ~DWC3_EP_BUSY;
dep->res_trans_idx = 0;
}
/*
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@ -1490,7 +1605,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
{
u32 uf;
u32 uf, mask;
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
@ -1498,16 +1613,10 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
return;
}
if (event->parameters) {
u32 mask;
mask = ~(dep->interval - 1);
uf = event->parameters & mask;
/* 4 micro frames in the future */
uf += dep->interval * 4;
} else {
uf = 0;
}
mask = ~(dep->interval - 1);
uf = event->parameters & mask;
/* 4 micro frames in the future */
uf += dep->interval * 4;
__dwc3_gadget_kick_transfer(dep, uf, 1);
}
@ -1519,8 +1628,8 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
struct dwc3_event_depevt mod_ev = *event;
/*
* We were asked to remove one requests. It is possible that this
* request and a few other were started together and have the same
* We were asked to remove one request. It is possible that this
* request and a few others were started together and have the same
* transfer index. Since we stopped the complete endpoint we don't
* know how many requests were already completed (and not yet)
* reported and how could be done (later). We purge them all until
@ -1529,7 +1638,7 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
mod_ev.status = DEPEVT_STATUS_LST;
dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
dep->flags &= ~DWC3_EP_BUSY;
/* pending requets are ignored and are queued on XferNotReady */
/* pending requests are ignored and are queued on XferNotReady */
}
static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
@ -1570,6 +1679,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERCOMPLETE:
dep->res_trans_idx = 0;
if (usb_endpoint_xfer_isoc(dep->desc)) {
dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
dep->name);
@ -1594,7 +1705,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
int ret;
dev_vdbg(dwc->dev, "%s: reason %s\n",
dep->name, event->status
dep->name, event->status &
DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
: "Transfer Not Active");
@ -1805,6 +1917,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->test_mode = false;
dwc3_stop_active_transfers(dwc);
dwc3_clear_stall_all_ep(dwc);
@ -2082,7 +2195,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
while (left > 0) {
union dwc3_event event;
memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
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
@ -2123,7 +2237,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
/**
* dwc3_gadget_init - Initializes gadget related registers
* @dwc: Pointer to out controller context structure
* @dwc: pointer to our controller context structure
*
* Returns 0 on success otherwise negative errno.
*/
@ -2149,9 +2263,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err1;
}
dwc->setup_buf = dma_alloc_coherent(dwc->dev,
sizeof(*dwc->setup_buf) * 2,
&dwc->setup_buf_addr, GFP_KERNEL);
dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
GFP_KERNEL);
if (!dwc->setup_buf) {
dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
@ -2242,8 +2355,7 @@ err4:
dwc->ep0_bounce_addr);
err3:
dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
dwc->setup_buf, dwc->setup_buf_addr);
kfree(dwc->setup_buf);
err2:
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
@ -2272,8 +2384,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);
dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
dwc->setup_buf, dwc->setup_buf_addr);
kfree(dwc->setup_buf);
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
dwc->ep0_trb, dwc->ep0_trb_addr);

View File

@ -100,6 +100,9 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
@ -108,8 +111,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
void dwc3_map_buffer_to_dma(struct dwc3_request *req);
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW

View File

@ -53,7 +53,7 @@ int dwc3_host_init(struct dwc3 *dwc)
struct platform_device *xhci;
int ret;
xhci = platform_device_alloc("xhci", -1);
xhci = platform_device_alloc("xhci-hcd", -1);
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
ret = -ENOMEM;

View File

@ -599,16 +599,29 @@ config USB_AUDIO
depends on SND
select SND_PCM
help
Gadget Audio is compatible with USB Audio Class specification 1.0.
It will include at least one AudioControl interface, zero or more
AudioStream interface and zero or more MIDIStream interface.
Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
playback or capture audio stream.
This Gadget Audio driver is compatible with USB Audio Class
specification 2.0. It implements 1 AudioControl interface,
1 AudioStreaming Interface each for USB-OUT and USB-IN.
Number of channels, sample rate and sample size can be
specified as module parameters.
This driver doesn't expect any real Audio codec to be present
on the device - the audio streams are simply sinked to and
sourced from a virtual ALSA sound card created. The user-space
application may choose to do whatever it wants with the data
received from the USB Host and choose to provide whatever it
wants as audio data to the USB Host.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_audio".
config GADGET_UAC1
bool "UAC 1.0 (Legacy)"
depends on USB_AUDIO
help
If you instead want older UAC Spec-1.0 driver that also has audio
paths hardwired to the Audio codec chip on-board and doesn't work
without one.
config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET

View File

@ -29,7 +29,7 @@
/* Driver strings */
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
#define UDC_DRIVER_VERSION_STRING "01.00.0206"
/* system */
#include <linux/module.h>
@ -140,7 +140,7 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
/* endpoint names used for print */
static const char ep0_string[] = "ep0in";
static const char *ep_string[] = {
static const char *const ep_string[] = {
ep0_string,
"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
@ -204,9 +204,8 @@ static void print_regs(struct udc *dev)
DBG(dev, "DMA mode = BF (buffer fill mode)\n");
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
}
if (!use_dma) {
if (!use_dma)
dev_info(&dev->pdev->dev, "FIFO mode\n");
}
DBG(dev, "-------------------------------------------------------\n");
}
@ -445,6 +444,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
VDBG(ep->dev, "ep-%d reset\n", ep->num);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.ops = &udc_ep_ops;
INIT_LIST_HEAD(&ep->queue);
@ -569,9 +569,8 @@ udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
/* free dma chain if created */
if (req->chain_len > 1) {
if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
}
pci_pool_free(ep->dev->data_requests, req->td_data,
req->td_phys);
@ -639,9 +638,8 @@ udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
bytes = remaining;
/* dwords first */
for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
writel(*(buf + i), ep->txfifo);
}
/* remaining bytes must be written by byte access */
for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
@ -660,9 +658,8 @@ static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
for (i = 0; i < dwords; i++) {
for (i = 0; i < dwords; i++)
*(buf + i) = readl(dev->rxfifo);
}
return 0;
}
@ -675,9 +672,8 @@ static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
/* dwords first */
for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
}
/* remaining bytes must be read by byte access */
if (bytes % UDC_DWORD_BYTES) {
@ -831,20 +827,8 @@ __acquires(ep->dev->lock)
dev = ep->dev;
/* unmap DMA */
if (req->dma_mapping) {
if (ep->in)
pci_unmap_single(dev->pdev,
req->req.dma,
req->req.length,
PCI_DMA_TODEVICE);
else
pci_unmap_single(dev->pdev,
req->req.dma,
req->req.length,
PCI_DMA_FROMDEVICE);
req->dma_mapping = 0;
req->req.dma = DMA_DONT_USE;
}
if (ep->dma)
usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
halted = ep->halted;
ep->halted = 1;
@ -897,9 +881,8 @@ static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
struct udc_data_dma *td;
td = req->td_data;
while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
td = phys_to_virt(td->next);
}
return td;
@ -949,21 +932,18 @@ static int udc_create_dma_chain(
dma_addr = DMA_DONT_USE;
/* unset L bit in first desc for OUT */
if (!ep->in) {
if (!ep->in)
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
}
/* alloc only new desc's if not already available */
len = req->req.length / ep->ep.maxpacket;
if (req->req.length % ep->ep.maxpacket) {
if (req->req.length % ep->ep.maxpacket)
len++;
}
if (len > req->chain_len) {
/* shorter chain already allocated before */
if (req->chain_len > 1) {
if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
}
req->chain_len = len;
create_new_chain = 1;
}
@ -1006,11 +986,12 @@ static int udc_create_dma_chain(
/* link td and assign tx bytes */
if (i == buf_len) {
if (create_new_chain) {
if (create_new_chain)
req->td_data->next = dma_addr;
} else {
/* req->td_data->next = virt_to_phys(td); */
}
/*
else
req->td_data->next = virt_to_phys(td);
*/
/* write tx bytes */
if (ep->in) {
/* first desc */
@ -1024,11 +1005,12 @@ static int udc_create_dma_chain(
UDC_DMA_IN_STS_TXBYTES);
}
} else {
if (create_new_chain) {
if (create_new_chain)
last->next = dma_addr;
} else {
/* last->next = virt_to_phys(td); */
}
/*
else
last->next = virt_to_phys(td);
*/
if (ep->in) {
/* write tx bytes */
td->status = AMD_ADDBITS(td->status,
@ -1095,20 +1077,11 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
return -ESHUTDOWN;
/* map dma (usually done before) */
if (ep->dma && usbreq->length != 0
&& (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
if (ep->dma) {
VDBG(dev, "DMA map req %p\n", req);
if (ep->in)
usbreq->dma = pci_map_single(dev->pdev,
usbreq->buf,
usbreq->length,
PCI_DMA_TODEVICE);
else
usbreq->dma = pci_map_single(dev->pdev,
usbreq->buf,
usbreq->length,
PCI_DMA_FROMDEVICE);
req->dma_mapping = 1;
retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
if (retval)
return retval;
}
VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
@ -1479,11 +1452,10 @@ static int startup_registers(struct udc *dev)
/* program speed */
tmp = readl(&dev->regs->cfg);
if (use_fullspeed) {
if (use_fullspeed)
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
} else {
else
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
}
writel(tmp, &dev->regs->cfg);
return 0;
@ -1504,9 +1476,8 @@ static void udc_basic_init(struct udc *dev)
mod_timer(&udc_timer, jiffies - 1);
}
/* stop poll stall timer */
if (timer_pending(&udc_pollstall_timer)) {
if (timer_pending(&udc_pollstall_timer))
mod_timer(&udc_pollstall_timer, jiffies - 1);
}
/* disable DMA */
tmp = readl(&dev->regs->ctl);
tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
@ -1540,11 +1511,10 @@ static void udc_setup_endpoints(struct udc *dev)
/* read enum speed */
tmp = readl(&dev->regs->sts);
tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
dev->gadget.speed = USB_SPEED_HIGH;
} else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
dev->gadget.speed = USB_SPEED_FULL;
}
/* set basic ep parameters */
for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
@ -1570,9 +1540,8 @@ static void udc_setup_endpoints(struct udc *dev)
* disabling ep interrupts when ENUM interrupt occurs but ep is
* not enabled by gadget driver
*/
if (!ep->desc) {
if (!ep->desc)
ep_init(dev->regs, ep);
}
if (use_dma) {
/*
@ -1670,9 +1639,8 @@ static void udc_tasklet_disconnect(unsigned long par)
spin_lock(&dev->lock);
/* empty queues */
for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
empty_req_queue(&dev->ep[tmp]);
}
}
@ -1746,9 +1714,8 @@ static void udc_timer_function(unsigned long v)
* open the fifo
*/
udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
if (!stop_timer) {
if (!stop_timer)
add_timer(&udc_timer);
}
} else {
/*
* fifo contains data now, setup timer for opening
@ -1760,9 +1727,8 @@ static void udc_timer_function(unsigned long v)
set_rde++;
/* debug: lhadmot_timer_start = 221070 */
udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
if (!stop_timer) {
if (!stop_timer)
add_timer(&udc_timer);
}
}
} else
@ -1907,19 +1873,17 @@ static void activate_control_endpoints(struct udc *dev)
mod_timer(&udc_timer, jiffies - 1);
}
/* stop pollstall timer */
if (timer_pending(&udc_pollstall_timer)) {
if (timer_pending(&udc_pollstall_timer))
mod_timer(&udc_pollstall_timer, jiffies - 1);
}
/* enable DMA */
tmp = readl(&dev->regs->ctl);
tmp |= AMD_BIT(UDC_DEVCTL_MODE)
| AMD_BIT(UDC_DEVCTL_RDE)
| AMD_BIT(UDC_DEVCTL_TDE);
if (use_dma_bufferfill_mode) {
if (use_dma_bufferfill_mode)
tmp |= AMD_BIT(UDC_DEVCTL_BF);
} else if (use_dma_ppb_du) {
else if (use_dma_ppb_du)
tmp |= AMD_BIT(UDC_DEVCTL_DU);
}
writel(tmp, &dev->regs->ctl);
}
@ -2104,9 +2068,8 @@ static void udc_ep0_set_rde(struct udc *dev)
udc_timer.expires =
jiffies + HZ/UDC_RDE_TIMER_DIV;
set_rde = 1;
if (!stop_timer) {
if (!stop_timer)
add_timer(&udc_timer);
}
}
}
}
@ -2131,7 +2094,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
if (use_dma) {
/* BNA event ? */
if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
DBG(dev, "BNA ep%dout occurred - DESPTR = %x \n",
DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n",
ep->num, readl(&ep->regs->desptr));
/* clear BNA */
writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
@ -2294,9 +2257,8 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
jiffies
+ HZ*UDC_RDE_TIMER_SECONDS;
set_rde = 1;
if (!stop_timer) {
if (!stop_timer)
add_timer(&udc_timer);
}
}
if (ep->num != UDC_EP0OUT_IX)
dev->data_ep_queued = 0;
@ -2318,9 +2280,8 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
/* check pending CNAKS */
if (cnak_pending) {
/* CNAk processing when rxfifo empty only */
if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
udc_process_cnak_queue(dev);
}
}
/* clear OUT bits in ep status */
@ -2348,7 +2309,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* BNA ? */
if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
dev_err(&dev->pdev->dev,
"BNA ep%din occurred - DESPTR = %08lx \n",
"BNA ep%din occurred - DESPTR = %08lx\n",
ep->num,
(unsigned long) readl(&ep->regs->desptr));
@ -2361,7 +2322,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* HE event ? */
if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
dev_err(&dev->pdev->dev,
"HE ep%dn occurred - DESPTR = %08lx \n",
"HE ep%dn occurred - DESPTR = %08lx\n",
ep->num, (unsigned long) readl(&ep->regs->desptr));
/* clear HE */
@ -2427,9 +2388,9 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* write fifo */
udc_txfifo_write(ep, &req->req);
len = req->req.length - req->req.actual;
if (len > ep->ep.maxpacket)
len = ep->ep.maxpacket;
req->req.actual += len;
if (len > ep->ep.maxpacket)
len = ep->ep.maxpacket;
req->req.actual += len;
if (req->req.actual == req->req.length
|| (len != ep->ep.maxpacket)) {
/* complete req */
@ -2581,9 +2542,8 @@ __acquires(dev->lock)
if (!timer_pending(&udc_timer)) {
udc_timer.expires = jiffies +
HZ/UDC_RDE_TIMER_DIV;
if (!stop_timer) {
if (!stop_timer)
add_timer(&udc_timer);
}
}
}
@ -2697,9 +2657,8 @@ __acquires(dev->lock)
/* check pending CNAKS */
if (cnak_pending) {
/* CNAk processing when rxfifo empty only */
if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
udc_process_cnak_queue(dev);
}
}
finished:
@ -2723,7 +2682,7 @@ static irqreturn_t udc_control_in_isr(struct udc *dev)
tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
/* DMA completion */
if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
VDBG(dev, "isr: TDC clear \n");
VDBG(dev, "isr: TDC clear\n");
ret_val = IRQ_HANDLED;
/* clear TDC bit */
@ -3426,7 +3385,7 @@ static int udc_remote_wakeup(struct udc *dev)
}
/* PCI device parameters */
static const struct pci_device_id pci_id[] = {
static DEFINE_PCI_DEVICE_TABLE(pci_id) = {
{
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
.class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,

View File

@ -29,7 +29,6 @@
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/prefetch.h>
#include <asm/byteorder.h>
#include <mach/hardware.h>
@ -558,6 +557,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
/* restore the endpoint's pristine config */
ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.maxpacket = ep->maxpacket;
/* reset fifos and endpoint */

View File

@ -659,6 +659,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
return -EINVAL;
}
ep->desc = NULL;
ep->ep.desc = NULL;
list_splice_init(&ep->queue, &req_list);
if (ep->can_dma) {

View File

@ -14,10 +14,8 @@
#include <linux/kernel.h>
#include <linux/utsname.h>
#include "u_audio.h"
#define DRIVER_DESC "Linux USB Audio Gadget"
#define DRIVER_VERSION "Dec 18, 2008"
#define DRIVER_VERSION "Feb 2, 2012"
/*-------------------------------------------------------------------------*/
@ -33,8 +31,36 @@
#include "config.c"
#include "epautoconf.c"
#include "u_audio.c"
#include "f_audio.c"
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
static char manufacturer[50];
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *audio_strings[] = {
&stringtab_dev,
NULL,
};
#ifdef CONFIG_GADGET_UAC1
#include "u_uac1.h"
#include "u_uac1.c"
#include "f_uac1.c"
#else
#include "f_uac2.c"
#endif
/*-------------------------------------------------------------------------*/
@ -54,9 +80,15 @@ static struct usb_device_descriptor device_desc = {
.bcdUSB = __constant_cpu_to_le16(0x200),
#ifdef CONFIG_GADGET_UAC1
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
#else
.bDeviceClass = USB_CLASS_MISC,
.bDeviceSubClass = 0x02,
.bDeviceProtocol = 0x01,
#endif
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id defaults change according to what configs
@ -108,6 +140,9 @@ static struct usb_configuration audio_config_driver = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
#ifndef CONFIG_GADGET_UAC1
.unbind = uac2_unbind_config,
#endif
};
/*-------------------------------------------------------------------------*/
@ -157,7 +192,9 @@ fail:
static int __exit audio_unbind(struct usb_composite_dev *cdev)
{
#ifdef CONFIG_GADGET_UAC1
gaudio_cleanup();
#endif
return 0;
}

View File

@ -37,10 +37,10 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
* Put the transceiver in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
val = otg_io_read(udc->transceiver, ULPI_FUNC_CTRL);
val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
otg_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
break;
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");

View File

@ -2181,6 +2181,7 @@ static int ep_disable(struct usb_ep *ep)
} while (mEp->dir != direction);
mEp->desc = NULL;
mEp->ep.desc = NULL;
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
@ -2537,7 +2538,7 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return usb_phy_set_power(udc->transceiver, mA);
return -ENOTSUPP;
}
@ -2900,7 +2901,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
if (retval < 0)
goto free_udc;
udc->transceiver = otg_get_transceiver();
udc->transceiver = usb_get_transceiver();
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (udc->transceiver == NULL) {
@ -2928,7 +2929,8 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
goto unreg_device;
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
retval = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (retval)
goto remove_dbg;
}
@ -2945,8 +2947,8 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
remove_trans:
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);
otg_put_transceiver(udc->transceiver);
otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
usb_put_transceiver(udc->transceiver);
}
err("error = %i", retval);
@ -2958,7 +2960,7 @@ unreg_device:
device_unregister(&udc->gadget.dev);
put_transceiver:
if (udc->transceiver)
otg_put_transceiver(udc->transceiver);
usb_put_transceiver(udc->transceiver);
free_udc:
kfree(udc);
_udc = NULL;
@ -2981,8 +2983,8 @@ static void udc_remove(void)
usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);
otg_put_transceiver(udc->transceiver);
otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
usb_put_transceiver(udc->transceiver);
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);

View File

@ -136,7 +136,7 @@ struct ci13xxx {
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
int vbus_active; /* is VBUS active */
struct otg_transceiver *transceiver; /* Transceiver struct */
struct usb_phy *transceiver; /* Transceiver struct */
};
/******************************************************************************

File diff suppressed because it is too large Load Diff

View File

@ -275,24 +275,24 @@ struct usb_ep *usb_ep_autoconfig_ss(
/* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep (gadget, "ep-e");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep;
goto found_ep;
ep = find_ep (gadget, "ep-f");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep;
goto found_ep;
} else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */
ep = find_ep(gadget, "ep3-bulk");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep;
goto found_ep;
} else if (USB_ENDPOINT_XFER_BULK == type
&& (USB_DIR_IN & desc->bEndpointAddress)) {
/* DMA may be available */
ep = find_ep(gadget, "ep2-bulk");
if (ep && ep_matches(gadget, ep, desc,
ep_comp))
return ep;
goto found_ep;
}
#ifdef CONFIG_BLACKFIN
@ -311,18 +311,22 @@ struct usb_ep *usb_ep_autoconfig_ss(
} else
ep = NULL;
if (ep && ep_matches(gadget, ep, desc, ep_comp))
return ep;
goto found_ep;
#endif
}
/* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
if (ep_matches(gadget, ep, desc, ep_comp))
return ep;
goto found_ep;
}
/* Fail */
return NULL;
found_ep:
ep->desc = NULL;
ep->comp_desc = NULL;
return ep;
}
/**

View File

@ -5,7 +5,7 @@
* Copyright (C) 2008 by David Brownell
* Copyright (C) 2008 by Nokia Corporation
* Copyright (C) 2009 by Samsung Electronics
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
* Author: Michal Nazarewicz (mina86@mina86.com)
*
* This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation,
@ -237,6 +237,42 @@ static struct usb_descriptor_header *acm_hs_function[] = {
NULL,
};
static struct usb_endpoint_descriptor acm_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 acm_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 acm_ss_bulk_comp_desc = {
.bLength = sizeof acm_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
};
static struct usb_descriptor_header *acm_ss_function[] = {
(struct usb_descriptor_header *) &acm_iad_descriptor,
(struct usb_descriptor_header *) &acm_control_interface_desc,
(struct usb_descriptor_header *) &acm_header_desc,
(struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
(struct usb_descriptor_header *) &acm_descriptor,
(struct usb_descriptor_header *) &acm_union_desc,
(struct usb_descriptor_header *) &acm_hs_notify_desc,
(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
(struct usb_descriptor_header *) &acm_data_interface_desc,
(struct usb_descriptor_header *) &acm_ss_in_desc,
(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
(struct usb_descriptor_header *) &acm_ss_out_desc,
(struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
NULL,
};
/* string descriptors: */
#define ACM_CTRL_IDX 0
@ -643,9 +679,21 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors */
f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
}
if (gadget_is_superspeed(c->cdev->gadget)) {
acm_ss_in_desc.bEndpointAddress =
acm_fs_in_desc.bEndpointAddress;
acm_ss_out_desc.bEndpointAddress =
acm_fs_out_desc.bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
if (!f->ss_descriptors)
goto fail;
}
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
acm->port_num,
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
acm->port.in->name, acm->port.out->name,
acm->notify->name);
@ -675,6 +723,8 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
usb_free_descriptors(f->descriptors);
gs_free_req(acm->notify, acm->notify_req);
kfree(acm);

View File

@ -97,6 +97,20 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g)
/* interface descriptor: */
static struct usb_interface_assoc_descriptor
ecm_iad_descriptor = {
.bLength = sizeof ecm_iad_descriptor,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
/* .bFirstInterface = DYNAMIC, */
.bInterfaceCount = 2, /* control + data */
.bFunctionClass = USB_CLASS_COMM,
.bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
.bFunctionProtocol = USB_CDC_PROTO_NONE,
/* .iFunction = DYNAMIC */
};
static struct usb_interface_descriptor ecm_control_intf = {
.bLength = sizeof ecm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@ -199,6 +213,7 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_fs_function[] = {
/* CDC ECM control descriptors */
(struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@ -247,6 +262,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_hs_function[] = {
/* CDC ECM control descriptors */
(struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@ -339,6 +355,7 @@ static struct usb_string ecm_string_defs[] = {
[0].s = "CDC Ethernet Control Model (ECM)",
[1].s = NULL /* DYNAMIC */,
[2].s = "CDC Ethernet Data",
[3].s = "CDC ECM",
{ } /* end of list */
};
@ -674,6 +691,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (status < 0)
goto fail;
ecm->ctrl_id = status;
ecm_iad_descriptor.bFirstInterface = status;
ecm_control_intf.bInterfaceNumber = status;
ecm_union_desc.bMasterInterface0 = status;
@ -864,6 +882,13 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
return status;
ecm_string_defs[1].id = status;
ecm_desc.iMACAddress = status;
/* IAD label */
status = usb_string_id(c->cdev);
if (status < 0)
return status;
ecm_string_defs[3].id = status;
ecm_iad_descriptor.iFunction = status;
}
/* allocate and initialize one new instance */

View File

@ -2,7 +2,7 @@
* f_fs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
* Author: Michal Nazarewicz <mina86@mina86.com>
*
* Based on inode.c (GadgetFS) which was:
* Copyright (C) 2003-2004 David Brownell

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyright (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
* Author: Michal Nazarewicz <mina86@mina86.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -304,7 +304,6 @@
static const char fsg_string_interface[] = "Mass Storage";
#define FSG_NO_INTR_EP 1
#define FSG_NO_DEVICE_STRINGS 1
#define FSG_NO_OTG 1
#define FSG_NO_INTR_EP 1
@ -620,7 +619,7 @@ static int fsg_setup(struct usb_function *f,
switch (ctrl->bRequest) {
case USB_BULK_RESET_REQUEST:
case US_BULK_RESET_REQUEST:
if (ctrl->bRequestType !=
(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@ -636,7 +635,7 @@ static int fsg_setup(struct usb_function *f,
raise_exception(fsg->common, FSG_STATE_RESET);
return DELAYED_STATUS;
case USB_BULK_GET_MAX_LUN_REQUEST:
case US_BULK_GET_MAX_LUN:
if (ctrl->bRequestType !=
(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@ -1742,7 +1741,7 @@ static int send_status(struct fsg_common *common)
struct fsg_buffhd *bh;
struct bulk_cs_wrap *csw;
int rc;
u8 status = USB_STATUS_PASS;
u8 status = US_BULK_STAT_OK;
u32 sd, sdinfo = 0;
/* Wait for the next buffer to become available */
@ -1763,11 +1762,11 @@ static int send_status(struct fsg_common *common)
if (common->phase_error) {
DBG(common, "sending phase-error status\n");
status = USB_STATUS_PHASE_ERROR;
status = US_BULK_STAT_PHASE;
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
DBG(common, "sending command-failure status\n");
status = USB_STATUS_FAIL;
status = US_BULK_STAT_FAIL;
VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@ -1776,12 +1775,12 @@ static int send_status(struct fsg_common *common)
/* Store and send the Bulk-only CSW */
csw = (void *)bh->buf;
csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
csw->Tag = common->tag;
csw->Residue = cpu_to_le32(common->residue);
csw->Status = status;
bh->inreq->length = USB_BULK_CS_WRAP_LEN;
bh->inreq->length = US_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
if (!start_in_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
@ -2221,7 +2220,7 @@ unknown_cmnd:
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
struct fsg_bulk_cb_wrap *cbw = req->buf;
struct bulk_cb_wrap *cbw = req->buf;
struct fsg_common *common = fsg->common;
/* Was this a real packet? Should it be ignored? */
@ -2229,9 +2228,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
return -EINVAL;
/* Is the CBW valid? */
if (req->actual != USB_BULK_CB_WRAP_LEN ||
if (req->actual != US_BULK_CB_WRAP_LEN ||
cbw->Signature != cpu_to_le32(
USB_BULK_CB_SIG)) {
US_BULK_CB_SIGN)) {
DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
req->actual,
le32_to_cpu(cbw->Signature));
@ -2253,7 +2252,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
/* Is the CBW meaningful? */
if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
@ -2273,7 +2272,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Save the command for later */
common->cmnd_size = cbw->Length;
memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
if (cbw->Flags & USB_BULK_IN_FLAG)
if (cbw->Flags & US_BULK_FLAG_IN)
common->data_dir = DATA_DIR_TO_HOST;
else
common->data_dir = DATA_DIR_FROM_HOST;
@ -2303,7 +2302,7 @@ static int get_next_command(struct fsg_common *common)
}
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;

View File

@ -780,7 +780,7 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
midi->out_ep->driver_data = cdev; /* claim */
/* allocate temporary function list */
midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(midi_function),
midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
GFP_KERNEL);
if (!midi_function) {
status = -ENOMEM;

View File

@ -5,7 +5,7 @@
* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
* Copyright (C) 2008 Nokia Corporation
* Copyright (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
* Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -99,6 +99,34 @@ static struct usb_descriptor_header *gser_hs_function[] __initdata = {
NULL,
};
static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
.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 = {
.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 = {
.bLength = sizeof gser_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
};
static struct usb_descriptor_header *gser_ss_function[] __initdata = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_ss_in_desc,
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
(struct usb_descriptor_header *) &gser_ss_out_desc,
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
NULL,
};
/* string descriptors: */
static struct usb_string gser_string_defs[] = {
@ -201,9 +229,21 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
}
if (gadget_is_superspeed(c->cdev->gadget)) {
gser_ss_in_desc.bEndpointAddress =
gser_fs_in_desc.bEndpointAddress;
gser_ss_out_desc.bEndpointAddress =
gser_fs_out_desc.bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
if (!f->ss_descriptors)
goto fail;
}
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
gser->port_num,
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
gser->port.in->name, gser->port.out->name);
return 0;
@ -225,6 +265,8 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
{
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
usb_free_descriptors(f->descriptors);
kfree(func_to_gser(f));
}

View File

@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/atomic.h>
#include "u_audio.h"
#include "u_uac1.h"
#define OUT_EP_MAX_PACKET_SIZE 200
static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
@ -216,29 +216,6 @@ static struct usb_descriptor_header *f_audio_desc[] __initdata = {
NULL,
};
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
static char manufacturer[50];
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *audio_strings[] = {
&stringtab_dev,
NULL,
};
/*
* This function is an ALSA sound card following USB Audio Class Spec 1.0.
*/

1449
drivers/usb/gadget/f_uac2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -855,7 +855,7 @@ static int class_setup_req(struct fsg_dev *fsg,
if (transport_is_bbb()) {
switch (ctrl->bRequest) {
case USB_BULK_RESET_REQUEST:
case US_BULK_RESET_REQUEST:
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@ -871,7 +871,7 @@ static int class_setup_req(struct fsg_dev *fsg,
value = DELAYED_STATUS;
break;
case USB_BULK_GET_MAX_LUN_REQUEST:
case US_BULK_GET_MAX_LUN:
if (ctrl->bRequestType != (USB_DIR_IN |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@ -2125,7 +2125,7 @@ static int send_status(struct fsg_dev *fsg)
struct fsg_lun *curlun = fsg->curlun;
struct fsg_buffhd *bh;
int rc;
u8 status = USB_STATUS_PASS;
u8 status = US_BULK_STAT_OK;
u32 sd, sdinfo = 0;
/* Wait for the next buffer to become available */
@ -2146,11 +2146,11 @@ static int send_status(struct fsg_dev *fsg)
if (fsg->phase_error) {
DBG(fsg, "sending phase-error status\n");
status = USB_STATUS_PHASE_ERROR;
status = US_BULK_STAT_PHASE;
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
DBG(fsg, "sending command-failure status\n");
status = USB_STATUS_FAIL;
status = US_BULK_STAT_FAIL;
VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@ -2160,12 +2160,12 @@ static int send_status(struct fsg_dev *fsg)
struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
csw->Tag = fsg->tag;
csw->Residue = cpu_to_le32(fsg->residue);
csw->Status = status;
bh->inreq->length = USB_BULK_CS_WRAP_LEN;
bh->inreq->length = US_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
start_transfer(fsg, fsg->bulk_in, bh->inreq,
&bh->inreq_busy, &bh->state);
@ -2609,16 +2609,16 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
struct fsg_bulk_cb_wrap *cbw = req->buf;
struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? Should it be ignored? */
if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
return -EINVAL;
/* Is the CBW valid? */
if (req->actual != USB_BULK_CB_WRAP_LEN ||
if (req->actual != US_BULK_CB_WRAP_LEN ||
cbw->Signature != cpu_to_le32(
USB_BULK_CB_SIG)) {
US_BULK_CB_SIGN)) {
DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
req->actual,
le32_to_cpu(cbw->Signature));
@ -2638,7 +2638,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
/* Is the CBW meaningful? */
if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
@ -2656,7 +2656,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Save the command for later */
fsg->cmnd_size = cbw->Length;
memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
if (cbw->Flags & USB_BULK_IN_FLAG)
if (cbw->Flags & US_BULK_FLAG_IN)
fsg->data_dir = DATA_DIR_TO_HOST;
else
fsg->data_dir = DATA_DIR_FROM_HOST;
@ -2685,7 +2685,7 @@ static int get_next_command(struct fsg_dev *fsg)
}
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);

View File

@ -1638,6 +1638,7 @@ static int qe_ep_disable(struct usb_ep *_ep)
/* Nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->tx_req = NULL;
qe_ep_reset(udc, ep->epnum);

View File

@ -659,6 +659,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@ -768,7 +769,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
* @is_last: return flag if it is the last dTD of the request
* return: pointer to the built dTD */
static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
dma_addr_t *dma, int *is_last)
dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
{
u32 swap_temp;
struct ep_td_struct *dtd;
@ -777,7 +778,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
*length = min(req->req.length - req->req.actual,
(unsigned)EP_MAX_LENGTH_TRANSFER);
dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma);
if (dtd == NULL)
return dtd;
@ -827,7 +828,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
}
/* Generate dtd chain for a request */
static int fsl_req_to_dtd(struct fsl_req *req)
static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
{
unsigned count;
int is_last;
@ -836,7 +837,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
dma_addr_t dma;
do {
dtd = fsl_build_dtd(req, &count, &dma, &is_last);
dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
if (dtd == NULL)
return -ENOMEM;
@ -910,13 +911,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->req.actual = 0;
req->dtd_count = 0;
spin_lock_irqsave(&udc->lock, flags);
/* build dtds and push them to device queue */
if (!fsl_req_to_dtd(req)) {
if (!fsl_req_to_dtd(req, gfp_flags)) {
spin_lock_irqsave(&udc->lock, flags);
fsl_queue_td(ep, req);
} else {
spin_unlock_irqrestore(&udc->lock, flags);
return -ENOMEM;
}
@ -1217,7 +1216,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
udc = container_of(gadget, struct fsl_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return usb_phy_set_power(udc->transceiver, mA);
return -ENOTSUPP;
}
@ -1295,7 +1294,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
if (fsl_req_to_dtd(req) == 0)
if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req);
else
return -ENOMEM;
@ -1379,7 +1378,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->mapped = 1;
/* prime the data phase */
if ((fsl_req_to_dtd(req) == 0))
if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
fsl_queue_td(ep, req);
else /* no mem */
goto stall;
@ -1966,7 +1965,8 @@ static int fsl_start(struct usb_gadget_driver *driver,
/* connect to bus through transceiver */
if (udc_controller->transceiver) {
retval = otg_set_peripheral(udc_controller->transceiver,
retval = otg_set_peripheral(
udc_controller->transceiver->otg,
&udc_controller->gadget);
if (retval < 0) {
ERR("can't bind to transceiver\n");
@ -2006,7 +2006,7 @@ static int fsl_stop(struct usb_gadget_driver *driver)
return -EINVAL;
if (udc_controller->transceiver)
otg_set_peripheral(udc_controller->transceiver, NULL);
otg_set_peripheral(udc_controller->transceiver->otg, NULL);
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
@ -2430,7 +2430,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
udc_controller->transceiver = otg_get_transceiver();
udc_controller->transceiver = usb_get_transceiver();
if (!udc_controller->transceiver) {
ERR("Can't find OTG driver!\n");
ret = -ENODEV;

View File

@ -471,7 +471,7 @@ struct fsl_udc {
struct usb_ctrlrequest local_setup_buff;
spinlock_t lock;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
unsigned softconnect:1;
unsigned vbus_active:1;
unsigned stopped:1;

View File

@ -2,7 +2,7 @@
* g_ffs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
* Author: Michal Nazarewicz <mina86@mina86.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -235,6 +235,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
ep->ep.maxpacket = MAX_FIFO_SIZE;
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->irqs = 0;
ep->dma = 0;
@ -310,12 +311,9 @@ done(struct goku_ep *ep, struct goku_request *req, int status)
status = req->req.status;
dev = ep->dev;
if (req->mapped) {
pci_unmap_single(dev->pdev, req->req.dma, req->req.length,
ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
}
if (ep->dma)
usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
#ifndef USB_TRACE
if (status && status != -ESHUTDOWN)
@ -736,10 +734,11 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -EBUSY;
/* set up dma mapping in case the caller didn't */
if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
_req->dma = pci_map_single(dev->pdev, _req->buf, _req->length,
ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
req->mapped = 1;
if (ep->dma) {
status = usb_gadget_map_request(&dev->gadget, &req->req,
ep->is_in);
if (status)
return status;
}
#ifdef USB_TRACE

View File

@ -60,9 +60,9 @@ static struct usb_device_descriptor device_desc = {
/* .bDeviceClass = USB_CLASS_COMM, */
/* .bDeviceSubClass = 0, */
/* .bDeviceProtocol = 0, */
.bDeviceClass = 0xEF,
.bDeviceSubClass = 2,
.bDeviceProtocol = 1,
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id can be overridden by module parameters. */

View File

@ -1043,6 +1043,8 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
// FIXME don't call this with the spinlock held ...
if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
else
retval = len;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
}

View File

@ -401,16 +401,7 @@ static void done(struct langwell_ep *ep, struct langwell_request *req,
dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
}
if (req->mapped) {
dma_unmap_single(&dev->pdev->dev,
req->req.dma, req->req.length,
is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
} else
dma_sync_single_for_cpu(&dev->pdev->dev, req->req.dma,
req->req.length,
is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
if (status != -ESHUTDOWN)
dev_dbg(&dev->pdev->dev,
@ -487,6 +478,7 @@ static int langwell_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&dev->lock, flags);
@ -749,7 +741,8 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
struct langwell_ep *ep;
struct langwell_udc *dev;
unsigned long flags;
int is_iso = 0, zlflag = 0;
int is_iso = 0;
int ret;
/* always require a cpu-view buffer */
req = container_of(_req, struct langwell_request, req);
@ -776,33 +769,10 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
/* set up dma mapping in case the caller didn't */
if (_req->dma == DMA_ADDR_INVALID) {
/* WORKAROUND: WARN_ON(size == 0) */
if (_req->length == 0) {
dev_vdbg(&dev->pdev->dev, "req->length: 0->1\n");
zlflag = 1;
_req->length++;
}
_req->dma = dma_map_single(&dev->pdev->dev,
_req->buf, _req->length,
is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (zlflag && (_req->length == 1)) {
dev_vdbg(&dev->pdev->dev, "req->length: 1->0\n");
zlflag = 0;
_req->length = 0;
}
req->mapped = 1;
dev_vdbg(&dev->pdev->dev, "req->mapped = 1\n");
} else {
dma_sync_single_for_device(&dev->pdev->dev,
_req->dma, _req->length,
is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 0;
dev_vdbg(&dev->pdev->dev, "req->mapped = 0\n");
}
/* set up dma mapping */
ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
if (ret)
return ret;
dev_dbg(&dev->pdev->dev,
"%s queue req %p, len %u, buf %p, dma 0x%08x\n",
@ -1261,9 +1231,9 @@ static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
if (dev->transceiver) {
dev_vdbg(&dev->pdev->dev, "otg_set_power\n");
dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
return otg_set_power(dev->transceiver, mA);
return usb_phy_set_power(dev->transceiver, mA);
}
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
@ -1906,7 +1876,7 @@ static int langwell_stop(struct usb_gadget *g,
/* unbind OTG transceiver */
if (dev->transceiver)
(void)otg_set_peripheral(dev->transceiver, 0);
(void)otg_set_peripheral(dev->transceiver->otg, 0);
/* disable interrupt and set controller to stop state */
langwell_udc_stop(dev);

View File

@ -162,7 +162,7 @@ struct langwell_udc {
spinlock_t lock; /* device lock */
struct langwell_ep *ep;
struct usb_gadget_driver *driver;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
u8 dev_addr;
u32 usb_state;
u32 resume_state;

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyright (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
* Author: Michal Nazarewicz <mina86@mina86.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify

View File

@ -4,7 +4,7 @@
* Copyright (C) 2008 David Brownell
* Copyright (C) 2008 Nokia Corporation
* Copyright (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
* Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -217,7 +217,7 @@ struct mv_udc {
struct work_struct vbus_work;
struct workqueue_struct *qwork;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
struct mv_usb_platform_data *pdata;

View File

@ -608,6 +608,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@ -771,8 +772,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
udc->ep0_state = DATA_STATE_XMIT;
/* irq handler advances the queue */
if (req != NULL)
list_add_tail(&req->queue, &ep->queue);
list_add_tail(&req->queue, &ep->queue);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
@ -1384,7 +1384,8 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
}
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
retval = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (retval) {
dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n");
@ -2181,7 +2182,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG)
udc->transceiver = otg_get_transceiver();
udc->transceiver = usb_get_transceiver();
#endif
udc->clknum = pdata->clknum;

View File

@ -385,12 +385,9 @@ net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status)
status = req->req.status;
dev = ep->dev;
if (use_dma && req->mapped) {
dma_unmap_single(dev->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 (use_dma && ep->dma)
usb_gadget_unmap_request(&dev->gadget, &req->req,
ep->is_in);
if (status && status != -ESHUTDOWN)
dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n",
@ -850,10 +847,11 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -ESHUTDOWN;
/* set up dma mapping in case the caller didn't */
if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) {
_req->dma = dma_map_single(dev->dev, _req->buf, _req->length,
ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
if (use_dma && ep->dma) {
status = usb_gadget_map_request(&dev->gadget, _req,
ep->is_in);
if (status)
return status;
}
dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n",

View File

@ -806,12 +806,8 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status)
status = req->req.status;
dev = ep->dev;
if (req->mapped) {
pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
}
if (ep->dma)
usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
if (status && status != -ESHUTDOWN)
VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
@ -857,10 +853,13 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -EOPNOTSUPP;
/* set up dma mapping in case the caller didn't */
if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
_req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
req->mapped = 1;
if (ep->dma) {
int ret;
ret = usb_gadget_map_request(&dev->gadget, _req,
ep->is_in);
if (ret)
return ret;
}
#if 0

View File

@ -251,6 +251,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&ep->udc->lock, flags);
ep->desc = NULL;
ep->ep.desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
ep->has_dma = 0;
@ -1213,7 +1214,7 @@ static int omap_wakeup(struct usb_gadget *gadget)
/* NOTE: non-OTG systems may use SRP TOO... */
} else if (!(udc->devstat & UDC_ATT)) {
if (udc->transceiver)
retval = otg_start_srp(udc->transceiver);
retval = otg_start_srp(udc->transceiver->otg);
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -1345,7 +1346,7 @@ static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA)
udc = container_of(gadget, struct omap_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@ -1839,11 +1840,13 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
spin_lock(&udc->lock);
}
if (udc->transceiver)
otg_set_suspend(udc->transceiver, 1);
usb_phy_set_suspend(
udc->transceiver, 1);
} else {
VDBG("resume\n");
if (udc->transceiver)
otg_set_suspend(udc->transceiver, 0);
usb_phy_set_suspend(
udc->transceiver, 0);
if (udc->gadget.speed == USB_SPEED_FULL
&& udc->driver->resume) {
spin_unlock(&udc->lock);
@ -2154,7 +2157,8 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
/* connect to bus through transceiver */
if (udc->transceiver) {
status = otg_set_peripheral(udc->transceiver, &udc->gadget);
status = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (status < 0) {
ERR("can't bind to transceiver\n");
if (driver->unbind) {
@ -2200,7 +2204,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
(void) otg_set_peripheral(udc->transceiver, NULL);
(void) otg_set_peripheral(udc->transceiver->otg, NULL);
else
pullup_disable(udc);
@ -2650,7 +2654,7 @@ static void omap_udc_release(struct device *dev)
}
static int __init
omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
{
unsigned tmp, buf;
@ -2790,7 +2794,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
{
int status = -ENODEV;
int hmc;
struct otg_transceiver *xceiv = NULL;
struct usb_phy *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data;
struct clk *dc_clk;
@ -2863,7 +2867,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
* use it. Except for OTG, we don't _need_ to talk to one;
* but not having one probably means no VBUS detection.
*/
xceiv = otg_get_transceiver();
xceiv = usb_get_transceiver();
if (xceiv)
type = xceiv->label;
else if (config->otg) {
@ -3009,7 +3013,7 @@ cleanup1:
cleanup0:
if (xceiv)
otg_put_transceiver(xceiv);
usb_put_transceiver(xceiv);
if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
clk_disable(hhc_clk);
@ -3039,7 +3043,7 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
pullup_disable(udc);
if (udc->transceiver) {
otg_put_transceiver(udc->transceiver);
usb_put_transceiver(udc->transceiver);
udc->transceiver = NULL;
}
omap_writew(0, UDC_SYSCON1);

View File

@ -164,7 +164,7 @@ struct omap_udc {
struct omap_ep ep[32];
u16 devstat;
u16 clr_halt;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
struct list_head iso;
unsigned softconnect:1;
unsigned vbus_active:1;

View File

@ -15,6 +15,14 @@
#include <linux/interrupt.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/gpio.h>
#include <linux/irq.h>
/* GPIO port for VBUS detecting */
static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */
#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */
/* Address offset of Registers */
#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
@ -295,6 +303,21 @@ struct pch_udc_ep {
unsigned long epsts;
};
/**
* struct pch_vbus_gpio_data - Structure holding GPIO informaton
* for detecting VBUS
* @port: gpio port number
* @intr: gpio interrupt number
* @irq_work_fall Structure for WorkQueue
* @irq_work_rise Structure for WorkQueue
*/
struct pch_vbus_gpio_data {
int port;
int intr;
struct work_struct irq_work_fall;
struct work_struct irq_work_rise;
};
/**
* struct pch_udc_dev - Structure holding complete information
* of the PCH USB device
@ -311,6 +334,7 @@ struct pch_udc_ep {
* @registered: driver regsitered with system
* @suspended: driver in suspended state
* @connected: gadget driver associated
* @vbus_session: required vbus_session state
* @set_cfg_not_acked: pending acknowledgement 4 setup
* @waiting_zlp_ack: pending acknowledgement 4 ZLP
* @data_requests: DMA pool for data requests
@ -322,6 +346,7 @@ struct pch_udc_ep {
* @base_addr: for mapped device memory
* @irq: IRQ line for the device
* @cfg_data: current cfg, intf, and alt in use
* @vbus_gpio: GPIO informaton for detecting VBUS
*/
struct pch_udc_dev {
struct usb_gadget gadget;
@ -337,6 +362,7 @@ struct pch_udc_dev {
registered:1,
suspended:1,
connected:1,
vbus_session:1,
set_cfg_not_acked:1,
waiting_zlp_ack:1;
struct pci_pool *data_requests;
@ -347,7 +373,8 @@ struct pch_udc_dev {
unsigned long phys_addr;
void __iomem *base_addr;
unsigned irq;
struct pch_udc_cfg_data cfg_data;
struct pch_udc_cfg_data cfg_data;
struct pch_vbus_gpio_data vbus_gpio;
};
#define PCH_UDC_PCI_BAR 1
@ -553,6 +580,29 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
}
/**
* pch_udc_reconnect() - This API initializes usb device controller,
* and clear the disconnect status.
* @dev: Reference to pch_udc_regs structure
*/
static void pch_udc_init(struct pch_udc_dev *dev);
static void pch_udc_reconnect(struct pch_udc_dev *dev)
{
pch_udc_init(dev);
/* enable device interrupts */
/* pch_udc_enable_interrupts() */
pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
UDC_DEVINT_UR | UDC_DEVINT_ENUM);
/* Clear the disconnect */
pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
mdelay(1);
/* Resume USB signalling */
pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
}
/**
* pch_udc_vbus_session() - set or clearr the disconnect status.
* @dev: Reference to pch_udc_regs structure
@ -563,10 +613,18 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
int is_active)
{
if (is_active)
pch_udc_clear_disconnect(dev);
else
if (is_active) {
pch_udc_reconnect(dev);
dev->vbus_session = 1;
} else {
if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
pch_udc_set_disconnect(dev);
dev->vbus_session = 0;
}
}
/**
@ -1126,7 +1184,17 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
if (!gadget)
return -EINVAL;
dev = container_of(gadget, struct pch_udc_dev, gadget);
pch_udc_vbus_session(dev, is_on);
if (is_on) {
pch_udc_reconnect(dev);
} else {
if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
pch_udc_set_disconnect(dev);
}
return 0;
}
@ -1182,6 +1250,188 @@ static const struct usb_gadget_ops pch_udc_ops = {
.stop = pch_udc_stop,
};
/**
* pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status.
* @dev: Reference to the driver structure
*
* Return value:
* 1: VBUS is high
* 0: VBUS is low
* -1: It is not enable to detect VBUS using GPIO
*/
static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev)
{
int vbus = 0;
if (dev->vbus_gpio.port)
vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0;
else
vbus = -1;
return vbus;
}
/**
* pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low.
* If VBUS is Low, disconnect is processed
* @irq_work: Structure for WorkQueue
*
*/
static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
{
struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
struct pch_vbus_gpio_data, irq_work_fall);
struct pch_udc_dev *dev =
container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
int vbus_saved = -1;
int vbus;
int count;
if (!dev->vbus_gpio.port)
return;
for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL);
count++) {
vbus = pch_vbus_gpio_get_value(dev);
if ((vbus_saved == vbus) && (vbus == 0)) {
dev_dbg(&dev->pdev->dev, "VBUS fell");
if (dev->driver
&& dev->driver->disconnect) {
dev->driver->disconnect(
&dev->gadget);
}
if (dev->vbus_gpio.intr)
pch_udc_init(dev);
else
pch_udc_reconnect(dev);
return;
}
vbus_saved = vbus;
mdelay(PCH_VBUS_INTERVAL);
}
}
/**
* pch_vbus_gpio_work_rise() - This API checks VBUS is High.
* If VBUS is High, connect is processed
* @irq_work: Structure for WorkQueue
*
*/
static void pch_vbus_gpio_work_rise(struct work_struct *irq_work)
{
struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
struct pch_vbus_gpio_data, irq_work_rise);
struct pch_udc_dev *dev =
container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
int vbus;
if (!dev->vbus_gpio.port)
return;
mdelay(PCH_VBUS_INTERVAL);
vbus = pch_vbus_gpio_get_value(dev);
if (vbus == 1) {
dev_dbg(&dev->pdev->dev, "VBUS rose");
pch_udc_reconnect(dev);
return;
}
}
/**
* pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS
* @irq: Interrupt request number
* @dev: Reference to the device structure
*
* Return codes:
* 0: Success
* -EINVAL: GPIO port is invalid or can't be initialized.
*/
static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
{
struct pch_udc_dev *dev = (struct pch_udc_dev *)data;
if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr)
return IRQ_NONE;
if (pch_vbus_gpio_get_value(dev))
schedule_work(&dev->vbus_gpio.irq_work_rise);
else
schedule_work(&dev->vbus_gpio.irq_work_fall);
return IRQ_HANDLED;
}
/**
* pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
* @dev: Reference to the driver structure
* @vbus_gpio Number of GPIO port to detect gpio
*
* Return codes:
* 0: Success
* -EINVAL: GPIO port is invalid or can't be initialized.
*/
static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
{
int err;
int irq_num = 0;
dev->vbus_gpio.port = 0;
dev->vbus_gpio.intr = 0;
if (vbus_gpio_port <= -1)
return -EINVAL;
err = gpio_is_valid(vbus_gpio_port);
if (!err) {
pr_err("%s: gpio port %d is invalid\n",
__func__, vbus_gpio_port);
return -EINVAL;
}
err = gpio_request(vbus_gpio_port, "pch_vbus");
if (err) {
pr_err("%s: can't request gpio port %d, err: %d\n",
__func__, vbus_gpio_port, err);
return -EINVAL;
}
dev->vbus_gpio.port = vbus_gpio_port;
gpio_direction_input(vbus_gpio_port);
INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
irq_num = gpio_to_irq(vbus_gpio_port);
if (irq_num > 0) {
irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH);
err = request_irq(irq_num, pch_vbus_gpio_irq, 0,
"vbus_detect", dev);
if (!err) {
dev->vbus_gpio.intr = irq_num;
INIT_WORK(&dev->vbus_gpio.irq_work_rise,
pch_vbus_gpio_work_rise);
} else {
pr_err("%s: can't request irq %d, err: %d\n",
__func__, irq_num, err);
}
}
return 0;
}
/**
* pch_vbus_gpio_free() - This API frees resources of GPIO port
* @dev: Reference to the driver structure
*/
static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
{
if (dev->vbus_gpio.intr)
free_irq(dev->vbus_gpio.intr, dev);
if (dev->vbus_gpio.port)
gpio_free(dev->vbus_gpio.port);
}
/**
* complete_req() - This API is invoked from the driver when processing
* of a request is complete
@ -1493,6 +1743,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
pch_udc_ep_disable(ep);
pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
ep->desc = NULL;
ep->ep.desc = NULL;
INIT_LIST_HEAD(&ep->queue);
spin_unlock_irqrestore(&ep->dev->lock, iflags);
return 0;
@ -2335,8 +2586,11 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
/* Complete request queue */
empty_req_queue(ep);
}
if (dev->driver && dev->driver->disconnect)
if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
}
/**
@ -2371,6 +2625,11 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
pch_udc_set_dma(dev, DMA_DIR_TX);
pch_udc_set_dma(dev, DMA_DIR_RX);
pch_udc_ep_set_rrdy(&(dev->ep[UDC_EP0OUT_IDX]));
/* enable device interrupts */
pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US |
UDC_DEVINT_ES | UDC_DEVINT_ENUM |
UDC_DEVINT_SI | UDC_DEVINT_SC);
}
/**
@ -2459,12 +2718,18 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
*/
static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
{
int vbus;
/* USB Reset Interrupt */
if (dev_intr & UDC_DEVINT_UR)
if (dev_intr & UDC_DEVINT_UR) {
pch_udc_svc_ur_interrupt(dev);
dev_dbg(&dev->pdev->dev, "USB_RESET\n");
}
/* Enumeration Done Interrupt */
if (dev_intr & UDC_DEVINT_ENUM)
if (dev_intr & UDC_DEVINT_ENUM) {
pch_udc_svc_enum_interrupt(dev);
dev_dbg(&dev->pdev->dev, "USB_ENUM\n");
}
/* Set Interface Interrupt */
if (dev_intr & UDC_DEVINT_SI)
pch_udc_svc_intf_interrupt(dev);
@ -2472,8 +2737,30 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
if (dev_intr & UDC_DEVINT_SC)
pch_udc_svc_cfg_interrupt(dev);
/* USB Suspend interrupt */
if (dev_intr & UDC_DEVINT_US)
if (dev_intr & UDC_DEVINT_US) {
if (dev->driver
&& dev->driver->suspend) {
spin_unlock(&dev->lock);
dev->driver->suspend(&dev->gadget);
spin_lock(&dev->lock);
}
vbus = pch_vbus_gpio_get_value(dev);
if ((dev->vbus_session == 0)
&& (vbus != 1)) {
if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
pch_udc_reconnect(dev);
} else if ((dev->vbus_session == 0)
&& (vbus == 1)
&& !dev->vbus_gpio.intr)
schedule_work(&dev->vbus_gpio.irq_work_fall);
dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
}
/* Clear the SOF interrupt, if enabled */
if (dev_intr & UDC_DEVINT_SOF)
dev_dbg(&dev->pdev->dev, "SOF\n");
@ -2499,6 +2786,14 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev)
dev_intr = pch_udc_read_device_interrupts(dev);
ep_intr = pch_udc_read_ep_interrupts(dev);
/* For a hot plug, this find that the controller is hung up. */
if (dev_intr == ep_intr)
if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
/* The controller is reset */
pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
return IRQ_HANDLED;
}
if (dev_intr)
/* Clear device interrupts */
pch_udc_write_device_interrupts(dev, dev_intr);
@ -2625,6 +2920,7 @@ static int pch_udc_pcd_init(struct pch_udc_dev *dev)
{
pch_udc_init(dev);
pch_udc_pcd_reinit(dev);
pch_vbus_gpio_init(dev, vbus_gpio_port);
return 0;
}
@ -2725,7 +3021,8 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
pch_udc_setup_ep0(dev);
/* clear SD */
pch_udc_clear_disconnect(dev);
if ((pch_vbus_gpio_get_value(dev) != 0) || !dev->vbus_gpio.intr)
pch_udc_clear_disconnect(dev);
dev->connected = 1;
return 0;
@ -2803,6 +3100,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
kfree(dev->ep0out_buf);
pch_vbus_gpio_free(dev);
pch_udc_exit(dev);
if (dev->irq_registered)
@ -2912,8 +3211,10 @@ static int pch_udc_probe(struct pci_dev *pdev,
}
pch_udc = dev;
/* initialize the hardware */
if (pch_udc_pcd_init(dev))
if (pch_udc_pcd_init(dev)) {
retval = -ENODEV;
goto finished;
}
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
dev)) {
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,

View File

@ -283,6 +283,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
pxa25x_ep_fifo_flush (_ep);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
local_irq_restore(flags);
@ -995,7 +996,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
udc = container_of(_gadget, struct pxa25x_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@ -1192,6 +1193,7 @@ static void udc_reinit(struct pxa25x_udc *dev)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
ep->pio_irqs = 0;
@ -1301,7 +1303,8 @@ fail:
/* connect to bus through transceiver */
if (dev->transceiver) {
retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
retval = otg_set_peripheral(dev->transceiver->otg,
&dev->gadget);
if (retval) {
DMSG("can't bind to transceiver\n");
if (driver->unbind)
@ -1360,7 +1363,7 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
local_irq_enable();
if (dev->transceiver)
(void) otg_set_peripheral(dev->transceiver, NULL);
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
@ -2159,7 +2162,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
dev->transceiver = otg_get_transceiver();
dev->transceiver = usb_get_transceiver();
if (gpio_is_valid(dev->mach->gpio_pullup)) {
if ((retval = gpio_request(dev->mach->gpio_pullup,
@ -2238,7 +2241,7 @@ lubbock_fail0:
gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup:
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
usb_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
clk_put(dev->clk);
@ -2280,7 +2283,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
clk_put(dev->clk);
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
usb_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}

View File

@ -119,7 +119,7 @@ struct pxa25x_udc {
struct device *dev;
struct clk *clk;
struct pxa2xx_udc_mach_info *mach;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];

View File

@ -1666,7 +1666,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
udc = to_gadget_udc(_gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@ -1835,7 +1835,8 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
driver->driver.name);
if (udc->transceiver) {
retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
retval = otg_set_peripheral(udc->transceiver->otg,
&udc->gadget);
if (retval) {
dev_err(udc->dev, "can't bind to transceiver\n");
goto transceiver_fail;
@ -1908,7 +1909,7 @@ static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
driver->driver.name);
if (udc->transceiver)
return otg_set_peripheral(udc->transceiver, NULL);
return otg_set_peripheral(udc->transceiver->otg, NULL);
return 0;
}
@ -2463,7 +2464,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
udc->dev = &pdev->dev;
udc->mach = pdev->dev.platform_data;
udc->transceiver = otg_get_transceiver();
udc->transceiver = usb_get_transceiver();
gpio = udc->mach->gpio_pullup;
if (gpio_is_valid(gpio)) {
@ -2542,7 +2543,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
if (gpio_is_valid(gpio))
gpio_free(gpio);
otg_put_transceiver(udc->transceiver);
usb_put_transceiver(udc->transceiver);
udc->transceiver = NULL;
platform_set_drvdata(_dev, NULL);

View File

@ -447,7 +447,7 @@ struct pxa_udc {
struct usb_gadget_driver *driver;
struct device *dev;
struct pxa2xx_udc_mach_info *mach;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
enum ep0_state ep0state;
struct udc_stats stats;

View File

@ -663,11 +663,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
ep->fifoctr = D0FIFOCTR;
/* dma mapping */
req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597),
req->req.buf, req->req.length,
dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
return 0;
return usb_gadget_map_request(&r8a66597->gadget, &req->req, dma->dir);
}
static void sudmac_free_channel(struct r8a66597 *r8a66597,
@ -677,9 +673,7 @@ static void sudmac_free_channel(struct r8a66597 *r8a66597,
if (!r8a66597_is_sudmac(r8a66597))
return;
dma_unmap_single(r8a66597_to_dev(ep->r8a66597),
req->req.dma, req->req.length,
ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
usb_gadget_unmap_request(&r8a66597->gadget, &req->req, ep->dma->dir);
r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel);

View File

@ -30,6 +30,7 @@
#include <linux/prefetch.h>
#include <linux/platform_data/s3c-hsudc.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <mach/regs-s3c2443-clock.h>
@ -145,7 +146,7 @@ struct s3c_hsudc {
struct usb_gadget_driver *driver;
struct device *dev;
struct s3c24xx_hsudc_platdata *pd;
struct otg_transceiver *transceiver;
struct usb_phy *transceiver;
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
spinlock_t lock;
void __iomem *regs;
@ -759,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
unsigned long flags;
u32 ecr = 0;
hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
hsep = our_ep(_ep);
if (!_ep || !desc || hsep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| hsep->bEndpointAddress != desc->bEndpointAddress
@ -816,6 +817,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 1;
spin_unlock_irqrestore(&hsudc->lock, flags);
@ -853,7 +855,7 @@ static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req)
{
struct s3c_hsudc_req *hsreq;
hsreq = container_of(_req, struct s3c_hsudc_req, req);
hsreq = our_req(_req);
WARN_ON(!list_empty(&hsreq->queue));
kfree(hsreq);
}
@ -876,12 +878,12 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req,
u32 offset;
u32 csr;
hsreq = container_of(_req, struct s3c_hsudc_req, req);
hsreq = our_req(_req);
if ((!_req || !_req->complete || !_req->buf ||
!list_empty(&hsreq->queue)))
return -EINVAL;
hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
hsep = our_ep(_ep);
hsudc = hsep->dev;
if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
@ -935,7 +937,7 @@ static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct s3c_hsudc_req *hsreq;
unsigned long flags;
hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
hsep = our_ep(_ep);
if (!_ep || hsep->ep.name == ep0name)
return -EINVAL;
@ -1005,6 +1007,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
hsep->ep.ops = &s3c_hsudc_ep_ops;
hsep->fifo = hsudc->regs + S3C_BR(epnum);
hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 0;
hsep->wedge = 0;
@ -1166,7 +1169,8 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
/* connect to bus through transceiver */
if (hsudc->transceiver) {
ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
ret = otg_set_peripheral(hsudc->transceiver->otg,
&hsudc->gadget);
if (ret) {
dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
hsudc->gadget.name);
@ -1178,6 +1182,9 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
s3c_hsudc_reconfig(hsudc);
pm_runtime_get_sync(hsudc->dev);
s3c_hsudc_init_phy();
if (hsudc->pd->gpio_init)
hsudc->pd->gpio_init();
@ -1208,13 +1215,16 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
pm_runtime_put(hsudc->dev);
if (hsudc->pd->gpio_uninit)
hsudc->pd->gpio_uninit();
s3c_hsudc_stop_activity(hsudc);
spin_unlock_irqrestore(&hsudc->lock, flags);
if (hsudc->transceiver)
(void) otg_set_peripheral(hsudc->transceiver, NULL);
(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
disable_irq(hsudc->irq);
@ -1243,7 +1253,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
return -ENODEV;
if (hsudc->transceiver)
return otg_set_power(hsudc->transceiver, mA);
return usb_phy_set_power(hsudc->transceiver, mA);
return -EOPNOTSUPP;
}
@ -1275,7 +1285,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
hsudc->dev = dev;
hsudc->pd = pdev->dev.platform_data;
hsudc->transceiver = otg_get_transceiver();
hsudc->transceiver = usb_get_transceiver();
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
@ -1362,6 +1372,8 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
if (ret)
goto err_add_udc;
pm_runtime_enable(dev);
return 0;
err_add_udc:
device_unregister(&hsudc->gadget.dev);
@ -1377,7 +1389,7 @@ err_remap:
release_mem_region(res->start, resource_size(res));
err_res:
if (hsudc->transceiver)
otg_put_transceiver(hsudc->transceiver);
usb_put_transceiver(hsudc->transceiver);
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:

View File

@ -1148,6 +1148,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 1;
s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
@ -1630,6 +1631,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
ep->dev = dev;
ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 0;
INIT_LIST_HEAD (&ep->queue);
}

View File

@ -242,7 +242,7 @@ static struct usb_composite_driver gserial_driver = {
.name = "g_serial",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_HIGH,
.max_speed = USB_SPEED_SUPER,
};
static int __init init(void)

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyeight (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
* Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -145,48 +145,8 @@
#endif /* DUMP_MSGS */
/*-------------------------------------------------------------------------*/
/* Bulk-only data structures */
/* Command Block Wrapper */
struct fsg_bulk_cb_wrap {
__le32 Signature; /* Contains 'USBC' */
u32 Tag; /* Unique per command id */
__le32 DataTransferLength; /* Size of the data */
u8 Flags; /* Direction in bit 7 */
u8 Lun; /* LUN (normally 0) */
u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
u8 CDB[16]; /* Command Data Block */
};
#define USB_BULK_CB_WRAP_LEN 31
#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
#define USB_BULK_IN_FLAG 0x80
/* Command Status Wrapper */
struct bulk_cs_wrap {
__le32 Signature; /* Should = 'USBS' */
u32 Tag; /* Same as original command */
__le32 Residue; /* Amount not transferred */
u8 Status; /* See below */
};
#define USB_BULK_CS_WRAP_LEN 13
#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
#define USB_STATUS_PASS 0
#define USB_STATUS_FAIL 1
#define USB_STATUS_PHASE_ERROR 2
/* Bulk-only class specific requests */
#define USB_BULK_RESET_REQUEST 0xff
#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
/* CBI Interrupt data structure */
struct interrupt_data {
u8 bType;

View File

@ -1,5 +1,5 @@
/*
* u_audio.c -- ALSA audio utilities for Gadget stack
* u_uac1.c -- ALSA audio utilities for Gadget stack
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
@ -17,7 +17,7 @@
#include <linux/random.h>
#include <linux/syscalls.h>
#include "u_audio.h"
#include "u_uac1.h"
/*
* This component encapsulates the ALSA devices for USB audio gadget

View File

@ -1,5 +1,5 @@
/*
* u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities
* u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc

View File

@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@ -49,6 +50,57 @@ static DEFINE_MUTEX(udc_lock);
/* ------------------------------------------------------------------------- */
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
if (req->length == 0)
return 0;
if (req->num_sgs) {
int mapped;
mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (mapped == 0) {
dev_err(&gadget->dev, "failed to map SGs\n");
return -EFAULT;
}
req->num_mapped_sgs = mapped;
} else {
req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (dma_mapping_error(&gadget->dev, req->dma)) {
dev_err(&gadget->dev, "failed to map buffer\n");
return -EFAULT;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request);
void usb_gadget_unmap_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
if (req->length == 0)
return;
if (req->num_mapped_sgs) {
dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0;
} else {
dma_unmap_single(&gadget->dev, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
/* ------------------------------------------------------------------------- */
/**
* usb_gadget_start - tells usb device controller to start up
* @gadget: The gadget we want to get started

View File

@ -196,7 +196,7 @@ config USB_EHCI_S5P
config USB_EHCI_MV
bool "EHCI support for Marvell on-chip controller"
depends on USB_EHCI_HCD
depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP)
select USB_EHCI_ROOT_HUB_TT
---help---
Enables support for Marvell (including PXA and MMP series) on-chip
@ -606,10 +606,3 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
config USB_PXA168_EHCI
bool "Marvell PXA168 on-chip EHCI HCD support"
depends on USB_EHCI_HCD && ARCH_MMP
help
Enable support for Marvell PXA168 SoC's on-chip EHCI
host controller

View File

@ -107,7 +107,7 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
HCC_32FRAME_PERIODIC_LIST(params) ?
" 32 peridic list" : "");
" 32 periodic list" : "");
}
}
#else

View File

@ -142,12 +142,12 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
ehci->transceiver = otg_get_transceiver();
ehci->transceiver = usb_get_transceiver();
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
hcd, ehci, ehci->transceiver);
if (ehci->transceiver) {
retval = otg_set_host(ehci->transceiver,
retval = otg_set_host(ehci->transceiver->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
if (ehci->transceiver)
@ -194,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
if (ehci->transceiver) {
otg_set_host(ehci->transceiver, NULL);
otg_set_host(ehci->transceiver->otg, NULL);
put_device(ehci->transceiver->dev);
}
@ -216,6 +216,8 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
unsigned int port_offset)
{
u32 portsc;
struct usb_hcd *hcd = ehci_to_hcd(ehci);
void __iomem *non_ehci = hcd->regs;
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
@ -231,6 +233,8 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
/* enable UTMI PHY */
setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN);
portsc |= PORT_PTS_UTMI;
break;
case FSL_USB2_PHY_NONE:
@ -252,22 +256,19 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if (pdata->have_sysif_regs) {
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
/*
* Turn on cache snooping hardware, since some PowerPC platforms
* wholly rely on hardware to deal with cache coherent
*/
/* Setup Snooping for all the 4GB space */
/* SNOOP1 starts from 0x0, size 2G */
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
/* SNOOP2 starts from 0x80000000, size 2G */
out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
}
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
/*
* Turn on cache snooping hardware, since some PowerPC platforms
* wholly rely on hardware to deal with cache coherent
*/
/* Setup Snooping for all the 4GB space */
/* SNOOP1 starts from 0x0, size 2G */
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
/* SNOOP2 starts from 0x80000000, size 2G */
out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
#endif
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
@ -316,7 +317,9 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
struct fsl_usb2_platform_data *pdata;
struct device *dev;
dev = hcd->self.controller;
pdata = hcd->self.controller->platform_data;
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
@ -346,6 +349,16 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
ehci_reset(ehci);
if (of_device_is_compatible(dev->parent->of_node,
"fsl,mpc5121-usb2-dr")) {
/*
* set SBUSCFG:AHBBRST so that control msgs don't
* fail when doing heavy PATA writes.
*/
ehci_writel(ehci, SBUSCFG_INCR8,
hcd->regs + FSL_SOC_USB_SBUSCFG);
}
retval = ehci_fsl_reinit(ehci);
return retval;
}
@ -469,6 +482,8 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
/* restore EHCI registers */
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);

View File

@ -19,6 +19,8 @@
#define _EHCI_FSL_H
/* offsets for the non-ehci registers in the FSL SOC USB controller */
#define FSL_SOC_USB_SBUSCFG 0x90
#define SBUSCFG_INCR8 0x02 /* INCR8, specified */
#define FSL_SOC_USB_ULPIVP 0x170
#define FSL_SOC_USB_PORTSC1 0x184
#define PORT_PTS_MSK (3<<30)
@ -45,5 +47,7 @@
#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
#define CTRL_UTMI_PHY_EN (1<<9)
#define CTRL_PHY_CLK_VALID (1 << 17)
#define SNOOP_SIZE_2GB 0x1e
#endif /* _EHCI_FSL_H */

View File

@ -1361,11 +1361,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_grlib_driver
#endif
#ifdef CONFIG_USB_PXA168_EHCI
#include "ehci-pxa168.c"
#define PLATFORM_DRIVER ehci_pxa168_driver
#endif
#ifdef CONFIG_CPU_XLR
#include "ehci-xls.c"
#define PLATFORM_DRIVER ehci_xls_driver
@ -1376,6 +1371,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mv_driver
#endif
#ifdef CONFIG_MACH_LOONGSON1
#include "ehci-ls1x.c"
#define PLATFORM_DRIVER ehci_ls1x_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)

View File

@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
ehci->owned_ports = 0;
}
static int ehci_port_change(struct ehci_hcd *ehci)
static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
{
int i = HCS_N_PORTS(ehci->hcs_params);
@ -727,7 +727,7 @@ static int ehci_hub_control (
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
&& hcd->self.b_hnp_enable) {
otg_start_hnp(ehci->transceiver);
otg_start_hnp(ehci->transceiver->otg);
break;
}
#endif
@ -1076,7 +1076,8 @@ error_exit:
return retval;
}
static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
int portnum)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@ -1085,7 +1086,8 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
set_owner(ehci, --portnum, PORT_OWNER);
}
static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
int portnum)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 __iomem *reg;

View File

@ -0,0 +1,159 @@
/*
* Bus Glue for Loongson LS1X built-in EHCI controller.
*
* Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include <linux/platform_device.h>
static int ehci_ls1x_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int ret;
ehci->caps = hcd->regs;
ret = ehci_setup(hcd);
if (ret)
return ret;
ehci_port_power(ehci, 0);
return 0;
}
static const struct hc_driver ehci_ls1x_hc_driver = {
.description = hcd_name,
.product_desc = "LOONGSON1 EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_ls1x_reset,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct resource *res;
int irq;
int ret;
pr_debug("initializing loongson1 ehci USB Controller\n");
if (usb_disabled())
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no IRQ. Check %s setup!\n",
dev_name(&pdev->dev));
return -ENODEV;
}
irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no register addr. Check %s setup!\n",
dev_name(&pdev->dev));
return -ENODEV;
}
hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_dbg(&pdev->dev, "controller already in use\n");
ret = -EBUSY;
goto err_put_hcd;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
ret = -EFAULT;
goto err_release_region;
}
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret)
goto err_iounmap;
return ret;
err_iounmap:
iounmap(hcd->regs);
err_release_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_put_hcd:
usb_put_hcd(hcd);
return ret;
}
static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
return 0;
}
static struct platform_driver ehci_ls1x_driver = {
.probe = ehci_hcd_ls1x_probe,
.remove = ehci_hcd_ls1x_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ls1x-ehci",
.owner = THIS_MODULE,
},
};
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");

Some files were not shown because too many files have changed in this diff Show More