You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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.
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user