Revert "usb: gadget: Backport Android drivers from 2.6.35 for HD2 by tytung."
This reverts commit 70f8304d7ae4683734b435abeacaa069e33863c9.
This commit is contained in:
parent
52203a8404
commit
79b69f0bfb
@ -47,10 +47,6 @@ struct msm_hsusb_platform_data {
|
||||
/* 1 : uart, 0 : usb */
|
||||
void (*usb_uart_switch)(int);
|
||||
void (*config_usb_id_gpios)(bool enable);
|
||||
void (*usb_hub_enable)(bool);
|
||||
void (*serial_debug_gpios)(int);
|
||||
int (*china_ac_detect)(void);
|
||||
void (*disable_usb_charger)(void);
|
||||
/* val, reg pairs terminated by -1 */
|
||||
int *phy_init_seq;
|
||||
|
||||
@ -80,11 +76,8 @@ struct msm_hsusb_platform_data {
|
||||
#endif
|
||||
char *serial_number;
|
||||
int usb_id_pin_gpio;
|
||||
int dock_pin_gpio;
|
||||
int id_pin_irq;
|
||||
bool enable_car_kit_detect;
|
||||
__u8 accessory_detect;
|
||||
bool dock_detect;
|
||||
};
|
||||
|
||||
int usb_get_connect_type(void);
|
||||
|
@ -53,6 +53,59 @@ MODULE_VERSION("1.0");
|
||||
|
||||
static const char longname[] = "Gadget Android";
|
||||
|
||||
enum {
|
||||
USB_FUNCTION_UMS = 0,
|
||||
USB_FUNCTION_ADB = 1,
|
||||
USB_FUNCTION_RNDIS,
|
||||
USB_FUNCTION_DIAG,
|
||||
USB_FUNCTION_SERIAL,
|
||||
USB_FUNCTION_PROJECTOR,
|
||||
USB_FUNCTION_FSYNC,
|
||||
USB_FUNCTION_MTP,
|
||||
USB_FUNCTION_MODEM,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_ANDROID_MTP
|
||||
#define MS_VENDOR_CODE 0x0b
|
||||
#define FEATURE_DESC_SIZE 64
|
||||
#define PID_MTP 0x0c93
|
||||
#define PID_MTP_ADB 0x0ca8
|
||||
struct ms_comp_feature_descriptor {
|
||||
__le32 dwLength;
|
||||
__le16 bcdVersion;
|
||||
__le16 wIndex;
|
||||
__u8 bCount;
|
||||
__u8 resv1[7];
|
||||
/* for MTP */
|
||||
__u8 bFirstInterfaceNumber;
|
||||
__u8 resv2;
|
||||
__u8 compatibleID[8];
|
||||
__u8 subCompatibleID[8];
|
||||
__u8 resv3[6];
|
||||
/* for adb */
|
||||
__u8 bFirstInterfaceNumber2;
|
||||
__u8 resv4;
|
||||
__u8 compatibleID2[8];
|
||||
__u8 subCompatibleID2[8];
|
||||
__u8 resv5[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
static struct ms_comp_feature_descriptor ms_comp_desc = {
|
||||
.dwLength = __constant_cpu_to_le32(FEATURE_DESC_SIZE),
|
||||
.bcdVersion = __constant_cpu_to_le16(0x0100),
|
||||
.wIndex = __constant_cpu_to_le16(0x0004),
|
||||
.bCount = 0x02,
|
||||
/* for MTP */
|
||||
.bFirstInterfaceNumber = 0,
|
||||
.resv2 = 1,
|
||||
.compatibleID = "MTP",
|
||||
/* for adb */
|
||||
.bFirstInterfaceNumber2 = 1,
|
||||
.resv4 = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Default vendor and product IDs, overridden by platform data */
|
||||
#define VENDOR_ID 0x18D1
|
||||
#define PRODUCT_ID 0x0001
|
||||
@ -109,6 +162,17 @@ static struct usb_device_descriptor device_desc = {
|
||||
|
||||
static struct list_head _functions = LIST_HEAD_INIT(_functions);
|
||||
static int _registered_function_count = 0;
|
||||
static int get_product_id(struct android_dev *dev);
|
||||
|
||||
void android_usb_set_connected(int connected)
|
||||
{
|
||||
if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) {
|
||||
if (connected)
|
||||
usb_gadget_connect(_android_dev->cdev->gadget);
|
||||
else
|
||||
usb_gadget_disconnect(_android_dev->cdev->gadget);
|
||||
}
|
||||
}
|
||||
|
||||
static struct android_usb_function *get_function(const char *name)
|
||||
{
|
||||
@ -124,6 +188,7 @@ static void bind_functions(struct android_dev *dev)
|
||||
{
|
||||
struct android_usb_function *f;
|
||||
char **functions = dev->functions;
|
||||
int product_id;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->num_functions; i++) {
|
||||
@ -134,9 +199,14 @@ static void bind_functions(struct android_dev *dev)
|
||||
else
|
||||
printk(KERN_ERR "function %s not found in bind_functions\n", name);
|
||||
}
|
||||
product_id = get_product_id(dev);
|
||||
printk(KERN_INFO "usb: product_id=0x%x\n", product_id);
|
||||
device_desc.idProduct = __constant_cpu_to_le16(product_id);
|
||||
if (dev->cdev)
|
||||
dev->cdev->desc.idProduct = device_desc.idProduct;
|
||||
}
|
||||
|
||||
static int android_bind_config(struct usb_configuration *c)
|
||||
static int __init android_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct android_dev *dev = _android_dev;
|
||||
|
||||
@ -167,7 +237,46 @@ static int android_setup_config(struct usb_configuration *c,
|
||||
{
|
||||
int i;
|
||||
int ret = -EOPNOTSUPP;
|
||||
#ifdef CONFIG_USB_ANDROID_MTP
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct usb_request *req = cdev->req;
|
||||
struct android_dev *dev = _android_dev;
|
||||
int product_id;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
/* vendor request to GET OS feature descriptor */
|
||||
if (((ctrl->bRequestType << 8) | ctrl->bRequest) ==
|
||||
(((USB_DIR_IN | USB_TYPE_VENDOR) << 8) | MS_VENDOR_CODE)) {
|
||||
|
||||
printk(KERN_DEBUG "usb: get OS feature descriptor\n");
|
||||
if (w_index != 0x0004 || w_length > FEATURE_DESC_SIZE)
|
||||
return ret;
|
||||
|
||||
product_id = get_product_id(dev);
|
||||
printk(KERN_INFO "mtp: product_id = 0x%x\n", product_id);
|
||||
if (product_id == PID_MTP) {
|
||||
ms_comp_desc.bCount = 1;
|
||||
ms_comp_desc.dwLength =
|
||||
__constant_cpu_to_le32(40);
|
||||
ret = w_length;
|
||||
} else if (product_id == PID_MTP_ADB) {
|
||||
ms_comp_desc.bCount = 2;
|
||||
ms_comp_desc.dwLength =
|
||||
__constant_cpu_to_le32(64);
|
||||
ret = w_length;
|
||||
}
|
||||
/* respond with data transfer or status phase? */
|
||||
if (ret >= 0) {
|
||||
memcpy(req->buf, (char *)&ms_comp_desc, w_length);
|
||||
req->zero = 0;
|
||||
req->length = ret;
|
||||
ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (ret < 0)
|
||||
ERROR(cdev, "get feature desc err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < android_config_driver.next_interface_id; i++) {
|
||||
if (android_config_driver.interface[i]->setup) {
|
||||
ret = android_config_driver.interface[i]->setup(
|
||||
@ -198,7 +307,7 @@ static int product_matches_functions(struct android_usb_product *p)
|
||||
{
|
||||
struct usb_function *f;
|
||||
list_for_each_entry(f, &android_config_driver.functions, list) {
|
||||
if (product_has_function(p, f) == !!f->disabled)
|
||||
if (product_has_function(p, f) == !!f->hidden)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -220,7 +329,7 @@ static int get_product_id(struct android_dev *dev)
|
||||
return dev->product_id;
|
||||
}
|
||||
|
||||
static int android_bind(struct usb_composite_dev *cdev)
|
||||
static int __init android_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct android_dev *dev = _android_dev;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
@ -249,6 +358,9 @@ static int android_bind(struct usb_composite_dev *cdev)
|
||||
strings_dev[STRING_SERIAL_IDX].id = id;
|
||||
device_desc.iSerialNumber = id;
|
||||
|
||||
if (gadget->ops->wakeup)
|
||||
android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
|
||||
/* register our configuration */
|
||||
ret = usb_add_config(cdev, &android_config_driver);
|
||||
if (ret) {
|
||||
@ -300,9 +412,84 @@ void android_register_function(struct android_usb_function *f)
|
||||
/* bind our functions if they have all registered
|
||||
* and the main driver has bound.
|
||||
*/
|
||||
if (dev && dev->config && _registered_function_count == dev->num_functions)
|
||||
if (dev->config && _registered_function_count == dev->num_functions)
|
||||
bind_functions(dev);
|
||||
}
|
||||
int android_show_function(char *buf)
|
||||
{
|
||||
unsigned length = 0;
|
||||
struct usb_function *f;
|
||||
list_for_each_entry(f, &android_config_driver.functions, list) {
|
||||
length += sprintf(buf + length, "%s:%s\n", f->name,
|
||||
(f->hidden)?"disable":"enable");
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int android_switch_function(unsigned func)
|
||||
{
|
||||
struct usb_function *f;
|
||||
struct android_dev *dev = _android_dev;
|
||||
int product_id;
|
||||
printk(KERN_INFO "%s: %u\n", __func__, func);
|
||||
list_for_each_entry(f, &android_config_driver.functions, list) {
|
||||
if ((func & (1 << USB_FUNCTION_UMS)) &&
|
||||
!strcmp(f->name, "usb_mass_storage"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_ADB)) &&
|
||||
!strcmp(f->name, "adb"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_RNDIS)) &&
|
||||
!strcmp(f->name, "rndis"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_DIAG)) &&
|
||||
!strcmp(f->name, "diag"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_MODEM)) &&
|
||||
!strcmp(f->name, "modem"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_SERIAL)) &&
|
||||
!strcmp(f->name, "serial"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_MTP)) &&
|
||||
!strcmp(f->name, "mtp"))
|
||||
f->hidden = 0;
|
||||
/* also enable adb with MTP function */
|
||||
else if ((func & (1 << USB_FUNCTION_MTP)) &&
|
||||
!strcmp(f->name, "adb"))
|
||||
f->hidden = 0;
|
||||
else if ((func & (1 << USB_FUNCTION_PROJECTOR)) &&
|
||||
!strcmp(f->name, "projector"))
|
||||
f->hidden = 0;
|
||||
else
|
||||
f->hidden = 1;
|
||||
}
|
||||
product_id = get_product_id(dev);
|
||||
device_desc.idProduct = __constant_cpu_to_le16(product_id);
|
||||
if (dev->cdev)
|
||||
dev->cdev->desc.idProduct = device_desc.idProduct;
|
||||
|
||||
/* We need to specify the COMM class in the device descriptor
|
||||
* if we are using RNDIS.
|
||||
*/
|
||||
if (func & (1 << USB_FUNCTION_RNDIS))
|
||||
dev->cdev->desc.bDeviceClass = USB_CLASS_COMM;
|
||||
else
|
||||
dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MSM_72K
|
||||
msm_hsusb_request_reset();
|
||||
#else
|
||||
/* force reenumeration */
|
||||
if (dev->cdev && dev->cdev->gadget &&
|
||||
dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
|
||||
usb_gadget_disconnect(dev->cdev->gadget);
|
||||
msleep(10);
|
||||
usb_gadget_connect(dev->cdev->gadget);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void android_enable_function(struct usb_function *f, int enable)
|
||||
{
|
||||
@ -310,12 +497,12 @@ void android_enable_function(struct usb_function *f, int enable)
|
||||
int disable = !enable;
|
||||
int product_id;
|
||||
|
||||
if (!!f->disabled != disable) {
|
||||
usb_function_set_enabled(f, !disable);
|
||||
if (!!f->hidden != disable) {
|
||||
f->hidden = disable;
|
||||
|
||||
#ifdef CONFIG_USB_ANDROID_RNDIS
|
||||
if (!strcmp(f->name, "rndis")) {
|
||||
struct usb_function *func;
|
||||
struct usb_function *func;
|
||||
|
||||
/* We need to specify the COMM class in the device descriptor
|
||||
* if we are using RNDIS.
|
||||
@ -330,12 +517,12 @@ void android_enable_function(struct usb_function *f, int enable)
|
||||
dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
|
||||
|
||||
/* Windows does not support other interfaces when RNDIS is enabled,
|
||||
* so we disable UMS and MTP when RNDIS is on.
|
||||
* so we disable UMS when RNDIS is on.
|
||||
*/
|
||||
list_for_each_entry(func, &android_config_driver.functions, list) {
|
||||
if (!strcmp(func->name, "usb_mass_storage")
|
||||
|| !strcmp(func->name, "mtp")) {
|
||||
usb_function_set_enabled(func, !enable);
|
||||
if (!strcmp(func->name, "usb_mass_storage")) {
|
||||
func->hidden = enable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -345,10 +532,20 @@ void android_enable_function(struct usb_function *f, int enable)
|
||||
device_desc.idProduct = __constant_cpu_to_le16(product_id);
|
||||
if (dev->cdev)
|
||||
dev->cdev->desc.idProduct = device_desc.idProduct;
|
||||
usb_composite_force_reset(dev->cdev);
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MSM_72K
|
||||
msm_hsusb_request_reset();
|
||||
#else
|
||||
/* force reenumeration */
|
||||
if (dev->cdev && dev->cdev->gadget &&
|
||||
dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
|
||||
usb_gadget_disconnect(dev->cdev->gadget);
|
||||
msleep(10);
|
||||
usb_gadget_connect(dev->cdev->gadget);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void android_set_serialno(char *serialno)
|
||||
{
|
||||
strings_dev[STRING_SERIAL_IDX].s = serialno;
|
||||
@ -360,7 +557,8 @@ int android_get_model_id(void)
|
||||
return dev->product_id;
|
||||
}
|
||||
|
||||
static int android_probe(struct platform_device *pdev)
|
||||
|
||||
static int __init android_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct android_usb_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct android_dev *dev = _android_dev;
|
||||
|
@ -36,7 +36,7 @@
|
||||
*/
|
||||
|
||||
/* big enough to hold our biggest descriptor */
|
||||
#define USB_BUFSIZ 1024
|
||||
#define USB_BUFSIZ 512
|
||||
|
||||
static struct usb_composite_driver *composite;
|
||||
|
||||
@ -75,7 +75,7 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_function *f = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", !f->disabled);
|
||||
return sprintf(buf, "%d\n", !f->hidden);
|
||||
}
|
||||
|
||||
static ssize_t enable_store(
|
||||
@ -90,36 +90,13 @@ static ssize_t enable_store(
|
||||
if (driver->enable_function)
|
||||
driver->enable_function(f, value);
|
||||
else
|
||||
usb_function_set_enabled(f, value);
|
||||
f->hidden = !value;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
|
||||
|
||||
void usb_function_set_enabled(struct usb_function *f, int enabled)
|
||||
{
|
||||
f->disabled = !enabled;
|
||||
kobject_uevent(&f->dev->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
|
||||
|
||||
void usb_composite_force_reset(struct usb_composite_dev *cdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
/* force reenumeration */
|
||||
if (cdev && cdev->gadget && cdev->gadget->speed != USB_SPEED_UNKNOWN) {
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
|
||||
usb_gadget_disconnect(cdev->gadget);
|
||||
msleep(10);
|
||||
usb_gadget_connect(cdev->gadget);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_add_function() - add a function to a configuration
|
||||
@ -135,7 +112,7 @@ void usb_composite_force_reset(struct usb_composite_dev *cdev)
|
||||
* This function returns the value of the function's bind(), which is
|
||||
* zero for success else a negative errno value.
|
||||
*/
|
||||
int usb_add_function(struct usb_configuration *config,
|
||||
int __init usb_add_function(struct usb_configuration *config,
|
||||
struct usb_function *function)
|
||||
{
|
||||
struct usb_composite_dev *cdev = config->cdev;
|
||||
@ -280,7 +257,7 @@ int usb_function_activate(struct usb_function *function)
|
||||
* Returns the interface ID which was allocated; or -ENODEV if no
|
||||
* more interface IDs can be allocated.
|
||||
*/
|
||||
int usb_interface_id(struct usb_configuration *config,
|
||||
int __init usb_interface_id(struct usb_configuration *config,
|
||||
struct usb_function *function)
|
||||
{
|
||||
unsigned id = config->next_interface_id;
|
||||
@ -293,6 +270,34 @@ int usb_interface_id(struct usb_configuration *config,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct usb_function *get_function_by_intf(struct usb_composite_dev *cdev,
|
||||
int intf)
|
||||
{
|
||||
struct usb_configuration *config = cdev->config;
|
||||
enum usb_device_speed speed = cdev->gadget->speed;
|
||||
struct usb_function *f;
|
||||
struct usb_descriptor_header *descriptor;
|
||||
struct usb_interface_descriptor *intf_desc;
|
||||
int i;
|
||||
for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
|
||||
f = config->interface[i];
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (f->hidden)
|
||||
continue;
|
||||
|
||||
if (speed == USB_SPEED_HIGH)
|
||||
descriptor = *(f->hs_descriptors);
|
||||
else
|
||||
descriptor = *(f->descriptors);
|
||||
intf_desc = (struct usb_interface_descriptor *)descriptor;
|
||||
if (intf_desc->bDescriptorType == USB_DT_INTERFACE &&
|
||||
intf_desc->bInterfaceNumber == intf)
|
||||
return f;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int config_buf(struct usb_configuration *config,
|
||||
enum usb_device_speed speed, void *buf, u8 type)
|
||||
{
|
||||
@ -334,7 +339,7 @@ static int config_buf(struct usb_configuration *config,
|
||||
descriptors = f->hs_descriptors;
|
||||
else
|
||||
descriptors = f->descriptors;
|
||||
if (f->disabled || !descriptors || descriptors[0] == NULL)
|
||||
if (f->hidden || !descriptors || descriptors[0] == NULL)
|
||||
continue;
|
||||
status = usb_descriptor_fillbuf(next, len,
|
||||
(const struct usb_descriptor_header **) descriptors);
|
||||
@ -346,11 +351,9 @@ static int config_buf(struct usb_configuration *config,
|
||||
while ((descriptor = *descriptors++) != NULL) {
|
||||
intf = (struct usb_interface_descriptor *)dest;
|
||||
if (intf->bDescriptorType == USB_DT_INTERFACE) {
|
||||
/* don't increment bInterfaceNumber for alternate settings */
|
||||
if (intf->bAlternateSetting == 0)
|
||||
intf->bInterfaceNumber = interfaceCount++;
|
||||
else
|
||||
intf->bInterfaceNumber = interfaceCount - 1;
|
||||
intf->bInterfaceNumber = interfaceCount;
|
||||
intf = (struct usb_interface_descriptor *)descriptor;
|
||||
intf->bInterfaceNumber = interfaceCount++;
|
||||
}
|
||||
dest += intf->bLength;
|
||||
}
|
||||
@ -457,8 +460,6 @@ static void reset_config(struct usb_composite_dev *cdev)
|
||||
list_for_each_entry(f, &cdev->config->functions, list) {
|
||||
if (f->disable)
|
||||
f->disable(f);
|
||||
|
||||
bitmap_zero(f->endpoints, 32);
|
||||
}
|
||||
cdev->config = NULL;
|
||||
}
|
||||
@ -504,36 +505,9 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
/* Initialize all interfaces by setting them to altsetting zero. */
|
||||
for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
|
||||
struct usb_function *f = c->interface[tmp];
|
||||
struct usb_descriptor_header **descriptors;
|
||||
|
||||
if (!f)
|
||||
break;
|
||||
if (f->disabled)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Record which endpoints are used by the function. This is used
|
||||
* to dispatch control requests targeted at that endpoint to the
|
||||
* function's setup callback instead of the current
|
||||
* configuration's setup callback.
|
||||
*/
|
||||
if (gadget->speed == USB_SPEED_HIGH)
|
||||
descriptors = f->hs_descriptors;
|
||||
else
|
||||
descriptors = f->descriptors;
|
||||
|
||||
for (; *descriptors; ++descriptors) {
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
int addr;
|
||||
|
||||
if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
|
||||
continue;
|
||||
|
||||
ep = (struct usb_endpoint_descriptor *)*descriptors;
|
||||
addr = ((ep->bEndpointAddress & 0x80) >> 3)
|
||||
| (ep->bEndpointAddress & 0x0f);
|
||||
set_bit(addr, f->endpoints);
|
||||
}
|
||||
|
||||
result = f->set_alt(f, tmp, 0);
|
||||
if (result < 0) {
|
||||
@ -549,8 +523,6 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
|
||||
done:
|
||||
usb_gadget_vbus_draw(gadget, power);
|
||||
|
||||
schedule_work(&cdev->switch_work);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -568,7 +540,7 @@ done:
|
||||
* assigns global resources including string IDs, and per-configuration
|
||||
* resources such as interface IDs and endpoints.
|
||||
*/
|
||||
int usb_add_config(struct usb_composite_dev *cdev,
|
||||
int __init usb_add_config(struct usb_composite_dev *cdev,
|
||||
struct usb_configuration *config)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
@ -765,7 +737,7 @@ static int get_string(struct usb_composite_dev *cdev,
|
||||
* ensure that for example different functions don't wrongly assign
|
||||
* different meanings to the same identifier.
|
||||
*/
|
||||
int usb_string_id(struct usb_composite_dev *cdev)
|
||||
int __init usb_string_id(struct usb_composite_dev *cdev)
|
||||
{
|
||||
if (cdev->next_string_id < 254) {
|
||||
/* string id 0 is reserved */
|
||||
@ -784,7 +756,6 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
"setup complete --> %d, %d/%d\n",
|
||||
req->status, req->actual, req->length);
|
||||
}
|
||||
|
||||
/*
|
||||
* The setup() callback implements all the ep0 functionality that's
|
||||
* not handled lower down, in hardware or the hardware driver(like
|
||||
@ -803,15 +774,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
struct usb_function *f = NULL;
|
||||
u8 endp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (!cdev->connected) {
|
||||
cdev->connected = 1;
|
||||
schedule_work(&cdev->switch_work);
|
||||
}
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
|
||||
/* partial re-init of the response message; the function or the
|
||||
* gadget might need to intercept e.g. a control-OUT completion
|
||||
@ -855,21 +817,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
case USB_DT_STRING:
|
||||
value = get_string(cdev, req->buf,
|
||||
w_index, w_value & 0xff);
|
||||
|
||||
/* Allow functions to handle USB_DT_STRING.
|
||||
* This is required for MTP.
|
||||
*/
|
||||
if (value < 0) {
|
||||
struct usb_configuration *cfg;
|
||||
list_for_each_entry(cfg, &cdev->configs, list) {
|
||||
if (cfg && cfg->setup) {
|
||||
value = cfg->setup(cfg, ctrl);
|
||||
if (value >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value >= 0)
|
||||
value = min(w_length, (u16) value);
|
||||
break;
|
||||
@ -910,7 +857,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
goto unknown;
|
||||
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
|
||||
break;
|
||||
f = cdev->config->interface[intf];
|
||||
f = get_function_by_intf(cdev, intf);
|
||||
if (!f)
|
||||
break;
|
||||
if (w_value && !f->set_alt)
|
||||
@ -922,7 +869,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
goto unknown;
|
||||
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
|
||||
break;
|
||||
f = cdev->config->interface[intf];
|
||||
f = get_function_by_intf(cdev, intf);
|
||||
if (!f)
|
||||
break;
|
||||
/* lots of interfaces only need altsetting zero... */
|
||||
@ -939,36 +886,26 @@ unknown:
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
|
||||
/* functions always handle their interfaces and endpoints...
|
||||
* punt other recipients (other, WUSB, ...) to the current
|
||||
/* functions always handle their interfaces ... punt other
|
||||
* recipients (endpoint, other, WUSB, ...) to the current
|
||||
* configuration code.
|
||||
*
|
||||
* REVISIT it could make sense to let the composite device
|
||||
* take such requests too, if that's ever needed: to work
|
||||
* in config 0, etc.
|
||||
*/
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_INTERFACE:
|
||||
if ((ctrl->bRequestType & USB_RECIP_MASK)
|
||||
== USB_RECIP_INTERFACE) {
|
||||
if (cdev->config == NULL)
|
||||
return value;
|
||||
|
||||
f = cdev->config->interface[intf];
|
||||
break;
|
||||
|
||||
case USB_RECIP_ENDPOINT:
|
||||
endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
|
||||
list_for_each_entry(f, &cdev->config->functions, list) {
|
||||
if (test_bit(endp, f->endpoints))
|
||||
break;
|
||||
}
|
||||
if (&f->list == &cdev->config->functions)
|
||||
f = get_function_by_intf(cdev, intf);
|
||||
if (f && f->setup)
|
||||
value = f->setup(f, ctrl);
|
||||
else
|
||||
f = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f && f->setup)
|
||||
value = f->setup(f, ctrl);
|
||||
else {
|
||||
if (value < 0 && !f) {
|
||||
struct usb_configuration *c;
|
||||
|
||||
c = cdev->config;
|
||||
@ -1026,27 +963,13 @@ static void composite_disconnect(struct usb_gadget *gadget)
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (cdev->config)
|
||||
reset_config(cdev);
|
||||
|
||||
cdev->connected = 0;
|
||||
schedule_work(&cdev->switch_work);
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static ssize_t composite_show_suspended(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
|
||||
return sprintf(buf, "%d\n", cdev->suspended);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
|
||||
|
||||
static void composite_unbind(struct usb_gadget *gadget)
|
||||
static void /* __init_or_exit */
|
||||
composite_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
|
||||
@ -1089,16 +1012,13 @@ static void composite_unbind(struct usb_gadget *gadget)
|
||||
kfree(cdev->req->buf);
|
||||
usb_ep_free_request(gadget->ep0, cdev->req);
|
||||
}
|
||||
|
||||
switch_dev_unregister(&cdev->sw_connected);
|
||||
switch_dev_unregister(&cdev->sw_config);
|
||||
kfree(cdev);
|
||||
set_gadget_data(gadget, NULL);
|
||||
device_remove_file(&gadget->dev, &dev_attr_suspended);
|
||||
composite = NULL;
|
||||
}
|
||||
|
||||
static void string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
|
||||
static void __init
|
||||
string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
|
||||
{
|
||||
struct usb_string *str = tab->strings;
|
||||
|
||||
@ -1110,7 +1030,8 @@ static void string_override_one(struct usb_gadget_strings *tab, u8 id, const cha
|
||||
}
|
||||
}
|
||||
|
||||
static void string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
|
||||
static void __init
|
||||
string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
|
||||
{
|
||||
while (*tab) {
|
||||
string_override_one(*tab, id, s);
|
||||
@ -1118,30 +1039,7 @@ static void string_override(struct usb_gadget_strings **tab, u8 id, const char *
|
||||
}
|
||||
}
|
||||
|
||||
static void composite_switch_work(struct work_struct *data)
|
||||
{
|
||||
struct usb_composite_dev *cdev =
|
||||
container_of(data, struct usb_composite_dev, switch_work);
|
||||
struct usb_configuration *config = cdev->config;
|
||||
int connected;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (cdev->connected != cdev->sw_connected.state) {
|
||||
connected = cdev->connected;
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
switch_set_state(&cdev->sw_connected, connected);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
}
|
||||
|
||||
if (config)
|
||||
switch_set_state(&cdev->sw_config, config->bConfigurationValue);
|
||||
else
|
||||
switch_set_state(&cdev->sw_config, 0);
|
||||
}
|
||||
|
||||
static int composite_bind(struct usb_gadget *gadget)
|
||||
static int __init composite_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
int status = -ENOMEM;
|
||||
@ -1176,14 +1074,6 @@ static int composite_bind(struct usb_gadget *gadget)
|
||||
*/
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
|
||||
/* standardized runtime overrides for device ID data */
|
||||
if (idVendor)
|
||||
cdev->desc.idVendor = cpu_to_le16(idVendor);
|
||||
if (idProduct)
|
||||
cdev->desc.idProduct = cpu_to_le16(idProduct);
|
||||
if (bcdDevice)
|
||||
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
|
||||
|
||||
/* composite gadget needs to assign strings for whole device (like
|
||||
* serial number), register function drivers, potentially update
|
||||
* power state and consumption, etc
|
||||
@ -1192,19 +1082,17 @@ static int composite_bind(struct usb_gadget *gadget)
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
cdev->sw_connected.name = "usb_connected";
|
||||
status = switch_dev_register(&cdev->sw_connected);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
cdev->sw_config.name = "usb_configuration";
|
||||
status = switch_dev_register(&cdev->sw_config);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
INIT_WORK(&cdev->switch_work, composite_switch_work);
|
||||
|
||||
cdev->desc = *composite->dev;
|
||||
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
/* standardized runtime overrides for device ID data */
|
||||
if (idVendor)
|
||||
cdev->desc.idVendor = cpu_to_le16(idVendor);
|
||||
if (idProduct)
|
||||
cdev->desc.idProduct = cpu_to_le16(idProduct);
|
||||
if (bcdDevice)
|
||||
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
|
||||
|
||||
/* strings can't be assigned before bind() allocates the
|
||||
* releavnt identifiers
|
||||
*/
|
||||
@ -1218,10 +1106,6 @@ static int composite_bind(struct usb_gadget *gadget)
|
||||
string_override(composite->strings,
|
||||
cdev->desc.iSerialNumber, iSerialNumber);
|
||||
|
||||
status = device_create_file(&gadget->dev, &dev_attr_suspended);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
INFO(cdev, "%s ready\n", composite->name);
|
||||
return 0;
|
||||
|
||||
@ -1232,7 +1116,8 @@ fail:
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void composite_suspend(struct usb_gadget *gadget)
|
||||
static void
|
||||
composite_suspend(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct usb_function *f;
|
||||
@ -1249,11 +1134,10 @@ static void composite_suspend(struct usb_gadget *gadget)
|
||||
}
|
||||
if (composite->suspend)
|
||||
composite->suspend(cdev);
|
||||
|
||||
cdev->suspended = 1;
|
||||
}
|
||||
|
||||
static void composite_resume(struct usb_gadget *gadget)
|
||||
static void
|
||||
composite_resume(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct usb_function *f;
|
||||
@ -1270,24 +1154,6 @@ static void composite_resume(struct usb_gadget *gadget)
|
||||
f->resume(f);
|
||||
}
|
||||
}
|
||||
|
||||
cdev->suspended = 0;
|
||||
}
|
||||
|
||||
static int composite_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct usb_function *f = dev_get_drvdata(dev);
|
||||
|
||||
if (!f) {
|
||||
/* this happens when the device is first created */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (add_uevent_var(env, "FUNCTION=%s", f->name))
|
||||
return -ENOMEM;
|
||||
if (add_uevent_var(env, "ENABLED=%d", !f->disabled))
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1296,7 +1162,7 @@ static struct usb_gadget_driver composite_driver = {
|
||||
.speed = USB_SPEED_HIGH,
|
||||
|
||||
.bind = composite_bind,
|
||||
.unbind = composite_unbind,
|
||||
.unbind = __exit_p(composite_unbind),
|
||||
|
||||
.setup = composite_setup,
|
||||
.disconnect = composite_disconnect,
|
||||
@ -1324,7 +1190,7 @@ static struct usb_gadget_driver composite_driver = {
|
||||
* while it was binding. That would usually be done in order to wait for
|
||||
* some userspace participation.
|
||||
*/
|
||||
int usb_composite_register(struct usb_composite_driver *driver)
|
||||
int __init usb_composite_register(struct usb_composite_driver *driver)
|
||||
{
|
||||
if (!driver || !driver->dev || !driver->bind || composite)
|
||||
return -EINVAL;
|
||||
@ -1338,7 +1204,6 @@ int usb_composite_register(struct usb_composite_driver *driver)
|
||||
driver->class = class_create(THIS_MODULE, "usb_composite");
|
||||
if (IS_ERR(driver->class))
|
||||
return PTR_ERR(driver->class);
|
||||
driver->class->dev_uevent = composite_uevent;
|
||||
|
||||
return usb_gadget_register_driver(&composite_driver);
|
||||
}
|
||||
@ -1350,7 +1215,7 @@ int usb_composite_register(struct usb_composite_driver *driver)
|
||||
* This function is used to unregister drivers using the composite
|
||||
* driver framework.
|
||||
*/
|
||||
void usb_composite_unregister(struct usb_composite_driver *driver)
|
||||
void __exit usb_composite_unregister(struct usb_composite_driver *driver)
|
||||
{
|
||||
if (composite != driver)
|
||||
return;
|
||||
|
@ -71,6 +71,7 @@ static void TRACE(const char *tag, const void *_data, int len, int decode)
|
||||
#endif
|
||||
|
||||
#define HDLC_MAX 4096
|
||||
#define SMD_MAX 8192
|
||||
|
||||
#define TX_REQ_BUF_SZ 8192
|
||||
#define RX_REQ_BUF_SZ 8192
|
||||
@ -87,6 +88,8 @@ struct diag_context
|
||||
struct usb_ep *in;
|
||||
struct list_head tx_req_idle;
|
||||
struct list_head rx_req_idle;
|
||||
struct list_head rx_arm9_idle;
|
||||
struct list_head rx_arm9_done;
|
||||
spinlock_t req_lock;
|
||||
#if ROUTE_TO_USERSPACE
|
||||
struct mutex user_lock;
|
||||
@ -103,12 +106,11 @@ struct diag_context
|
||||
unsigned char id_table[ID_TABLE_SZ];
|
||||
#endif
|
||||
smd_channel_t *ch;
|
||||
struct mutex smd_lock;
|
||||
int in_busy;
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
smd_channel_t *ch_dsp;
|
||||
int in_busy_dsp;
|
||||
#endif
|
||||
int online;
|
||||
int error;
|
||||
int init_done;
|
||||
|
||||
/* assembly buffer for USB->A9 HDLC frames */
|
||||
unsigned char hdlc_buf[HDLC_MAX];
|
||||
@ -119,6 +121,22 @@ struct diag_context
|
||||
u64 rx_count; /* from smd */
|
||||
|
||||
int function_enable;
|
||||
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
smd_channel_t *chqdsp;
|
||||
struct list_head tx_qdsp_idle;
|
||||
#endif
|
||||
/* for slate test */
|
||||
int is2ARM11;
|
||||
struct mutex diag2arm9_lock;
|
||||
struct mutex diag2arm9_read_lock;
|
||||
struct mutex diag2arm9_write_lock;
|
||||
bool diag2arm9_opened;
|
||||
unsigned char toARM9_buf[SMD_MAX];
|
||||
unsigned read_arm9_count;
|
||||
unsigned char *read_arm9_buf;
|
||||
wait_queue_head_t read_arm9_wq;
|
||||
struct usb_request *read_arm9_req;
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor diag_interface_desc = {
|
||||
@ -175,6 +193,23 @@ static struct usb_descriptor_header *hs_diag_descs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* string descriptors: */
|
||||
|
||||
static struct usb_string diag_string_defs[] = {
|
||||
[0].s = "HTC DIAG",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings diag_string_table = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = diag_string_defs,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *diag_strings[] = {
|
||||
&diag_string_table,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct diag_context _context;
|
||||
|
||||
static inline struct diag_context *func_to_dev(struct usb_function *f)
|
||||
@ -183,11 +218,42 @@ static inline struct diag_context *func_to_dev(struct usb_function *f)
|
||||
}
|
||||
|
||||
static void smd_try_to_send(struct diag_context *ctxt);
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
static void dsp_try_to_send(struct diag_context *ctxt);
|
||||
#endif
|
||||
static void smd_diag_notify(void *priv, unsigned event);
|
||||
|
||||
static void diag_queue_out(struct diag_context *ctxt);
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
static void diag_qdsp_complete_in(struct usb_ep *ept,
|
||||
struct usb_request *req);
|
||||
#endif
|
||||
|
||||
static struct usb_request *diag_req_new(unsigned len)
|
||||
{
|
||||
struct usb_request *req;
|
||||
if (len > SMD_MAX)
|
||||
return NULL;
|
||||
req = kmalloc(sizeof(struct usb_request), GFP_KERNEL);
|
||||
if (!req)
|
||||
return NULL;
|
||||
req->buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!req->buf) {
|
||||
kfree(req);
|
||||
return NULL;
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static void diag_req_free(struct usb_request *req)
|
||||
{
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
if (req->buf) {
|
||||
kfree(req->buf);
|
||||
req->buf = 0;
|
||||
}
|
||||
kfree(req);
|
||||
req = 0;
|
||||
}
|
||||
|
||||
/* add a request to the tail of a list */
|
||||
static void req_put(struct diag_context *ctxt, struct list_head *head,
|
||||
@ -227,29 +293,82 @@ static void reqs_free(struct diag_context *ctxt, struct usb_ep *ep,
|
||||
}
|
||||
}
|
||||
|
||||
static void smd_diag_enable(char *src, int enable)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
|
||||
printk(KERN_INFO "smd_try_open(%s): %d\n", src, enable);
|
||||
if (!ctxt->init_done)
|
||||
return;
|
||||
|
||||
mutex_lock(&ctxt->smd_lock);
|
||||
if (enable) {
|
||||
if (!ctxt->ch)
|
||||
smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify);
|
||||
} else {
|
||||
if (ctxt->ch) {
|
||||
smd_close(ctxt->ch);
|
||||
ctxt->ch = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ctxt->smd_lock);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if ROUTE_TO_USERSPACE
|
||||
#define USB_DIAG_IOC_MAGIC 0xFF
|
||||
#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *)
|
||||
#define USB_DIAG_FUNC_IOC_ENABLE_SET _IOW(USB_DIAG_IOC_MAGIC, 1, int)
|
||||
#define USB_DIAG_FUNC_IOC_ENABLE_GET _IOR(USB_DIAG_IOC_MAGIC, 2, int)
|
||||
#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *)
|
||||
#define USB_DIAG_FUNC_IOC_AMR_SET _IOW(USB_DIAG_IOC_MAGIC, 4, int)
|
||||
|
||||
static long diag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
void __user *argp = (void __user *)arg;
|
||||
int tmp_value;
|
||||
unsigned long flags;
|
||||
unsigned char temp_id_table[ID_TABLE_SZ];
|
||||
|
||||
if (cmd != USB_DIAG_FUNC_IOC_REGISTER_SET) {
|
||||
pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
|
||||
return -EINVAL;
|
||||
printk(KERN_INFO "diag:diag_ioctl() cmd=%d\n", cmd);
|
||||
|
||||
if (_IOC_TYPE(cmd) != USB_DIAG_IOC_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case USB_DIAG_FUNC_IOC_ENABLE_SET:
|
||||
if (copy_from_user(&tmp_value, argp, sizeof(int)))
|
||||
return -EFAULT;
|
||||
printk(KERN_INFO "diag: enable %d\n", tmp_value);
|
||||
android_enable_function(&_context.function, tmp_value);
|
||||
smd_diag_enable("diag_ioctl", tmp_value);
|
||||
/* force diag_read to return error when disable diag */
|
||||
if (tmp_value == 0)
|
||||
ctxt->error = 1;
|
||||
wake_up(&ctxt->read_wq);
|
||||
break;
|
||||
case USB_DIAG_FUNC_IOC_ENABLE_GET:
|
||||
tmp_value = !_context.function.hidden;
|
||||
if (copy_to_user(argp, &tmp_value, sizeof(tmp_value)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
case USB_DIAG_FUNC_IOC_REGISTER_SET:
|
||||
if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ))
|
||||
return -EFAULT;
|
||||
spin_lock_irqsave(&ctxt->req_lock, flags);
|
||||
memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ);
|
||||
spin_unlock_irqrestore(&ctxt->req_lock, flags);
|
||||
break;
|
||||
case USB_DIAG_FUNC_IOC_AMR_SET:
|
||||
if (copy_from_user(&ctxt->is2ARM11, argp, sizeof(int)))
|
||||
return -EFAULT;
|
||||
printk(KERN_INFO "diag: is2ARM11 %d\n", ctxt->is2ARM11);
|
||||
break;
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&ctxt->req_lock, flags);
|
||||
memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ);
|
||||
spin_unlock_irqrestore(&ctxt->req_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -260,6 +379,13 @@ static ssize_t diag_read(struct file *fp, char __user *buf,
|
||||
struct usb_request *req = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* we will block until we're online */
|
||||
if (!ctxt->online) {
|
||||
ret = wait_event_interruptible(ctxt->read_wq, (ctxt->online || ctxt->error));
|
||||
if (ret < 0 || ctxt->error)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mutex_lock(&ctxt->user_lock);
|
||||
|
||||
if (ctxt->user_read_len && ctxt->user_readp) {
|
||||
@ -285,7 +411,7 @@ static ssize_t diag_read(struct file *fp, char __user *buf,
|
||||
goto end;
|
||||
}
|
||||
if (!ctxt->online) {
|
||||
pr_err("%s: offline\n", __func__);
|
||||
/* pr_err("%s: offline\n", __func__); */
|
||||
ret = -EIO;
|
||||
goto end;
|
||||
}
|
||||
@ -357,6 +483,8 @@ static ssize_t diag_write(struct file *fp, const char __user *buf,
|
||||
}
|
||||
|
||||
ret = req->length;
|
||||
/* zero this so we don't put it back to idle queue */
|
||||
req = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
@ -388,6 +516,8 @@ static int diag_open(struct inode *ip, struct file *fp)
|
||||
}
|
||||
}
|
||||
ctxt->opened = true;
|
||||
/* clear the error latch */
|
||||
ctxt->error = 0;
|
||||
|
||||
done:
|
||||
mutex_unlock(&ctxt->user_lock);
|
||||
@ -427,6 +557,174 @@ static struct miscdevice diag_device_fops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static int diag2arm9_open(struct inode *ip, struct file *fp)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
struct usb_request *req;
|
||||
int rc = 0;
|
||||
int n;
|
||||
printk(KERN_INFO "%s\n", __func__);
|
||||
mutex_lock(&ctxt->diag2arm9_lock);
|
||||
if (ctxt->diag2arm9_opened) {
|
||||
pr_err("%s: already opened\n", __func__);
|
||||
rc = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
/* clear pending data if any */
|
||||
while ((req = req_get(ctxt, &ctxt->rx_arm9_done)))
|
||||
diag_req_free(req);
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
req = diag_req_new(SMD_MAX);
|
||||
if (!req) {
|
||||
while ((req = req_get(ctxt, &ctxt->rx_arm9_idle)))
|
||||
diag_req_free(req);
|
||||
rc = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
req_put(ctxt, &ctxt->rx_arm9_idle, req);
|
||||
}
|
||||
ctxt->read_arm9_count = 0;
|
||||
ctxt->read_arm9_buf = 0;
|
||||
ctxt->read_arm9_req = 0;
|
||||
ctxt->diag2arm9_opened = true;
|
||||
|
||||
smd_diag_enable("diag2arm9_open", 1);
|
||||
done:
|
||||
mutex_unlock(&ctxt->diag2arm9_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int diag2arm9_release(struct inode *ip, struct file *fp)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
struct usb_request *req;
|
||||
|
||||
printk(KERN_INFO "%s\n", __func__);
|
||||
mutex_lock(&ctxt->diag2arm9_lock);
|
||||
ctxt->diag2arm9_opened = false;
|
||||
wake_up(&ctxt->read_arm9_wq);
|
||||
mutex_lock(&ctxt->diag2arm9_read_lock);
|
||||
while ((req = req_get(ctxt, &ctxt->rx_arm9_idle)))
|
||||
diag_req_free(req);
|
||||
while ((req = req_get(ctxt, &ctxt->rx_arm9_done)))
|
||||
diag_req_free(req);
|
||||
if (ctxt->read_arm9_req)
|
||||
diag_req_free(ctxt->read_arm9_req);
|
||||
mutex_unlock(&ctxt->diag2arm9_read_lock);
|
||||
|
||||
/*************************************
|
||||
* If smd is closed, it will lead to slate can't be tested.
|
||||
* slate will open it for one time
|
||||
* but close it for several times and never open
|
||||
*************************************/
|
||||
/*smd_diag_enable("diag2arm9_release", 0);*/
|
||||
mutex_unlock(&ctxt->diag2arm9_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t diag2arm9_write(struct file *fp, const char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
int r = count;
|
||||
int writed = 0;
|
||||
|
||||
mutex_lock(&ctxt->diag2arm9_write_lock);
|
||||
|
||||
while (count > 0) {
|
||||
writed = count > SMD_MAX ? SMD_MAX : count;
|
||||
if (copy_from_user(ctxt->toARM9_buf, buf, writed)) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (ctxt->ch == NULL) {
|
||||
printk(KERN_ERR "%s: ctxt->ch == NULL", __func__);
|
||||
r = -EFAULT;
|
||||
break;
|
||||
} else if (ctxt->toARM9_buf == NULL) {
|
||||
printk(KERN_ERR "%s: ctxt->toARM9_buf == NULL", __func__);
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
smd_write(ctxt->ch, ctxt->toARM9_buf, writed);
|
||||
buf += writed;
|
||||
count -= writed;
|
||||
}
|
||||
|
||||
mutex_unlock(&ctxt->diag2arm9_write_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t diag2arm9_read(struct file *fp, char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
struct usb_request *req;
|
||||
int r = 0, xfer;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ctxt->diag2arm9_read_lock);
|
||||
|
||||
/* if we have data pending, give it to userspace */
|
||||
if (ctxt->read_arm9_count > 0)
|
||||
req = ctxt->read_arm9_req;
|
||||
else {
|
||||
retry:
|
||||
/* get data from done queue */
|
||||
req = 0;
|
||||
ret = wait_event_interruptible(ctxt->read_arm9_wq,
|
||||
((req = req_get(ctxt, &ctxt->rx_arm9_done)) ||
|
||||
!ctxt->diag2arm9_opened));
|
||||
if (!ctxt->diag2arm9_opened) {
|
||||
if (req)
|
||||
req_put(ctxt, &ctxt->rx_arm9_idle, req);
|
||||
goto done;
|
||||
}
|
||||
if (ret < 0 || req == 0)
|
||||
goto done;
|
||||
|
||||
if (req->actual == 0) {
|
||||
req_put(ctxt, &ctxt->rx_arm9_idle, req);
|
||||
goto retry;
|
||||
}
|
||||
ctxt->read_arm9_req = req;
|
||||
ctxt->read_arm9_count = req->actual;
|
||||
ctxt->read_arm9_buf = req->buf;
|
||||
}
|
||||
xfer = (ctxt->read_arm9_count < count) ? ctxt->read_arm9_count : count;
|
||||
if (copy_to_user(buf, ctxt->read_arm9_buf, xfer)) {
|
||||
printk(KERN_INFO "diag: copy_to_user fail\n");
|
||||
r = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
ctxt->read_arm9_buf += xfer;
|
||||
ctxt->read_arm9_count -= xfer;
|
||||
r += xfer;
|
||||
/* if we've emptied the buffer, release the request */
|
||||
if (ctxt->read_arm9_count == 0) {
|
||||
req_put(ctxt, &ctxt->rx_arm9_idle, ctxt->read_arm9_req);
|
||||
ctxt->read_arm9_req = 0;
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&ctxt->diag2arm9_read_lock);
|
||||
return r;
|
||||
}
|
||||
static struct file_operations diag2arm9_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = diag2arm9_open,
|
||||
.release = diag2arm9_release,
|
||||
.write = diag2arm9_write,
|
||||
.read = diag2arm9_read,
|
||||
};
|
||||
|
||||
static struct miscdevice diag2arm9_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "diag_arm9",
|
||||
.fops = &diag2arm9_fops,
|
||||
};
|
||||
|
||||
static void diag_in_complete(struct usb_ep *ept, struct usb_request *req)
|
||||
{
|
||||
struct diag_context *ctxt = req->context;
|
||||
@ -446,19 +744,7 @@ static void diag_in_complete(struct usb_ep *ept, struct usb_request *req)
|
||||
smd_try_to_send(ctxt);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
static void diag_dsp_in_complete(struct usb_ep *ept, struct usb_request *req)
|
||||
{
|
||||
struct diag_context *ctxt = req->context;
|
||||
|
||||
ctxt->in_busy_dsp = 0;
|
||||
req_put(ctxt, &ctxt->tx_req_idle, req);
|
||||
dsp_try_to_send(ctxt);
|
||||
wake_up(&ctxt->write_wq);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if !NO_HDLC
|
||||
static void diag_process_hdlc(struct diag_context *ctxt, void *_data, unsigned len)
|
||||
{
|
||||
unsigned char *data = _data;
|
||||
@ -585,8 +871,27 @@ again:
|
||||
int r = smd_read_avail(ctxt->ch);
|
||||
|
||||
if (r > TX_REQ_BUF_SZ) {
|
||||
printk(KERN_ERR "The SMD data is too large to send!!\n");
|
||||
return;
|
||||
}
|
||||
if (r > 0 && ctxt->is2ARM11) {
|
||||
/* to arm11 user space */
|
||||
struct usb_request *req;
|
||||
if (!ctxt->diag2arm9_opened)
|
||||
return;
|
||||
req = req_get(ctxt, &ctxt->rx_arm9_idle);
|
||||
if (!req) {
|
||||
printk(KERN_ERR "There is no enough request to ARM11!!\n");
|
||||
return;
|
||||
}
|
||||
smd_read(ctxt->ch, req->buf, r);
|
||||
req->actual = r;
|
||||
req_put(ctxt, &ctxt->rx_arm9_done, req);
|
||||
wake_up(&ctxt->read_arm9_wq);
|
||||
return;
|
||||
}
|
||||
if (!ctxt->online)
|
||||
return;
|
||||
if (r > 0) {
|
||||
struct usb_request *req;
|
||||
req = req_get(ctxt, &ctxt->tx_req_idle);
|
||||
@ -626,55 +931,6 @@ static void smd_diag_notify(void *priv, unsigned event)
|
||||
smd_try_to_send(ctxt);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
static void dsp_try_to_send(struct diag_context *ctxt)
|
||||
{
|
||||
again:
|
||||
if (ctxt->ch_dsp && (!ctxt->in_busy_dsp)) {
|
||||
int r = smd_read_avail(ctxt->ch_dsp);
|
||||
|
||||
if (r > TX_REQ_BUF_SZ) {
|
||||
return;
|
||||
}
|
||||
if (r > 0) {
|
||||
struct usb_request *req;
|
||||
req = req_get(ctxt, &ctxt->tx_req_idle);
|
||||
if (!req) {
|
||||
pr_err("%s: tx req queue is out of buffers\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
smd_read(ctxt->ch_dsp, req->buf, r);
|
||||
|
||||
if (!ctxt->online) {
|
||||
// printk("$$$ discard %d\n", r);
|
||||
req_put(ctxt, &ctxt->tx_req_idle, req);
|
||||
goto again;
|
||||
}
|
||||
req->complete = diag_dsp_in_complete;
|
||||
req->context = ctxt;
|
||||
req->length = r;
|
||||
|
||||
TRACE("Q6>", req->buf, r, 1);
|
||||
ctxt->in_busy_dsp = 1;
|
||||
r = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
|
||||
if (r < 0) {
|
||||
pr_err("%s: usb_ep_queue failed: %d\n",
|
||||
__func__, r);
|
||||
req_put(ctxt, &ctxt->tx_req_idle, req);
|
||||
ctxt->in_busy_dsp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsp_diag_notify(void *priv, unsigned event)
|
||||
{
|
||||
struct diag_context *ctxt = priv;
|
||||
dsp_try_to_send(ctxt);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init create_bulk_endpoints(struct diag_context *ctxt,
|
||||
struct usb_endpoint_descriptor *in_desc,
|
||||
struct usb_endpoint_descriptor *out_desc)
|
||||
@ -689,12 +945,14 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt,
|
||||
DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ep->driver_data = ctxt; /* claim the endpoint */
|
||||
ctxt->in = ep;
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, out_desc);
|
||||
if (!ep) {
|
||||
return -ENODEV;
|
||||
}
|
||||
ep->driver_data = ctxt; /* claim the endpoint */
|
||||
ctxt->out = ep;
|
||||
|
||||
ctxt->tx_count = ctxt->rx_count = 0;
|
||||
@ -733,8 +991,30 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt,
|
||||
req_put(ctxt, &ctxt->tx_req_idle, req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
for (n = 0; n < TX_REQ_NUM; n++) {
|
||||
req = usb_ep_alloc_request(ctxt->in, GFP_KERNEL);
|
||||
if (!req) {
|
||||
DBG(cdev, "%s: usb_ep_alloc_request out of memory\n",
|
||||
__func__);
|
||||
goto qdsp_tx_fail;
|
||||
}
|
||||
req->buf = kmalloc(TX_REQ_BUF_SZ, GFP_KERNEL);
|
||||
if (!req->buf) {
|
||||
DBG(cdev, "%s: kmalloc out of memory\n", __func__);
|
||||
goto qdsp_tx_fail;
|
||||
}
|
||||
req->context = ctxt;
|
||||
req->complete = diag_qdsp_complete_in;
|
||||
req_put(ctxt, &ctxt->tx_qdsp_idle, req);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
qdsp_tx_fail:
|
||||
reqs_free(ctxt, ctxt->in, &ctxt->tx_qdsp_idle);
|
||||
#endif
|
||||
tx_fail:
|
||||
reqs_free(ctxt, ctxt->in, &ctxt->tx_req_idle);
|
||||
rx_fail:
|
||||
@ -775,6 +1055,7 @@ diag_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
#if ROUTE_TO_USERSPACE
|
||||
misc_register(&diag_device_fops);
|
||||
#endif
|
||||
misc_register(&diag2arm9_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -789,6 +1070,7 @@ diag_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
#if ROUTE_TO_USERSPACE
|
||||
misc_deregister(&diag_device_fops);
|
||||
#endif
|
||||
misc_deregister(&diag2arm9_device);
|
||||
|
||||
ctxt->tx_count = ctxt->rx_count = 0;
|
||||
}
|
||||
@ -817,7 +1099,7 @@ static int diag_function_set_alt(struct usb_function *f,
|
||||
usb_ep_disable(ctxt->in);
|
||||
return ret;
|
||||
}
|
||||
ctxt->online = 1;
|
||||
ctxt->online = !ctxt->function.hidden;
|
||||
|
||||
#if ROUTE_TO_USERSPACE
|
||||
/* recycle unhandled rx reqs to user if any */
|
||||
@ -825,12 +1107,10 @@ static int diag_function_set_alt(struct usb_function *f,
|
||||
req_put(ctxt, &ctxt->rx_req_idle, req);
|
||||
#endif
|
||||
|
||||
diag_queue_out(ctxt);
|
||||
smd_try_to_send(ctxt);
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
dsp_try_to_send(ctxt);
|
||||
#endif
|
||||
|
||||
if (ctxt->online) {
|
||||
diag_queue_out(ctxt);
|
||||
smd_try_to_send(ctxt);
|
||||
}
|
||||
#if ROUTE_TO_USERSPACE
|
||||
wake_up(&ctxt->read_wq);
|
||||
wake_up(&ctxt->write_wq);
|
||||
@ -852,12 +1132,78 @@ static void diag_function_disable(struct usb_function *f)
|
||||
usb_ep_disable(ctxt->out);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
static void diag_qdsp_send(struct diag_context *ctxt)
|
||||
{
|
||||
int ret, r;
|
||||
struct usb_request *req;
|
||||
if (ctxt->chqdsp && ctxt->online) {
|
||||
r = smd_read_avail(ctxt->chqdsp);
|
||||
if (r > SMD_MAX || r <= 0)
|
||||
return;
|
||||
|
||||
req = req_get(ctxt, &ctxt->tx_qdsp_idle);
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
smd_read(ctxt->chqdsp, req->buf, r);
|
||||
req->length = r;
|
||||
|
||||
ret = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "diag: failed to queue qdsp req %d\n",
|
||||
ret);
|
||||
req_put(ctxt, &ctxt->tx_qdsp_idle, req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void diag_qdsp_complete_in(struct usb_ep *ept,
|
||||
struct usb_request *req)
|
||||
{
|
||||
struct diag_context *ctxt = req->context;
|
||||
|
||||
req_put(ctxt, &ctxt->tx_qdsp_idle, req);
|
||||
diag_qdsp_send(ctxt);
|
||||
|
||||
#if ROUTE_TO_USERSPACE
|
||||
wake_up(&ctxt->write_wq);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void diag_qdsp_notify(void *priv, unsigned event)
|
||||
{
|
||||
struct diag_context *ctxt = priv;
|
||||
diag_qdsp_send(ctxt);
|
||||
}
|
||||
|
||||
static int msm_diag_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct diag_context *ctxt = &_context;
|
||||
printk(KERN_INFO "diag:msm_diag_probe(), pdev->id=0x%x\n", pdev->id);
|
||||
|
||||
if (pdev->id == 1)
|
||||
smd_open("DSP_DIAG", &ctxt->chqdsp, ctxt, diag_qdsp_notify);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver msm_smd_qdsp_ch1_driver = {
|
||||
.probe = msm_diag_probe,
|
||||
.driver = {
|
||||
.name = "DSP_DIAG",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static int diag_set_enabled(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int enabled = simple_strtol(val, NULL, 0);
|
||||
if (_context.cdev)
|
||||
android_enable_function(&_context.function, enabled);
|
||||
_context.function_enable = !!enabled;
|
||||
smd_diag_enable("diag_set_enabled", enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -872,7 +1218,7 @@ module_param_call(tx_rx_count, NULL, diag_get_tx_rx_count, NULL, 0444);
|
||||
|
||||
static int diag_get_enabled(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
buffer[0] = '0' + !_context.function.disabled;
|
||||
buffer[0] = '0' + !_context.function.hidden;
|
||||
return 1;
|
||||
}
|
||||
module_param_call(enabled, diag_set_enabled, diag_get_enabled, NULL, 0664);
|
||||
@ -885,20 +1231,15 @@ int diag_bind_config(struct usb_configuration *c)
|
||||
|
||||
printk(KERN_INFO "diag_bind_config\n");
|
||||
|
||||
ret = smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify);
|
||||
if (ret)
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_ARCH_QSD8X50
|
||||
ret = smd_open("DSP_DIAG", &ctxt->ch_dsp, ctxt, dsp_diag_notify);
|
||||
if (ret) {
|
||||
pr_err("%s: smd_open failed (DSP_DIAG)\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
diag_string_defs[0].id = ret;
|
||||
diag_interface_desc.iInterface = ret;
|
||||
|
||||
ctxt->cdev = c->cdev;
|
||||
ctxt->function.name = "diag";
|
||||
ctxt->function.strings = diag_strings;
|
||||
ctxt->function.descriptors = fs_diag_descs;
|
||||
ctxt->function.hs_descriptors = hs_diag_descs;
|
||||
ctxt->function.bind = diag_function_bind;
|
||||
@ -906,7 +1247,9 @@ int diag_bind_config(struct usb_configuration *c)
|
||||
ctxt->function.set_alt = diag_function_set_alt;
|
||||
ctxt->function.disable = diag_function_disable;
|
||||
|
||||
ctxt->function.disabled = !_context.function_enable;
|
||||
ctxt->function.hidden = !_context.function_enable;
|
||||
if (!ctxt->function.hidden)
|
||||
smd_diag_enable("diag_bind_config", 1);
|
||||
|
||||
return usb_add_function(c, &ctxt->function);
|
||||
}
|
||||
@ -924,12 +1267,26 @@ static int __init init(void)
|
||||
spin_lock_init(&ctxt->req_lock);
|
||||
INIT_LIST_HEAD(&ctxt->rx_req_idle);
|
||||
INIT_LIST_HEAD(&ctxt->tx_req_idle);
|
||||
INIT_LIST_HEAD(&ctxt->rx_arm9_idle);
|
||||
INIT_LIST_HEAD(&ctxt->rx_arm9_done);
|
||||
#if ROUTE_TO_USERSPACE
|
||||
mutex_init(&ctxt->user_lock);
|
||||
INIT_LIST_HEAD(&ctxt->rx_req_user);
|
||||
init_waitqueue_head(&ctxt->read_wq);
|
||||
init_waitqueue_head(&ctxt->write_wq);
|
||||
#endif
|
||||
init_waitqueue_head(&ctxt->read_arm9_wq);
|
||||
mutex_init(&ctxt->diag2arm9_lock);
|
||||
mutex_init(&ctxt->diag2arm9_read_lock);
|
||||
mutex_init(&ctxt->diag2arm9_write_lock);
|
||||
mutex_init(&ctxt->smd_lock);
|
||||
ctxt->is2ARM11 = 0;
|
||||
|
||||
#if defined(CONFIG_MSM_N_WAY_SMD)
|
||||
INIT_LIST_HEAD(&ctxt->tx_qdsp_idle);
|
||||
platform_driver_register(&msm_smd_qdsp_ch1_driver);
|
||||
#endif
|
||||
ctxt->init_done = 1;
|
||||
|
||||
android_register_function(&diag_function);
|
||||
return 0;
|
||||
|
@ -31,11 +31,13 @@
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#include <linux/usb/android_composite.h>
|
||||
#include <mach/board.h>
|
||||
|
||||
#define BULK_BUFFER_SIZE 4096
|
||||
|
||||
/* number of tx requests to allocate */
|
||||
#define TX_REQ_MAX 4
|
||||
#define RX_REQ_MAX 32
|
||||
|
||||
static const char shortname[] = "android_adb";
|
||||
|
||||
@ -55,11 +57,18 @@ struct adb_dev {
|
||||
atomic_t open_excl;
|
||||
|
||||
struct list_head tx_idle;
|
||||
struct list_head rx_idle;
|
||||
struct list_head rx_done;
|
||||
|
||||
wait_queue_head_t read_wq;
|
||||
wait_queue_head_t write_wq;
|
||||
struct usb_request *rx_req;
|
||||
int rx_done;
|
||||
|
||||
/* the request we're currently reading from */
|
||||
struct usb_request *read_req;
|
||||
unsigned char *read_buf;
|
||||
unsigned read_count;
|
||||
|
||||
int maxsize;
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor adb_interface_desc = {
|
||||
@ -116,6 +125,22 @@ static struct usb_descriptor_header *hs_adb_descs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* string descriptors: */
|
||||
|
||||
static struct usb_string adb_string_defs[] = {
|
||||
[0].s = "ADB",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings adb_string_table = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = adb_string_defs,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *adb_strings[] = {
|
||||
&adb_string_table,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* temporary variable used between adb_open() and adb_gadget_bind() */
|
||||
static struct adb_dev *_adb_dev;
|
||||
@ -211,9 +236,11 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct adb_dev *dev = _adb_dev;
|
||||
|
||||
dev->rx_done = 1;
|
||||
if (req->status != 0)
|
||||
if (req->status != 0) {
|
||||
dev->error = 1;
|
||||
req_put(dev, &dev->rx_idle, req);
|
||||
} else
|
||||
req_put(dev, &dev->rx_done, req);
|
||||
|
||||
wake_up(&dev->read_wq);
|
||||
}
|
||||
@ -248,11 +275,13 @@ static int __init create_bulk_endpoints(struct adb_dev *dev,
|
||||
dev->ep_out = ep;
|
||||
|
||||
/* now allocate requests for our endpoints */
|
||||
req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE);
|
||||
if (!req)
|
||||
goto fail;
|
||||
req->complete = adb_complete_out;
|
||||
dev->rx_req = req;
|
||||
for (i = 0; i < RX_REQ_MAX; i++) {
|
||||
req = adb_request_new(dev->ep_out, 512);
|
||||
if (!req)
|
||||
goto fail;
|
||||
req->complete = adb_complete_out;
|
||||
req_put(dev, &dev->rx_idle, req);
|
||||
}
|
||||
|
||||
for (i = 0; i < TX_REQ_MAX; i++) {
|
||||
req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE);
|
||||
@ -300,40 +329,70 @@ static ssize_t adb_read(struct file *fp, char __user *buf,
|
||||
r = -EIO;
|
||||
goto done;
|
||||
}
|
||||
while (count > 0) {
|
||||
if (dev->error) {
|
||||
r = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we have idle read requests, get them queued */
|
||||
while ((req = req_get(dev, &dev->rx_idle))) {
|
||||
requeue_req:
|
||||
/* queue a request */
|
||||
req = dev->rx_req;
|
||||
req->length = count;
|
||||
dev->rx_done = 0;
|
||||
ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
DBG(cdev, "adb_read: failed to queue req %p (%d)\n", req, ret);
|
||||
r = -EIO;
|
||||
dev->error = 1;
|
||||
goto done;
|
||||
} else {
|
||||
DBG(cdev, "rx %p queue\n", req);
|
||||
}
|
||||
req->length = dev->maxsize?dev->maxsize:512;
|
||||
ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
printk(KERN_INFO "adb_read: failed to queue req (%d)\n", ret);
|
||||
r = -EIO;
|
||||
dev->error = 1;
|
||||
req_put(dev, &dev->rx_idle, req);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for a request to complete */
|
||||
ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
|
||||
if (ret < 0) {
|
||||
dev->error = 1;
|
||||
r = ret;
|
||||
goto done;
|
||||
}
|
||||
if (!dev->error) {
|
||||
/* If we got a 0-len packet, throw it back and try again. */
|
||||
if (req->actual == 0)
|
||||
goto requeue_req;
|
||||
/* if we have data pending, give it to userspace */
|
||||
if (dev->read_count > 0) {
|
||||
xfer = (dev->read_count < count) ? dev->read_count : count;
|
||||
|
||||
DBG(cdev, "rx %p %d\n", req, req->actual);
|
||||
xfer = (req->actual < count) ? req->actual : count;
|
||||
if (copy_to_user(buf, req->buf, xfer))
|
||||
r = -EFAULT;
|
||||
} else
|
||||
r = -EIO;
|
||||
if (copy_to_user(buf, dev->read_buf, xfer)) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
dev->read_buf += xfer;
|
||||
dev->read_count -= xfer;
|
||||
buf += xfer;
|
||||
count -= xfer;
|
||||
|
||||
/* if we've emptied the buffer, release the request */
|
||||
if (dev->read_count == 0) {
|
||||
req_put(dev, &dev->rx_idle, dev->read_req);
|
||||
dev->read_req = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* wait for a request to complete */
|
||||
req = 0;
|
||||
ret = wait_event_interruptible(dev->read_wq,
|
||||
((req = req_get(dev, &dev->rx_done)) || dev->error));
|
||||
|
||||
if (req != 0) {
|
||||
/* if we got a 0-len one we need to put it back into
|
||||
** service. if we made it the current read req we'd
|
||||
** be stuck forever
|
||||
*/
|
||||
if (req->actual == 0)
|
||||
goto requeue_req;
|
||||
|
||||
dev->read_req = req;
|
||||
dev->read_count = req->actual;
|
||||
dev->read_buf = req->buf;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
r = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
_unlock(&dev->read_excl);
|
||||
@ -521,7 +580,10 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
spin_lock_irq(&dev->lock);
|
||||
|
||||
adb_request_free(dev->rx_req, dev->ep_out);
|
||||
while ((req = req_get(dev, &dev->rx_done)))
|
||||
adb_request_free(req, dev->ep_out);
|
||||
while ((req = req_get(dev, &dev->rx_idle)))
|
||||
adb_request_free(req, dev->ep_out);
|
||||
while ((req = req_get(dev, &dev->tx_idle)))
|
||||
adb_request_free(req, dev->ep_in);
|
||||
|
||||
@ -541,6 +603,7 @@ static int adb_function_set_alt(struct usb_function *f,
|
||||
struct adb_dev *dev = func_to_dev(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
int ret;
|
||||
struct usb_request *req;
|
||||
|
||||
DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
|
||||
ret = usb_ep_enable(dev->ep_in,
|
||||
@ -557,7 +620,17 @@ static int adb_function_set_alt(struct usb_function *f,
|
||||
usb_ep_disable(dev->ep_in);
|
||||
return ret;
|
||||
}
|
||||
dev->online = 1;
|
||||
if (cdev->gadget->speed == USB_SPEED_FULL)
|
||||
dev->maxsize = 64;
|
||||
else
|
||||
dev->maxsize = 512;
|
||||
printk(KERN_INFO "%s: maxsize = %d\n", __func__, dev->maxsize);
|
||||
|
||||
/* retire any completed rx requests from previous session */
|
||||
while ((req = req_get(dev, &dev->rx_done)))
|
||||
req_put(dev, &dev->rx_idle, req);
|
||||
|
||||
dev->online = !dev->function.hidden;
|
||||
|
||||
/* readers may be blocked waiting for us to go online */
|
||||
wake_up(&dev->read_wq);
|
||||
@ -572,6 +645,7 @@ static void adb_function_disable(struct usb_function *f)
|
||||
DBG(cdev, "adb_function_disable\n");
|
||||
dev->online = 0;
|
||||
dev->error = 1;
|
||||
dev->maxsize = 0;
|
||||
usb_ep_disable(dev->ep_in);
|
||||
usb_ep_disable(dev->ep_out);
|
||||
|
||||
@ -602,18 +676,27 @@ static int adb_bind_config(struct usb_configuration *c)
|
||||
atomic_set(&dev->write_excl, 0);
|
||||
|
||||
INIT_LIST_HEAD(&dev->tx_idle);
|
||||
INIT_LIST_HEAD(&dev->rx_idle);
|
||||
INIT_LIST_HEAD(&dev->rx_done);
|
||||
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
adb_string_defs[0].id = ret;
|
||||
adb_interface_desc.iInterface = ret;
|
||||
dev->cdev = c->cdev;
|
||||
dev->function.name = "adb";
|
||||
dev->function.strings = adb_strings;
|
||||
dev->function.descriptors = fs_adb_descs;
|
||||
dev->function.hs_descriptors = hs_adb_descs;
|
||||
dev->function.bind = adb_function_bind;
|
||||
dev->function.unbind = adb_function_unbind;
|
||||
dev->function.set_alt = adb_function_set_alt;
|
||||
dev->function.disable = adb_function_disable;
|
||||
dev->maxsize = 512;
|
||||
|
||||
/* start disabled */
|
||||
dev->function.disabled = 1;
|
||||
if (board_mfg_mode() != 2)
|
||||
dev->function.hidden = 1;
|
||||
|
||||
/* _adb_dev must be set before calling usb_gadget_register_driver */
|
||||
_adb_dev = dev;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Gadget Function Driver for MTP
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* Author: Mike Lockwood <lockwood@android.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_F_MTP_H
|
||||
#define __LINUX_USB_F_MTP_H
|
||||
|
||||
/* Constants for MTP_SET_INTERFACE_MODE */
|
||||
#define MTP_INTERFACE_MODE_MTP 0
|
||||
#define MTP_INTERFACE_MODE_PTP 1
|
||||
|
||||
|
||||
struct mtp_file_range {
|
||||
/* file descriptor for file to transfer */
|
||||
int fd;
|
||||
/* offset in file for start of transfer */
|
||||
loff_t offset;
|
||||
/* number of bytes to transfer */
|
||||
int64_t length;
|
||||
};
|
||||
|
||||
struct mtp_event {
|
||||
/* size of the event */
|
||||
size_t length;
|
||||
/* event data to send */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Sends the specified file range to the host */
|
||||
#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
|
||||
/* Receives data from the host and writes it to a file.
|
||||
* The file is created if it does not exist.
|
||||
*/
|
||||
#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
|
||||
/* Sets the driver mode to either MTP or PTP */
|
||||
#define MTP_SET_INTERFACE_MODE _IOW('M', 2, int)
|
||||
/* Sends an event to the host via the interrupt endpoint */
|
||||
#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
|
||||
|
||||
#endif /* __LINUX_USB_F_MTP_H */
|
@ -4,8 +4,6 @@
|
||||
* Copyright (C) 2003-2005,2008 David Brownell
|
||||
* 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)
|
||||
*
|
||||
* 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
|
||||
@ -24,7 +22,6 @@
|
||||
|
||||
/* #define VERBOSE_DEBUG */
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/etherdevice.h>
|
||||
@ -123,7 +120,7 @@ static unsigned int bitrate(struct usb_gadget *g)
|
||||
|
||||
/* interface descriptor: */
|
||||
|
||||
static struct usb_interface_descriptor rndis_control_intf = {
|
||||
static struct usb_interface_descriptor rndis_control_intf __initdata = {
|
||||
.bLength = sizeof rndis_control_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -133,7 +130,7 @@ static struct usb_interface_descriptor rndis_control_intf = {
|
||||
#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS
|
||||
/* "Wireless" RNDIS; auto-detected by Windows */
|
||||
.bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 3,
|
||||
#else
|
||||
.bInterfaceClass = USB_CLASS_COMM,
|
||||
@ -143,7 +140,7 @@ static struct usb_interface_descriptor rndis_control_intf = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_header_desc header_desc = {
|
||||
static struct usb_cdc_header_desc header_desc __initdata = {
|
||||
.bLength = sizeof header_desc,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
@ -151,7 +148,7 @@ static struct usb_cdc_header_desc header_desc = {
|
||||
.bcdCDC = cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
|
||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
|
||||
.bLength = sizeof call_mgmt_descriptor,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
|
||||
@ -160,15 +157,15 @@ static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
|
||||
.bDataInterface = 0x01,
|
||||
};
|
||||
|
||||
static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
|
||||
.bLength = sizeof rndis_acm_descriptor,
|
||||
static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
|
||||
.bLength = sizeof acm_descriptor,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
|
||||
.bmCapabilities = 0x00,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc rndis_union_desc = {
|
||||
static struct usb_cdc_union_desc rndis_union_desc __initdata = {
|
||||
.bLength = sizeof(rndis_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
@ -178,7 +175,7 @@ static struct usb_cdc_union_desc rndis_union_desc = {
|
||||
|
||||
/* the data interface has two bulk endpoints */
|
||||
|
||||
static struct usb_interface_descriptor rndis_data_intf = {
|
||||
static struct usb_interface_descriptor rndis_data_intf __initdata = {
|
||||
.bLength = sizeof rndis_data_intf,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
@ -190,23 +187,9 @@ static struct usb_interface_descriptor rndis_data_intf = {
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
|
||||
static struct usb_interface_assoc_descriptor
|
||||
rndis_iad_descriptor = {
|
||||
.bLength = sizeof rndis_iad_descriptor,
|
||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||
|
||||
.bFirstInterface = 0, /* XXX, hardcoded */
|
||||
.bInterfaceCount = 2, // control + data
|
||||
.bFunctionClass = USB_CLASS_COMM,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
|
||||
.bFunctionProtocol = USB_CDC_PROTO_NONE,
|
||||
/* .iFunction = DYNAMIC */
|
||||
};
|
||||
|
||||
/* full speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor fs_notify_desc = {
|
||||
static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -216,7 +199,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = {
|
||||
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_in_desc = {
|
||||
static struct usb_endpoint_descriptor fs_in_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -224,7 +207,7 @@ static struct usb_endpoint_descriptor fs_in_desc = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor fs_out_desc = {
|
||||
static struct usb_endpoint_descriptor fs_out_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -232,13 +215,12 @@ static struct usb_endpoint_descriptor fs_out_desc = {
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *eth_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||
static struct usb_descriptor_header *eth_fs_function[] __initdata = {
|
||||
/* control interface matches ACM, not Ethernet */
|
||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||
(struct usb_descriptor_header *) &header_desc,
|
||||
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||
(struct usb_descriptor_header *) &acm_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||
(struct usb_descriptor_header *) &fs_notify_desc,
|
||||
/* data interface has no altsetting */
|
||||
@ -250,7 +232,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {
|
||||
|
||||
/* high speed support: */
|
||||
|
||||
static struct usb_endpoint_descriptor hs_notify_desc = {
|
||||
static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -259,7 +241,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
|
||||
};
|
||||
static struct usb_endpoint_descriptor hs_in_desc = {
|
||||
static struct usb_endpoint_descriptor hs_in_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -268,7 +250,7 @@ static struct usb_endpoint_descriptor hs_in_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hs_out_desc = {
|
||||
static struct usb_endpoint_descriptor hs_out_desc __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
@ -277,13 +259,12 @@ static struct usb_endpoint_descriptor hs_out_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *eth_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &rndis_iad_descriptor,
|
||||
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
|
||||
/* control interface matches ACM, not Ethernet */
|
||||
(struct usb_descriptor_header *) &rndis_control_intf,
|
||||
(struct usb_descriptor_header *) &header_desc,
|
||||
(struct usb_descriptor_header *) &call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_acm_descriptor,
|
||||
(struct usb_descriptor_header *) &acm_descriptor,
|
||||
(struct usb_descriptor_header *) &rndis_union_desc,
|
||||
(struct usb_descriptor_header *) &hs_notify_desc,
|
||||
/* data interface has no altsetting */
|
||||
@ -298,7 +279,6 @@ static struct usb_descriptor_header *eth_hs_function[] = {
|
||||
static struct usb_string rndis_string_defs[] = {
|
||||
[0].s = "RNDIS Communications Control",
|
||||
[1].s = "RNDIS Ethernet Data",
|
||||
[2].s = "RNDIS",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
@ -606,7 +586,7 @@ static void rndis_close(struct gether *geth)
|
||||
|
||||
/* ethernet function driver setup/binding */
|
||||
|
||||
static int
|
||||
static int __init
|
||||
rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
@ -619,7 +599,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
rndis->ctrl_id = status;
|
||||
rndis_iad_descriptor.bFirstInterface = status;
|
||||
|
||||
rndis_control_intf.bInterfaceNumber = status;
|
||||
rndis_union_desc.bMasterInterface0 = status;
|
||||
@ -783,6 +762,10 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
/* Some controllers can't support RNDIS ... */
|
||||
static inline bool can_support_rndis(struct usb_configuration *c)
|
||||
{
|
||||
/* only two endpoints on sa1100 */
|
||||
if (gadget_is_sa1100(c->cdev->gadget))
|
||||
return false;
|
||||
|
||||
/* everything else is *presumably* fine */
|
||||
return true;
|
||||
}
|
||||
@ -799,8 +782,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int
|
||||
rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
struct f_rndis *rndis;
|
||||
int status;
|
||||
@ -829,13 +811,6 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
return status;
|
||||
rndis_string_defs[1].id = status;
|
||||
rndis_data_intf.iInterface = status;
|
||||
|
||||
/* IAD iFunction label */
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
rndis_string_defs[2].id = status;
|
||||
rndis_iad_descriptor.iFunction = status;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
@ -865,7 +840,7 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
|
||||
#ifdef CONFIG_USB_ANDROID_RNDIS
|
||||
/* start disabled */
|
||||
rndis->port.func.disabled = 1;
|
||||
rndis->port.func.hidden = 1;
|
||||
#endif
|
||||
|
||||
status = usb_add_function(c, &rndis->port.func);
|
||||
@ -880,7 +855,7 @@ fail:
|
||||
#ifdef CONFIG_USB_ANDROID_RNDIS
|
||||
#include "rndis.c"
|
||||
|
||||
static int rndis_probe(struct platform_device *pdev)
|
||||
static int __init rndis_probe(struct platform_device *pdev)
|
||||
{
|
||||
rndis_pdata = pdev->dev.platform_data;
|
||||
return 0;
|
||||
|
@ -10,14 +10,14 @@
|
||||
* either version 2 of that License or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb/android_composite.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
#define CONFIG_MODEM_SUPPORT
|
||||
/*
|
||||
* This function packages a simple "generic serial" port with no real
|
||||
* control mechanisms, just raw data transfer over two bulk endpoints.
|
||||
@ -30,78 +30,187 @@
|
||||
struct gser_descs {
|
||||
struct usb_endpoint_descriptor *in;
|
||||
struct usb_endpoint_descriptor *out;
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
struct usb_endpoint_descriptor *notify;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct f_gser {
|
||||
struct gserial port;
|
||||
u8 data_id;
|
||||
u8 port_num;
|
||||
u8 disabled;
|
||||
u8 configured;
|
||||
|
||||
struct gser_descs fs;
|
||||
struct gser_descs hs;
|
||||
u8 online;
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
u8 pending;
|
||||
spinlock_t lock;
|
||||
struct usb_ep *notify;
|
||||
struct usb_endpoint_descriptor *notify_desc;
|
||||
struct usb_request *notify_req;
|
||||
|
||||
struct usb_cdc_line_coding port_line_coding;
|
||||
|
||||
/* SetControlLineState request */
|
||||
u16 port_handshake_bits;
|
||||
#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
|
||||
#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
|
||||
|
||||
/* SerialState notification */
|
||||
u16 serial_state;
|
||||
#define ACM_CTRL_OVERRUN (1 << 6)
|
||||
#define ACM_CTRL_PARITY (1 << 5)
|
||||
#define ACM_CTRL_FRAMING (1 << 4)
|
||||
#define ACM_CTRL_RI (1 << 3)
|
||||
#define ACM_CTRL_BRK (1 << 2)
|
||||
#define ACM_CTRL_DSR (1 << 1)
|
||||
#define ACM_CTRL_DCD (1 << 0)
|
||||
#endif
|
||||
};
|
||||
static struct usb_function *modem_function;
|
||||
static struct usb_function *serial_function;
|
||||
|
||||
static inline struct f_gser *func_to_gser(struct usb_function *f)
|
||||
{
|
||||
return container_of(f, struct f_gser, port.func);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static inline struct f_gser *port_to_gser(struct gserial *p)
|
||||
{
|
||||
return container_of(p, struct f_gser, port);
|
||||
}
|
||||
#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
|
||||
#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
|
||||
#endif
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* interface descriptor: */
|
||||
|
||||
static struct usb_interface_descriptor gser_interface_desc __initdata = {
|
||||
static struct usb_interface_descriptor gser_interface_desc = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
.bNumEndpoints = 3,
|
||||
#else
|
||||
.bNumEndpoints = 2,
|
||||
#endif
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
/* .iInterface = DYNAMIC */
|
||||
};
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static struct usb_cdc_header_desc gser_header_desc = {
|
||||
.bLength = sizeof(gser_header_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||
.bcdCDC = __constant_cpu_to_le16(0x0110),
|
||||
};
|
||||
|
||||
static struct usb_cdc_call_mgmt_descriptor
|
||||
gser_call_mgmt_descriptor = {
|
||||
.bLength = sizeof(gser_call_mgmt_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
|
||||
.bmCapabilities = 0,
|
||||
/* .bDataInterface = DYNAMIC */
|
||||
};
|
||||
|
||||
static struct usb_cdc_acm_descriptor gser_descriptor = {
|
||||
.bLength = sizeof(gser_descriptor),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||
.bmCapabilities = USB_CDC_CAP_LINE,
|
||||
};
|
||||
|
||||
static struct usb_cdc_union_desc gser_union_desc = {
|
||||
.bLength = sizeof(gser_union_desc),
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||
/* .bMasterInterface0 = DYNAMIC */
|
||||
/* .bSlaveInterface0 = DYNAMIC */
|
||||
};
|
||||
#endif
|
||||
/* full speed support: */
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static struct usb_endpoint_descriptor gser_fs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_fs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_fs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_fs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *gser_fs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
(struct usb_descriptor_header *) &gser_header_desc,
|
||||
(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_union_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_notify_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &gser_fs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_fs_out_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* high speed support: */
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static struct usb_endpoint_descriptor gser_hs_notify_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
|
||||
.bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_hs_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
|
||||
static struct usb_endpoint_descriptor gser_hs_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.wMaxPacketSize = __constant_cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *gser_hs_function[] __initdata = {
|
||||
static struct usb_descriptor_header *gser_hs_function[] = {
|
||||
(struct usb_descriptor_header *) &gser_interface_desc,
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
(struct usb_descriptor_header *) &gser_header_desc,
|
||||
(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_descriptor,
|
||||
(struct usb_descriptor_header *) &gser_union_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_notify_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &gser_hs_in_desc,
|
||||
(struct usb_descriptor_header *) &gser_hs_out_desc,
|
||||
NULL,
|
||||
@ -109,64 +218,365 @@ static struct usb_descriptor_header *gser_hs_function[] __initdata = {
|
||||
|
||||
/* string descriptors: */
|
||||
|
||||
static struct usb_string gser_string_defs[] = {
|
||||
[0].s = "Generic Serial",
|
||||
static struct usb_string modem_string_defs[] = {
|
||||
[0].s = "HTC Modem",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings gser_string_table = {
|
||||
static struct usb_gadget_strings modem_string_table = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = gser_string_defs,
|
||||
.strings = modem_string_defs,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *gser_strings[] = {
|
||||
&gser_string_table,
|
||||
static struct usb_gadget_strings *modem_strings[] = {
|
||||
&modem_string_table,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static struct usb_string serial_string_defs[] = {
|
||||
[0].s = "HTC Serial",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings serial_string_table = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = serial_string_defs,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *serial_strings[] = {
|
||||
&serial_string_table,
|
||||
NULL,
|
||||
};
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static void gser_complete_set_line_coding(struct usb_ep *ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
struct f_gser *gser = ep->driver_data;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
|
||||
if (req->status != 0) {
|
||||
DBG(cdev, "gser ttyGS%d completion, err %d\n",
|
||||
gser->port_num, req->status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* normal completion */
|
||||
if (req->actual != sizeof(gser->port_line_coding)) {
|
||||
DBG(cdev, "gser ttyGS%d short resp, len %d\n",
|
||||
gser->port_num, req->actual);
|
||||
usb_ep_set_halt(ep);
|
||||
} else {
|
||||
struct usb_cdc_line_coding *value = req->buf;
|
||||
gser->port_line_coding = *value;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int
|
||||
gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct usb_request *req = cdev->req;
|
||||
int value = -EOPNOTSUPP;
|
||||
u16 w_index = le16_to_cpu(ctrl->wIndex);
|
||||
u16 w_value = le16_to_cpu(ctrl->wValue);
|
||||
u16 w_length = le16_to_cpu(ctrl->wLength);
|
||||
|
||||
switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
||||
|
||||
/* SET_LINE_CODING ... just read and save what the host sends */
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_SET_LINE_CODING:
|
||||
if (w_length != sizeof(struct usb_cdc_line_coding)
|
||||
|| w_index != gser->data_id)
|
||||
goto invalid;
|
||||
value = w_length;
|
||||
cdev->gadget->ep0->driver_data = gser;
|
||||
req->complete = gser_complete_set_line_coding;
|
||||
break;
|
||||
|
||||
/* GET_LINE_CODING ... return what host sent, or initial value */
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_GET_LINE_CODING:
|
||||
if (w_index != gser->data_id)
|
||||
goto invalid;
|
||||
|
||||
value = min_t(unsigned, w_length,
|
||||
sizeof(struct usb_cdc_line_coding));
|
||||
memcpy(req->buf, &gser->port_line_coding, value);
|
||||
break;
|
||||
|
||||
/* SET_CONTROL_LINE_STATE ... save what the host sent */
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
||||
| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
||||
if (w_index != gser->data_id)
|
||||
goto invalid;
|
||||
|
||||
value = 0;
|
||||
gser->port_handshake_bits = w_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid:
|
||||
ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
|
||||
ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
}
|
||||
|
||||
/* respond with data transfer or status phase? */
|
||||
if (value >= 0) {
|
||||
DBG(cdev, "gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
|
||||
gser->port_num, ctrl->bRequestType, ctrl->bRequest,
|
||||
w_value, w_index, w_length);
|
||||
req->zero = 0;
|
||||
req->length = value;
|
||||
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
||||
if (value < 0)
|
||||
ERROR(cdev, "gser response on ttyGS%d, err %d\n",
|
||||
gser->port_num, value);
|
||||
}
|
||||
|
||||
/* device either stalls (value < 0) or reports success */
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct usb_interface_descriptor *desc;
|
||||
|
||||
/* we know alt == 0, so this is an activation or a reset */
|
||||
if (cdev->gadget->speed == USB_SPEED_HIGH)
|
||||
desc = (struct usb_interface_descriptor *) *(f->hs_descriptors);
|
||||
else
|
||||
desc = (struct usb_interface_descriptor *) *(f->descriptors);
|
||||
gser->data_id = desc->bInterfaceNumber;
|
||||
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
#if 0
|
||||
if (gser->notify->driver_data) {
|
||||
DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
|
||||
usb_ep_disable(gser->notify);
|
||||
}
|
||||
#endif
|
||||
gser->notify_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.notify,
|
||||
gser->fs.notify);
|
||||
usb_ep_enable(gser->notify, gser->notify_desc);
|
||||
gser->notify->driver_data = gser;
|
||||
#endif
|
||||
#if 0
|
||||
if (gser->port.in->driver_data) {
|
||||
DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
|
||||
gserial_disconnect(&gser->port);
|
||||
} else {
|
||||
DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
|
||||
gser->port.in_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.in, gser->fs.in);
|
||||
gser->port.out_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.out, gser->fs.out);
|
||||
}
|
||||
#endif
|
||||
gser->port.in_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.in, gser->fs.in);
|
||||
gser->port.out_desc = ep_choose(cdev->gadget,
|
||||
gser->hs.out, gser->fs.out);
|
||||
gserial_connect(&gser->port, gser->port_num);
|
||||
gser->online = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gser_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
|
||||
DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
|
||||
gserial_disconnect(&gser->port);
|
||||
#if 0
|
||||
/* disable endpoints, aborting down any active I/O */
|
||||
usb_ep_fifo_flush(gser->port.out);
|
||||
usb_ep_disable(gser->port.out);
|
||||
gser->port.out->driver_data = NULL;
|
||||
|
||||
usb_ep_fifo_flush(gser->port.in);
|
||||
usb_ep_disable(gser->port.in);
|
||||
gser->port.in->driver_data = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
usb_ep_fifo_flush(gser->notify);
|
||||
usb_ep_disable(gser->notify);
|
||||
gser->notify->driver_data = NULL;
|
||||
#endif
|
||||
gser->online = 0;
|
||||
}
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static int gser_notify(struct f_gser *gser, u8 type, u16 value,
|
||||
void *data, unsigned length)
|
||||
{
|
||||
struct usb_ep *ep = gser->notify;
|
||||
struct usb_request *req;
|
||||
struct usb_cdc_notification *notify;
|
||||
const unsigned len = sizeof(*notify) + length;
|
||||
void *buf;
|
||||
int status;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
|
||||
req = gser->notify_req;
|
||||
gser->notify_req = NULL;
|
||||
gser->pending = false;
|
||||
|
||||
req->length = len;
|
||||
notify = req->buf;
|
||||
buf = notify + 1;
|
||||
|
||||
notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
|
||||
| USB_RECIP_INTERFACE;
|
||||
notify->bNotificationType = type;
|
||||
notify->wValue = cpu_to_le16(value);
|
||||
notify->wIndex = cpu_to_le16(gser->data_id);
|
||||
notify->wLength = cpu_to_le16(length);
|
||||
memcpy(buf, data, length);
|
||||
|
||||
status = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
|
||||
gser->port_num, status);
|
||||
gser->notify_req = req;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int gser_notify_serial_state(struct f_gser *gser)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
struct usb_composite_dev *cdev = gser->port.func.config->cdev;
|
||||
if (gser->disabled)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&gser->lock, flags);
|
||||
if (gser->notify_req) {
|
||||
DBG(cdev, "gser ttyGS%d serial state %04x\n",
|
||||
gser->port_num, gser->serial_state);
|
||||
status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
|
||||
0, &gser->serial_state,
|
||||
sizeof(gser->serial_state));
|
||||
} else {
|
||||
gser->pending = true;
|
||||
status = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&gser->lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_gser *gser = req->context;
|
||||
u8 doit = false;
|
||||
unsigned long flags;
|
||||
|
||||
/* on this call path we do NOT hold the port spinlock,
|
||||
* which is why ACM needs its own spinlock
|
||||
*/
|
||||
spin_lock_irqsave(&gser->lock, flags);
|
||||
if (req->status != -ESHUTDOWN)
|
||||
doit = gser->pending;
|
||||
gser->notify_req = req;
|
||||
spin_unlock_irqrestore(&gser->lock, flags);
|
||||
|
||||
if (doit && gser->online)
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
static void gser_connect(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
unsigned int gser_get_dtr(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
if (gser->port_handshake_bits & ACM_CTRL_DTR)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int gser_get_rts(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
if (gser->port_handshake_bits & ACM_CTRL_RTS)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int gser_send_carrier_detect(struct gserial *port, unsigned int yes)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
u16 state;
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_DCD;
|
||||
if (yes)
|
||||
state |= ACM_CTRL_DCD;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
|
||||
}
|
||||
|
||||
unsigned int gser_send_ring_indicator(struct gserial *port, unsigned int yes)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
u16 state;
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_RI;
|
||||
if (yes)
|
||||
state |= ACM_CTRL_RI;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
|
||||
}
|
||||
static void gser_disconnect(struct gserial *port)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
|
||||
gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
|
||||
gser_notify_serial_state(gser);
|
||||
}
|
||||
|
||||
static int gser_send_break(struct gserial *port, int duration)
|
||||
{
|
||||
struct f_gser *gser = port_to_gser(port);
|
||||
u16 state;
|
||||
|
||||
state = gser->serial_state;
|
||||
state &= ~ACM_CTRL_BRK;
|
||||
if (duration)
|
||||
state |= ACM_CTRL_BRK;
|
||||
|
||||
gser->serial_state = state;
|
||||
return gser_notify_serial_state(gser);
|
||||
}
|
||||
#endif
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* serial function driver setup/binding */
|
||||
|
||||
static int __init
|
||||
static int
|
||||
gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct usb_composite_dev *cdev = c->cdev;
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
struct usb_gadget_strings *s;
|
||||
|
||||
/* allocate instance-specific interface IDs */
|
||||
status = usb_interface_id(c, f);
|
||||
@ -174,6 +584,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
goto fail;
|
||||
gser->data_id = status;
|
||||
gser_interface_desc.bInterfaceNumber = status;
|
||||
if (f->strings) {
|
||||
s = *(f->strings);
|
||||
gser_interface_desc.iInterface = s->strings[0].id;
|
||||
}
|
||||
|
||||
status = -ENODEV;
|
||||
|
||||
@ -182,13 +596,30 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (!ep)
|
||||
goto fail;
|
||||
gser->port.in = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
ep->driver_data = gser; /* claim */
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
gser->port.out = ep;
|
||||
ep->driver_data = cdev; /* claim */
|
||||
ep->driver_data = gser; /* claim */
|
||||
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
gser->notify = ep;
|
||||
ep->driver_data = gser; /* claim */
|
||||
/* allocate notification */
|
||||
gser->notify_req = gs_alloc_req(ep,
|
||||
sizeof(struct usb_cdc_notification) + 2,
|
||||
GFP_KERNEL);
|
||||
if (!gser->notify_req)
|
||||
goto fail;
|
||||
|
||||
gser->notify_req->complete = gser_notify_complete;
|
||||
gser->notify_req->context = gser;
|
||||
#endif
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->descriptors = usb_copy_descriptors(gser_fs_function);
|
||||
@ -197,6 +628,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->descriptors, &gser_fs_in_desc);
|
||||
gser->fs.out = usb_find_endpoint(gser_fs_function,
|
||||
f->descriptors, &gser_fs_out_desc);
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
gser->fs.notify = usb_find_endpoint(gser_fs_function,
|
||||
f->descriptors, &gser_fs_notify_desc);
|
||||
#endif
|
||||
|
||||
|
||||
/* support all relevant hardware speeds... we expect that when
|
||||
@ -208,6 +643,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
gser_fs_in_desc.bEndpointAddress;
|
||||
gser_hs_out_desc.bEndpointAddress =
|
||||
gser_fs_out_desc.bEndpointAddress;
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
gser_hs_notify_desc.bEndpointAddress =
|
||||
gser_fs_notify_desc.bEndpointAddress;
|
||||
#endif
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
|
||||
@ -216,6 +655,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
f->hs_descriptors, &gser_hs_in_desc);
|
||||
gser->hs.out = usb_find_endpoint(gser_hs_function,
|
||||
f->hs_descriptors, &gser_hs_out_desc);
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
gser->hs.notify = usb_find_endpoint(gser_hs_function,
|
||||
f->hs_descriptors, &gser_hs_notify_desc);
|
||||
#endif
|
||||
}
|
||||
|
||||
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
@ -225,6 +668,14 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
if (gser->notify_req)
|
||||
gs_free_req(gser->notify, gser->notify_req);
|
||||
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (gser->notify)
|
||||
gser->notify->driver_data = NULL;
|
||||
#endif
|
||||
/* we might as well release our claims on endpoints */
|
||||
if (gser->port.out)
|
||||
gser->port.out->driver_data = NULL;
|
||||
@ -239,9 +690,15 @@ fail:
|
||||
static void
|
||||
gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
struct f_gser *gser = func_to_gser(f);
|
||||
#endif
|
||||
if (gadget_is_dualspeed(c->cdev->gadget))
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->descriptors);
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
gs_free_req(gser->notify, gser->notify_req);
|
||||
#endif
|
||||
kfree(func_to_gser(f));
|
||||
}
|
||||
|
||||
@ -257,9 +714,9 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
* handle all the ones it binds. Caller is also responsible
|
||||
* for calling @gserial_cleanup() before module unload.
|
||||
*/
|
||||
int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
int gser_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
{
|
||||
struct f_gser *gser;
|
||||
struct f_gser *gser;
|
||||
int status;
|
||||
|
||||
/* REVISIT might want instance-specific strings to help
|
||||
@ -267,29 +724,129 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
|
||||
*/
|
||||
|
||||
/* maybe allocate device-global string ID */
|
||||
if (gser_string_defs[0].id == 0) {
|
||||
if (modem_string_defs[0].id == 0 && port_num == 0) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0)
|
||||
if (status < 0) {
|
||||
printk(KERN_ERR "%s: return %d\n", __func__, status);
|
||||
return status;
|
||||
gser_string_defs[0].id = status;
|
||||
}
|
||||
modem_string_defs[0].id = status;
|
||||
}
|
||||
if (serial_string_defs[0].id == 0 && port_num == 2) {
|
||||
status = usb_string_id(c->cdev);
|
||||
if (status < 0) {
|
||||
printk(KERN_ERR "%s: return %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
serial_string_defs[0].id = status;
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
gser = kzalloc(sizeof *gser, GFP_KERNEL);
|
||||
if (!gser)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
spin_lock_init(&gser->lock);
|
||||
#endif
|
||||
gser->port_num = port_num;
|
||||
|
||||
gser->port.func.name = "gser";
|
||||
gser->port.func.strings = gser_strings;
|
||||
if (port_num == 0) {
|
||||
gser->port.func.name = "modem";
|
||||
gser->port.func.strings = modem_strings;
|
||||
modem_function = &gser->port.func;
|
||||
} else if (port_num == 2) {
|
||||
gser->port.func.name = "serial";
|
||||
gser->port.func.strings = serial_strings;
|
||||
serial_function = &gser->port.func;
|
||||
}
|
||||
gser->port.func.bind = gser_bind;
|
||||
gser->port.func.unbind = gser_unbind;
|
||||
gser->port.func.set_alt = gser_set_alt;
|
||||
gser->port.func.disable = gser_disable;
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
gser->port.func.setup = gser_setup;
|
||||
gser->port.connect = gser_connect;
|
||||
gser->port.get_dtr = gser_get_dtr;
|
||||
gser->port.get_rts = gser_get_rts;
|
||||
gser->port.send_carrier_detect = gser_send_carrier_detect;
|
||||
gser->port.send_ring_indicator = gser_send_ring_indicator;
|
||||
gser->port.disconnect = gser_disconnect;
|
||||
gser->port.send_break = gser_send_break;
|
||||
#endif
|
||||
gser->port.func.hidden = 1;
|
||||
gser->disabled = 1;
|
||||
|
||||
status = usb_add_function(c, &gser->port.func);
|
||||
if (status)
|
||||
kfree(gser);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int modem_set_enabled(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
struct f_gser *gser;
|
||||
int enabled = simple_strtol(val, NULL, 0);
|
||||
printk(KERN_INFO "%s: %d\n", __func__, enabled);
|
||||
gser = func_to_gser(modem_function);
|
||||
if (!gser)
|
||||
return 0;
|
||||
gser->disabled = !enabled;
|
||||
android_enable_function(modem_function, enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int modem_get_enabled(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
buffer[0] = '0' + !modem_function->hidden;
|
||||
printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0');
|
||||
return 1;
|
||||
}
|
||||
module_param_call(modem_enabled, modem_set_enabled, modem_get_enabled, NULL, 0664);
|
||||
|
||||
static int serial_set_enabled(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
struct f_gser *gser;
|
||||
int enabled = simple_strtol(val, NULL, 0);
|
||||
printk(KERN_INFO "%s: %d\n", __func__, enabled);
|
||||
gser = func_to_gser(serial_function);
|
||||
if (!gser)
|
||||
return 0;
|
||||
gser->disabled = !enabled;
|
||||
android_enable_function(serial_function, enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_get_enabled(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
buffer[0] = '0' + !serial_function->hidden;
|
||||
printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0');
|
||||
return 1;
|
||||
}
|
||||
module_param_call(serial_enabled, serial_set_enabled, serial_get_enabled, NULL, 0664);
|
||||
|
||||
static int serial_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "serial_bind_config\n");
|
||||
ret = gser_bind_config(c, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = gser_bind_config(c, 2);
|
||||
if (ret == 0)
|
||||
gserial_setup(c->cdev->gadget, 3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct android_usb_function android_serial_function = {
|
||||
.name = "serial",
|
||||
.bind_config = serial_bind_config,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
printk(KERN_INFO "serial init\n");
|
||||
android_register_function(&android_serial_function);
|
||||
return 0;
|
||||
}
|
||||
module_init(init);
|
||||
|
@ -49,7 +49,6 @@
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
|
||||
#include <mach/htc_headset_mgr.h>
|
||||
#endif
|
||||
#include <mach/clk.h>
|
||||
|
||||
static const char driver_name[] = "msm72k_udc";
|
||||
|
||||
@ -82,14 +81,11 @@ static struct usb_info *the_usb_info;
|
||||
static int vbus;
|
||||
static int use_mfg_serialno;
|
||||
static char mfg_df_serialno[16];
|
||||
static int disable_charger;
|
||||
|
||||
#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
|
||||
extern int htc_get_usb_accessory_adc_level(uint32_t *buffer);
|
||||
#endif
|
||||
|
||||
|
||||
static struct switch_dev dock_switch = {
|
||||
.name = "dock",
|
||||
};
|
||||
@ -99,12 +95,6 @@ static struct switch_dev dock_switch = {
|
||||
#define DOCK_STATE_CAR (1 << 1)
|
||||
#endif
|
||||
|
||||
#include <linux/wakelock.h>
|
||||
#include <mach/perflock.h>
|
||||
|
||||
static struct wake_lock vbus_idle_wake_lock;
|
||||
static struct perf_lock usb_perf_lock;
|
||||
|
||||
struct msm_request {
|
||||
struct usb_request req;
|
||||
|
||||
@ -152,10 +142,8 @@ static void check_charger(struct work_struct *w);
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
|
||||
static void accessory_detect_work(struct work_struct *w);
|
||||
#endif
|
||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
|
||||
static void dock_detect_work(struct work_struct *w);
|
||||
static void dock_detect_init(struct usb_info *ui);
|
||||
#endif
|
||||
extern int android_switch_function(unsigned func);
|
||||
extern int android_show_function(char *buf);
|
||||
extern void android_set_serialno(char *serialno);
|
||||
|
||||
#define USB_STATE_IDLE 0
|
||||
@ -212,10 +200,6 @@ struct usb_info {
|
||||
void (*phy_reset)(void);
|
||||
void (*hw_reset)(bool en);
|
||||
void (*usb_uart_switch)(int);
|
||||
void (*serial_debug_gpios)(int);
|
||||
void (*usb_hub_enable)(bool);
|
||||
int (*china_ac_detect)(void);
|
||||
void (*disable_usb_charger)(void);
|
||||
|
||||
/* for notification when USB is connected or disconnected */
|
||||
void (*usb_connected)(int);
|
||||
@ -224,7 +208,6 @@ struct usb_info {
|
||||
struct work_struct work;
|
||||
struct delayed_work chg_work;
|
||||
struct work_struct detect_work;
|
||||
struct work_struct dock_work;
|
||||
struct work_struct notifier_work;
|
||||
unsigned phy_status;
|
||||
unsigned phy_fail_count;
|
||||
@ -249,13 +232,10 @@ struct usb_info {
|
||||
u8 in_lpm;
|
||||
|
||||
/* for accessory detection */
|
||||
bool dock_detect;
|
||||
u8 accessory_detect;
|
||||
u8 mfg_usb_carkit_enable;
|
||||
int idpin_irq;
|
||||
int dockpin_irq;
|
||||
int usb_id_pin_gpio;
|
||||
int dock_pin_gpio;
|
||||
void (*config_usb_id_gpios)(bool output_enable);
|
||||
/* 0: none, 1: carkit, 2: usb headset */
|
||||
u8 accessory_type;
|
||||
@ -346,7 +326,7 @@ static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg)
|
||||
USB_ULPI_VIEWPORT);
|
||||
|
||||
/* wait for completion */
|
||||
while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
|
||||
while((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
|
||||
|
||||
if (timeout == 0) {
|
||||
printk(KERN_ERR "ulpi_write: timeout\n");
|
||||
@ -533,8 +513,6 @@ static void usb_ept_start(struct msm_endpoint *ept)
|
||||
{
|
||||
struct usb_info *ui = ept->ui;
|
||||
struct msm_request *req = ept->req;
|
||||
int i, cnt;
|
||||
unsigned n = 1 << ept->bit;
|
||||
|
||||
BUG_ON(req->live);
|
||||
|
||||
@ -542,36 +520,14 @@ static void usb_ept_start(struct msm_endpoint *ept)
|
||||
ept->head->next = req->item_dma;
|
||||
ept->head->info = 0;
|
||||
|
||||
/* during high throughput testing it is observed that
|
||||
* ept stat bit is not set even thoguh all the data
|
||||
* structures are updated properly and ept prime bit
|
||||
* is set. To workaround the issue, try to check if
|
||||
* ept stat bit otherwise try to re-prime the ept
|
||||
*/
|
||||
for (i = 0; i < 5; i++) {
|
||||
writel(n, USB_ENDPTPRIME);
|
||||
for (cnt = 0; cnt < 3000; cnt++) {
|
||||
if (!(readl(USB_ENDPTPRIME) & n) &&
|
||||
(readl(USB_ENDPTSTAT) & n))
|
||||
goto DONE;
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
/* start the endpoint */
|
||||
writel(1 << ept->bit, USB_ENDPTPRIME);
|
||||
|
||||
if (!(readl(USB_ENDPTSTAT) & n)) {
|
||||
pr_err("Unable to prime the ept%d%s\n",
|
||||
ept->num,
|
||||
ept->flags & EPT_FLAG_IN ? "in" : "out");
|
||||
return;
|
||||
}
|
||||
|
||||
DONE:
|
||||
/* mark this chain of requests as live */
|
||||
while (req) {
|
||||
req->live = 1;
|
||||
req = req->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req)
|
||||
@ -801,6 +757,7 @@ static void handle_setup(struct usb_info *ui)
|
||||
{
|
||||
u16 temp = 0;
|
||||
|
||||
temp = 1 << USB_DEVICE_SELF_POWERED;
|
||||
temp |= (ui->remote_wakeup <<
|
||||
USB_DEVICE_REMOTE_WAKEUP);
|
||||
memcpy(req->buf, &temp, 2);
|
||||
@ -855,10 +812,6 @@ static void handle_setup(struct usb_info *ui)
|
||||
case J_TEST:
|
||||
case K_TEST:
|
||||
case SE0_NAK_TEST:
|
||||
if (!ui->test_mode) {
|
||||
disable_charger = 1;
|
||||
queue_delayed_work(ui->usb_wq, &ui->chg_work, 0);
|
||||
}
|
||||
case TST_PKT_TEST:
|
||||
ui->test_mode = ctl.wIndex;
|
||||
goto ack;
|
||||
@ -1160,6 +1113,30 @@ static ssize_t show_usb_cable_connect(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(usb_cable_connect, 0444, show_usb_cable_connect, NULL);
|
||||
|
||||
static ssize_t show_usb_function_switch(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return android_show_function(buf);
|
||||
}
|
||||
|
||||
static ssize_t store_usb_function_switch(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned u;
|
||||
ssize_t ret;
|
||||
|
||||
u = simple_strtoul(buf, NULL, 10);
|
||||
ret = android_switch_function(u);
|
||||
|
||||
if (ret == 0)
|
||||
return count;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(usb_function_switch, 0666,
|
||||
show_usb_function_switch, store_usb_function_switch);
|
||||
|
||||
static ssize_t show_usb_serial_number(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -1270,27 +1247,6 @@ static ssize_t show_USB_ID_status(struct device *dev,
|
||||
static DEVICE_ATTR(USB_ID_status, 0444,
|
||||
show_USB_ID_status, NULL);
|
||||
|
||||
static ssize_t show_usb_car_kit_enable(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct usb_info *ui = the_usb_info;
|
||||
int value = 1;
|
||||
unsigned length;
|
||||
|
||||
if (!ui)
|
||||
return 0;
|
||||
if (ui->accessory_detect == 0) {
|
||||
value = 0;
|
||||
}
|
||||
printk(KERN_INFO "usb: USB_car_kit_enable %d\n", ui->accessory_detect);
|
||||
length = sprintf(buf, "%d", value);
|
||||
return length;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(usb_car_kit_enable, 0444,
|
||||
show_usb_car_kit_enable, NULL);/*for kar kit AP check if car kit enable*/
|
||||
|
||||
static ssize_t show_usb_phy_setting(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -1370,17 +1326,13 @@ static ssize_t store_mfg_carkit_enable(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(usb_mfg_carkit_enable, 0644,
|
||||
show_mfg_carkit_enable, store_mfg_carkit_enable);
|
||||
#endif
|
||||
|
||||
#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
|
||||
static ssize_t dock_status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_info *ui = the_usb_info;
|
||||
if (ui->accessory_type == 1)
|
||||
return sprintf(buf, "online\n");
|
||||
else if (ui->accessory_type == 3) /*desk dock*/
|
||||
return sprintf(buf, "online\n");
|
||||
else
|
||||
return sprintf(buf, "offline\n");
|
||||
}
|
||||
@ -1417,13 +1369,6 @@ static void usb_prepare(struct usb_info *ui)
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
|
||||
INIT_WORK(&ui->detect_work, accessory_detect_work);
|
||||
#endif
|
||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
|
||||
if (ui->dock_detect) {
|
||||
INIT_WORK(&ui->dock_work, dock_detect_work);
|
||||
dock_detect_init(ui);
|
||||
}
|
||||
#endif
|
||||
|
||||
INIT_WORK(&ui->notifier_work, send_usb_connect_notify);
|
||||
INIT_DELAYED_WORK(&ui->chg_work, check_charger);
|
||||
|
||||
@ -1432,6 +1377,11 @@ static void usb_prepare(struct usb_info *ui)
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_usb_cable_connect failed\n");
|
||||
|
||||
ret = device_create_file(&ui->pdev->dev,
|
||||
&dev_attr_usb_function_switch);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_usb_function_switch failed\n");
|
||||
|
||||
ret = device_create_file(&ui->pdev->dev,
|
||||
&dev_attr_usb_serial_number);
|
||||
if (ret != 0)
|
||||
@ -1458,11 +1408,6 @@ static void usb_prepare(struct usb_info *ui)
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n");
|
||||
#endif
|
||||
ret = device_create_file(&ui->pdev->dev,
|
||||
&dev_attr_usb_car_kit_enable);/*for kar kit AP check if car kit enable*/
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_usb_car_kit_enable failed\n");
|
||||
|
||||
}
|
||||
|
||||
static int usb_wakeup_phy(struct usb_info *ui)
|
||||
@ -1605,18 +1550,6 @@ static void usb_start(struct usb_info *ui)
|
||||
|
||||
spin_lock_irqsave(&ui->lock, flags);
|
||||
ui->flags |= USB_FLAG_START;
|
||||
/*if msm_hsusb_set_vbus_state set 1, but usb did not init, the ui =NULL, */
|
||||
/*it would cause reboot with usb, it did not swith to USB and ADB fail*/
|
||||
/*So when USB start, check again*/
|
||||
if (vbus) {
|
||||
ui->flags |= USB_FLAG_VBUS_ONLINE;
|
||||
} else {
|
||||
ui->flags |= USB_FLAG_VBUS_OFFLINE;
|
||||
}
|
||||
/* online->switch to USB, offline->switch to uart */
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(!vbus);
|
||||
|
||||
queue_work(ui->usb_wq, &ui->work);
|
||||
spin_unlock_irqrestore(&ui->lock, flags);
|
||||
}
|
||||
@ -1681,13 +1614,6 @@ static void usb_lpm_enter(struct usb_info *ui)
|
||||
clk_set_rate(ui->ebi1clk, 0);
|
||||
ui->in_lpm = 1;
|
||||
spin_unlock_irqrestore(&ui->lock, iflags);
|
||||
|
||||
if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/
|
||||
printk(KERN_INFO "usb: idle_wake_unlock and perf unlock\n");
|
||||
wake_unlock(&vbus_idle_wake_lock);
|
||||
if (is_perf_lock_active(&usb_perf_lock))
|
||||
perf_unlock(&usb_perf_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_lpm_exit(struct usb_info *ui)
|
||||
@ -1705,86 +1631,8 @@ static void usb_lpm_exit(struct usb_info *ui)
|
||||
clk_enable(ui->otgclk);
|
||||
usb_wakeup_phy(ui);
|
||||
ui->in_lpm = 0;
|
||||
|
||||
if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/
|
||||
printk(KERN_INFO "usb: idle_wake_lock and perf lock\n");
|
||||
wake_lock(&vbus_idle_wake_lock);
|
||||
if (!is_perf_lock_active(&usb_perf_lock))
|
||||
perf_lock(&usb_perf_lock);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
|
||||
static irqreturn_t dock_interrupt(int irq, void *data)
|
||||
{
|
||||
struct usb_info *ui = data;
|
||||
disable_irq_nosync(ui->dockpin_irq);
|
||||
queue_work(ui->usb_wq, &ui->dock_work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static void dock_detect_work(struct work_struct *w)
|
||||
{
|
||||
struct usb_info *ui = container_of(w, struct usb_info, dock_work);
|
||||
int value;
|
||||
|
||||
value = gpio_get_value(ui->dock_pin_gpio);
|
||||
|
||||
if (value == 0 && vbus) {
|
||||
set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH);
|
||||
switch_set_state(&dock_switch, DOCK_STATE_DESK);
|
||||
ui->accessory_type = 3;
|
||||
printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_DESK);
|
||||
} else {
|
||||
set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW);
|
||||
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
|
||||
ui->accessory_type = 0;
|
||||
printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_UNDOCKED);
|
||||
}
|
||||
enable_irq(ui->dockpin_irq);
|
||||
|
||||
|
||||
}
|
||||
static void dock_detect_init(struct usb_info *ui)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ui->dock_pin_gpio == 0)
|
||||
return;
|
||||
if (ui->dockpin_irq == 0)
|
||||
ui->dockpin_irq = gpio_to_irq(ui->dock_pin_gpio);
|
||||
|
||||
ret = request_irq(ui->dockpin_irq, dock_interrupt,
|
||||
IRQF_TRIGGER_LOW,
|
||||
"dock_irq", ui);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "%s: request_irq failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
printk(KERN_INFO "%s: dock irq %d\n", __func__,
|
||||
ui->dockpin_irq);
|
||||
ret = set_irq_wake(ui->dockpin_irq, 1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "%s: set_irq_wake failed\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (switch_dev_register(&dock_switch) < 0) {
|
||||
printk(KERN_ERR "usb: fail to register dock switch!\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = device_create_file(dock_switch.dev, &dev_attr_status);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_status failed\n");
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
free_irq(ui->dockpin_irq, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
|
||||
static void carkit_detect(struct usb_info *ui)
|
||||
{
|
||||
@ -1842,7 +1690,7 @@ static void accessory_detect_by_adc(struct usb_info *ui)
|
||||
if (adc_value >= 0x2112 && adc_value <= 0x3D53) {
|
||||
printk(KERN_INFO "usb: headset inserted\n");
|
||||
ui->accessory_type = 2;
|
||||
headset_ext_detect(USB_AUDIO_OUT);
|
||||
headset_ext_detect(USB_HEADSET);
|
||||
} else if (adc_value >= 0x88A && adc_value <= 0x1E38) {
|
||||
printk(KERN_INFO "usb: carkit inserted\n");
|
||||
ui->accessory_type = 1;
|
||||
@ -1856,7 +1704,7 @@ static void accessory_detect_by_adc(struct usb_info *ui)
|
||||
} else {
|
||||
if (ui->accessory_type == 2) {
|
||||
printk(KERN_INFO "usb: headset removed\n");
|
||||
headset_ext_detect(USB_NO_HEADSET);
|
||||
headset_ext_detect(NO_DEVICE);
|
||||
} else if (ui->accessory_type == 1) {
|
||||
printk(KERN_INFO "usb: carkit removed\n");
|
||||
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
|
||||
@ -1908,8 +1756,7 @@ static void accessory_detect_init(struct usb_info *ui)
|
||||
|
||||
if (ui->usb_id_pin_gpio == 0)
|
||||
return;
|
||||
if (ui->idpin_irq == 0)
|
||||
ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
|
||||
ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
|
||||
|
||||
ret = request_irq(ui->idpin_irq, usbid_interrupt,
|
||||
IRQF_TRIGGER_LOW,
|
||||
@ -1929,11 +1776,9 @@ static void accessory_detect_init(struct usb_info *ui)
|
||||
printk(KERN_ERR "usb: fail to register dock switch!\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = device_create_file(dock_switch.dev, &dev_attr_status);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "dev_attr_status failed\n");
|
||||
|
||||
return;
|
||||
err:
|
||||
free_irq(ui->idpin_irq, 0);
|
||||
@ -1942,44 +1787,6 @@ err:
|
||||
#endif
|
||||
|
||||
#define DELAY_FOR_CHECK_CHG msecs_to_jiffies(300)
|
||||
|
||||
static void charger_detect_by_uart(struct usb_info *ui)
|
||||
{
|
||||
int is_china_ac;
|
||||
|
||||
/*UART*/
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(1);
|
||||
|
||||
is_china_ac = ui->china_ac_detect();
|
||||
|
||||
if (is_china_ac) {
|
||||
ui->connect_type = CONNECT_TYPE_AC;
|
||||
queue_work(ui->usb_wq, &ui->notifier_work);
|
||||
usb_lpm_enter(ui);
|
||||
printk(KERN_INFO "usb: AC charger\n");
|
||||
} else {
|
||||
ui->connect_type = CONNECT_TYPE_UNKNOWN;
|
||||
queue_delayed_work(ui->usb_wq, &ui->chg_work,
|
||||
DELAY_FOR_CHECK_CHG);
|
||||
printk(KERN_INFO "usb: not AC charger\n");
|
||||
|
||||
/*set uart to gpo*/
|
||||
if (ui->serial_debug_gpios)
|
||||
ui->serial_debug_gpios(0);
|
||||
/*turn on USB HUB*/
|
||||
if (ui->usb_hub_enable)
|
||||
ui->usb_hub_enable(1);
|
||||
|
||||
/*USB*/
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(0);
|
||||
|
||||
usb_lpm_exit(ui);
|
||||
usb_reset(ui);
|
||||
}
|
||||
}
|
||||
|
||||
static void charger_detect(struct usb_info *ui)
|
||||
{
|
||||
if (!vbus)
|
||||
@ -2004,13 +1811,6 @@ static void charger_detect(struct usb_info *ui)
|
||||
static void check_charger(struct work_struct *w)
|
||||
{
|
||||
struct usb_info *ui = container_of(w, struct usb_info, chg_work.work);
|
||||
if (disable_charger) {
|
||||
printk(KERN_INFO "usb: disable charger\n");
|
||||
if (ui->disable_usb_charger)
|
||||
ui->disable_usb_charger();
|
||||
disable_charger = 0;
|
||||
return;
|
||||
}
|
||||
/* unknown charger */
|
||||
if (vbus && ui->connect_type == CONNECT_TYPE_UNKNOWN)
|
||||
queue_work(ui->usb_wq, &ui->notifier_work);
|
||||
@ -2022,7 +1822,6 @@ static void usb_do_work(struct work_struct *w)
|
||||
unsigned long iflags;
|
||||
unsigned flags, _vbus;
|
||||
|
||||
|
||||
for (;;) {
|
||||
spin_lock_irqsave(&ui->lock, iflags);
|
||||
flags = ui->flags;
|
||||
@ -2037,15 +1836,9 @@ static void usb_do_work(struct work_struct *w)
|
||||
case USB_STATE_IDLE:
|
||||
if (flags & USB_FLAG_START) {
|
||||
pr_info("hsusb: IDLE -> ONLINE\n");
|
||||
|
||||
if (ui->china_ac_detect)
|
||||
charger_detect_by_uart(ui);
|
||||
else {
|
||||
usb_lpm_exit(ui);
|
||||
usb_reset(ui);
|
||||
|
||||
charger_detect(ui);
|
||||
}
|
||||
usb_lpm_exit(ui);
|
||||
usb_reset(ui);
|
||||
charger_detect(ui);
|
||||
|
||||
ui->state = USB_STATE_ONLINE;
|
||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
|
||||
@ -2117,14 +1910,9 @@ static void usb_do_work(struct work_struct *w)
|
||||
*/
|
||||
if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
|
||||
pr_info("hsusb: OFFLINE -> ONLINE\n");
|
||||
|
||||
if (ui->china_ac_detect)
|
||||
charger_detect_by_uart(ui);
|
||||
else {
|
||||
usb_lpm_exit(ui);
|
||||
usb_reset(ui);
|
||||
charger_detect(ui);
|
||||
}
|
||||
usb_lpm_exit(ui);
|
||||
usb_reset(ui);
|
||||
charger_detect(ui);
|
||||
|
||||
ui->state = USB_STATE_ONLINE;
|
||||
usb_do_work_check_vbus(ui);
|
||||
@ -2154,33 +1942,9 @@ void msm_hsusb_set_vbus_state(int online)
|
||||
} else {
|
||||
ui->flags |= USB_FLAG_VBUS_OFFLINE;
|
||||
}
|
||||
|
||||
if (online) {
|
||||
/*USB*/
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(0);
|
||||
} else {
|
||||
/*turn off USB HUB*/
|
||||
if (ui->usb_hub_enable)
|
||||
ui->usb_hub_enable(0);
|
||||
|
||||
/*UART*/
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(1);
|
||||
/*configure uart pin to alternate function*/
|
||||
if (ui->serial_debug_gpios)
|
||||
ui->serial_debug_gpios(1);
|
||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
|
||||
if (ui->accessory_type == 3) {
|
||||
set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW);
|
||||
switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
|
||||
ui->accessory_type = 0;
|
||||
printk(KERN_INFO "usb:dock: vbus offline\n");
|
||||
enable_irq(ui->dockpin_irq);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* online->switch to USB, offline->switch to uart */
|
||||
if (ui->usb_uart_switch)
|
||||
ui->usb_uart_switch(!online);
|
||||
queue_work(ui->usb_wq, &ui->work);
|
||||
}
|
||||
}
|
||||
@ -2601,10 +2365,6 @@ static int msm72k_probe(struct platform_device *pdev)
|
||||
ui->phy_init_seq = pdata->phy_init_seq;
|
||||
ui->usb_connected = pdata->usb_connected;
|
||||
ui->usb_uart_switch = pdata->usb_uart_switch;
|
||||
ui->serial_debug_gpios = pdata->serial_debug_gpios;
|
||||
ui->usb_hub_enable = pdata->usb_hub_enable;
|
||||
ui->china_ac_detect = pdata->china_ac_detect;
|
||||
ui->disable_usb_charger = pdata->disable_usb_charger;
|
||||
|
||||
ui->accessory_detect = pdata->accessory_detect;
|
||||
printk(KERN_INFO "usb: accessory detect %d\n",
|
||||
@ -2612,15 +2372,6 @@ static int msm72k_probe(struct platform_device *pdev)
|
||||
ui->usb_id_pin_gpio = pdata->usb_id_pin_gpio;
|
||||
printk(KERN_INFO "usb: id_pin_gpio %d\n",
|
||||
pdata->usb_id_pin_gpio);
|
||||
|
||||
ui->dock_detect = pdata->dock_detect;
|
||||
printk(KERN_INFO "usb: dock detect %d\n",
|
||||
ui->dock_detect);
|
||||
ui->dock_pin_gpio = pdata->dock_pin_gpio;
|
||||
printk(KERN_INFO "usb: dock pin gpio %d\n",
|
||||
ui->dock_pin_gpio);
|
||||
|
||||
ui->idpin_irq = pdata->id_pin_irq;
|
||||
if (pdata->config_usb_id_gpios)
|
||||
ui->config_usb_id_gpios = pdata->config_usb_id_gpios;
|
||||
}
|
||||
@ -2706,11 +2457,9 @@ static int msm72k_probe(struct platform_device *pdev)
|
||||
|
||||
/* initialize mfg serial number */
|
||||
|
||||
if (board_mfg_mode() == 1) {
|
||||
if (board_mfg_mode() == 1)
|
||||
use_mfg_serialno = 1;
|
||||
wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "usb_idle_lock");
|
||||
perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb");
|
||||
} else
|
||||
else
|
||||
use_mfg_serialno = 0;
|
||||
strncpy(mfg_df_serialno, "000000000000", strlen("000000000000"));
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
@ -292,13 +291,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
||||
/* mandatory */
|
||||
case OID_GEN_VENDOR_DESCRIPTION:
|
||||
pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
|
||||
if ( rndis_per_dev_params [configNr].vendorDescr ) {
|
||||
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
|
||||
memcpy (outbuf,
|
||||
rndis_per_dev_params [configNr].vendorDescr, length);
|
||||
} else {
|
||||
outbuf[0] = 0;
|
||||
}
|
||||
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
|
||||
memcpy (outbuf,
|
||||
rndis_per_dev_params [configNr].vendorDescr, length);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
@ -1,784 +0,0 @@
|
||||
/*
|
||||
* storage_common.c -- Common definitions for mass storage functionality
|
||||
*
|
||||
* Copyright (C) 2003-2008 Alan Stern
|
||||
* Copyeight (C) 2009 Samsung Electronics
|
||||
* Author: Michal Nazarewicz (m.nazarewicz@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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file requires the following identifiers used in USB strings to
|
||||
* be defined (each of type pointer to char):
|
||||
* - fsg_string_manufacturer -- name of the manufacturer
|
||||
* - fsg_string_product -- name of the product
|
||||
* - fsg_string_serial -- product's serial
|
||||
* - fsg_string_config -- name of the configuration
|
||||
* - fsg_string_interface -- name of the interface
|
||||
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
|
||||
* macro is defined prior to including this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
|
||||
* fsg_hs_intr_in_desc objects as well as
|
||||
* FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
|
||||
* macros are not defined.
|
||||
*
|
||||
* When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
|
||||
* FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
|
||||
* defined (as well as corresponding entries in string tables are
|
||||
* missing) and FSG_STRING_INTERFACE has value of zero.
|
||||
*
|
||||
* When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
|
||||
* the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
|
||||
* characters rather then a pointer to void.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
/* Thanks to NetChip Technologies for donating this product ID.
|
||||
*
|
||||
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
|
||||
* Instead: allocate your own, using normal USB-IF procedures. */
|
||||
#define FSG_VENDOR_ID 0x0525 /* NetChip */
|
||||
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef DEBUG
|
||||
#undef VERBOSE_DEBUG
|
||||
#undef DUMP_MSGS
|
||||
#endif /* !DEBUG */
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define VLDBG LDBG
|
||||
#else
|
||||
#define VLDBG(lun, fmt, args...) do { } while (0)
|
||||
#endif /* VERBOSE_DEBUG */
|
||||
|
||||
#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
|
||||
#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
|
||||
#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
|
||||
#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
|
||||
|
||||
/* Keep those macros in sync with thos in
|
||||
* include/linux/ubs/composite.h or else GCC will complain. If they
|
||||
* are identical (the same names of arguments, white spaces in the
|
||||
* same places) GCC will allow redefinition otherwise (even if some
|
||||
* white space is removed or added) warning will be issued. No
|
||||
* checking if those symbols is defined is performed because warning
|
||||
* is desired when those macros were defined by someone else to mean
|
||||
* something else. */
|
||||
#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
|
||||
#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
|
||||
#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
|
||||
#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
|
||||
|
||||
|
||||
|
||||
#ifdef DUMP_MSGS
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { \
|
||||
if (length < 512) { \
|
||||
DBG(fsg, "%s, length %u:\n", label, length); \
|
||||
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
|
||||
16, 1, buf, length, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define dump_msg(fsg, /* const char * */ label, \
|
||||
/* const u8 * */ buf, /* unsigned */ length) do { } while (0)
|
||||
|
||||
# ifdef VERBOSE_DEBUG
|
||||
|
||||
# define dump_cdb(fsg) \
|
||||
print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
|
||||
16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
|
||||
|
||||
# else
|
||||
|
||||
# define dump_cdb(fsg) do { } while (0)
|
||||
|
||||
# endif /* VERBOSE_DEBUG */
|
||||
|
||||
#endif /* DUMP_MSGS */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* SCSI device types */
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_CDROM 0x05
|
||||
|
||||
/* USB protocol value = the transport method */
|
||||
#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
|
||||
#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
|
||||
#define USB_PR_BULK 0x50 /* Bulk-only */
|
||||
|
||||
/* USB subclass value = the protocol encapsulation */
|
||||
#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
|
||||
#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
|
||||
#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
|
||||
#define USB_SC_UFI 0x04 /* UFI (floppy) */
|
||||
#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
|
||||
#define USB_SC_SCSI 0x06 /* Transparent SCSI */
|
||||
|
||||
/* 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;
|
||||
u8 bValue;
|
||||
};
|
||||
|
||||
#define CBI_INTERRUPT_DATA_LEN 2
|
||||
|
||||
/* CBI Accept Device-Specific Command request */
|
||||
#define USB_CBI_ADSC_REQUEST 0x00
|
||||
|
||||
|
||||
/* Length of a SCSI Command Data Block */
|
||||
#define MAX_COMMAND_SIZE 16
|
||||
|
||||
/* SCSI commands that we recognize */
|
||||
#define SC_FORMAT_UNIT 0x04
|
||||
#define SC_INQUIRY 0x12
|
||||
#define SC_MODE_SELECT_6 0x15
|
||||
#define SC_MODE_SELECT_10 0x55
|
||||
#define SC_MODE_SENSE_6 0x1a
|
||||
#define SC_MODE_SENSE_10 0x5a
|
||||
#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SC_READ_6 0x08
|
||||
#define SC_READ_10 0x28
|
||||
#define SC_READ_12 0xa8
|
||||
#define SC_READ_CAPACITY 0x25
|
||||
#define SC_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SC_READ_HEADER 0x44
|
||||
#define SC_READ_TOC 0x43
|
||||
#define SC_RELEASE 0x17
|
||||
#define SC_REQUEST_SENSE 0x03
|
||||
#define SC_RESERVE 0x16
|
||||
#define SC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SC_START_STOP_UNIT 0x1b
|
||||
#define SC_SYNCHRONIZE_CACHE 0x35
|
||||
#define SC_TEST_UNIT_READY 0x00
|
||||
#define SC_VERIFY 0x2f
|
||||
#define SC_WRITE_6 0x0a
|
||||
#define SC_WRITE_10 0x2a
|
||||
#define SC_WRITE_12 0xaa
|
||||
|
||||
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
|
||||
#define SS_NO_SENSE 0
|
||||
#define SS_COMMUNICATION_FAILURE 0x040800
|
||||
#define SS_INVALID_COMMAND 0x052000
|
||||
#define SS_INVALID_FIELD_IN_CDB 0x052400
|
||||
#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
|
||||
#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
|
||||
#define SS_MEDIUM_NOT_PRESENT 0x023a00
|
||||
#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
|
||||
#define SS_NOT_READY_TO_READY_TRANSITION 0x062800
|
||||
#define SS_RESET_OCCURRED 0x062900
|
||||
#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
|
||||
#define SS_UNRECOVERED_READ_ERROR 0x031100
|
||||
#define SS_WRITE_ERROR 0x030c02
|
||||
#define SS_WRITE_PROTECTED 0x072700
|
||||
|
||||
#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
|
||||
#define ASC(x) ((u8) ((x) >> 8))
|
||||
#define ASCQ(x) ((u8) (x))
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct fsg_lun {
|
||||
struct file *filp;
|
||||
loff_t file_length;
|
||||
loff_t num_sectors;
|
||||
|
||||
unsigned int initially_ro:1;
|
||||
unsigned int ro:1;
|
||||
unsigned int removable:1;
|
||||
unsigned int cdrom:1;
|
||||
unsigned int prevent_medium_removal:1;
|
||||
unsigned int registered:1;
|
||||
unsigned int info_valid:1;
|
||||
|
||||
u32 sense_data;
|
||||
u32 sense_data_info;
|
||||
u32 unit_attention_data;
|
||||
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
|
||||
|
||||
static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fsg_lun, dev);
|
||||
}
|
||||
|
||||
|
||||
/* Big enough to hold our biggest descriptor */
|
||||
#define EP0_BUFSIZE 256
|
||||
#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
|
||||
|
||||
/* Number of buffers we will use. 2 is enough for double-buffering */
|
||||
#define FSG_NUM_BUFFERS 2
|
||||
|
||||
/* Default size of buffer length. */
|
||||
#define FSG_BUFLEN ((u32)16384)
|
||||
|
||||
/* Maximal number of LUNs supported in mass storage function */
|
||||
#define FSG_MAX_LUNS 8
|
||||
|
||||
enum fsg_buffer_state {
|
||||
BUF_STATE_EMPTY = 0,
|
||||
BUF_STATE_FULL,
|
||||
BUF_STATE_BUSY
|
||||
};
|
||||
|
||||
struct fsg_buffhd {
|
||||
#ifdef FSG_BUFFHD_STATIC_BUFFER
|
||||
char buf[FSG_BUFLEN];
|
||||
#else
|
||||
void *buf;
|
||||
#endif
|
||||
enum fsg_buffer_state state;
|
||||
struct fsg_buffhd *next;
|
||||
|
||||
/* The NetChip 2280 is faster, and handles some protocol faults
|
||||
* better, if we don't submit any short bulk-out read requests.
|
||||
* So we will record the intended request length here. */
|
||||
unsigned int bulk_out_intended_length;
|
||||
|
||||
struct usb_request *inreq;
|
||||
int inreq_busy;
|
||||
struct usb_request *outreq;
|
||||
int outreq_busy;
|
||||
};
|
||||
|
||||
enum fsg_state {
|
||||
/* This one isn't used anywhere */
|
||||
FSG_STATE_COMMAND_PHASE = -10,
|
||||
FSG_STATE_DATA_PHASE,
|
||||
FSG_STATE_STATUS_PHASE,
|
||||
|
||||
FSG_STATE_IDLE = 0,
|
||||
FSG_STATE_ABORT_BULK_OUT,
|
||||
FSG_STATE_RESET,
|
||||
FSG_STATE_INTERFACE_CHANGE,
|
||||
FSG_STATE_CONFIG_CHANGE,
|
||||
FSG_STATE_DISCONNECT,
|
||||
FSG_STATE_EXIT,
|
||||
FSG_STATE_TERMINATED
|
||||
};
|
||||
|
||||
enum data_direction {
|
||||
DATA_DIR_UNKNOWN = 0,
|
||||
DATA_DIR_FROM_HOST,
|
||||
DATA_DIR_TO_HOST,
|
||||
DATA_DIR_NONE
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static inline u32 get_unaligned_be24(u8 *buf)
|
||||
{
|
||||
return 0xffffff & (u32) get_unaligned_be32(buf - 1);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
enum {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
FSG_STRING_MANUFACTURER = 1,
|
||||
FSG_STRING_PRODUCT,
|
||||
FSG_STRING_SERIAL,
|
||||
FSG_STRING_CONFIG,
|
||||
#endif
|
||||
FSG_STRING_INTERFACE
|
||||
};
|
||||
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
static struct usb_otg_descriptor
|
||||
fsg_otg_desc = {
|
||||
.bLength = sizeof fsg_otg_desc,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
.bmAttributes = USB_OTG_SRP,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* There is only one interface. */
|
||||
|
||||
static struct usb_interface_descriptor
|
||||
fsg_intf_desc = {
|
||||
.bLength = sizeof fsg_intf_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
||||
.bNumEndpoints = 2, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
|
||||
.bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
|
||||
.iInterface = FSG_STRING_INTERFACE,
|
||||
};
|
||||
|
||||
/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
|
||||
* and interrupt-in. */
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
/* wMaxPacketSize set by autoconfiguration */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_fs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 32, /* frames -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_fs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* USB 2.0 devices need to expose both high speed and full speed
|
||||
* descriptors, unless they only run at full speed.
|
||||
*
|
||||
* That means alternate endpoint descriptors (bigger packets)
|
||||
* and a "device qualifier" ... plus more construction options
|
||||
* for the config descriptor.
|
||||
*/
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_bulk_out_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = cpu_to_le16(512),
|
||||
.bInterval = 1, /* NAK every 1 uframe */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
|
||||
static struct usb_endpoint_descriptor
|
||||
fsg_hs_intr_in_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(2),
|
||||
.bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
|
||||
};
|
||||
|
||||
#ifndef FSG_NO_OTG
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
|
||||
#else
|
||||
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static struct usb_descriptor_header *fsg_hs_function[] = {
|
||||
#ifndef FSG_NO_OTG
|
||||
(struct usb_descriptor_header *) &fsg_otg_desc,
|
||||
#endif
|
||||
(struct usb_descriptor_header *) &fsg_intf_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
|
||||
(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
|
||||
#ifndef FSG_NO_INTR_EP
|
||||
(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* Maxpacket and other transfer characteristics vary by speed. */
|
||||
static struct usb_endpoint_descriptor *
|
||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
|
||||
struct usb_endpoint_descriptor *hs)
|
||||
{
|
||||
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
|
||||
return hs;
|
||||
return fs;
|
||||
}
|
||||
|
||||
|
||||
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
|
||||
static struct usb_string fsg_strings[] = {
|
||||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
{FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
|
||||
{FSG_STRING_PRODUCT, fsg_string_product},
|
||||
{FSG_STRING_SERIAL, fsg_string_serial},
|
||||
{FSG_STRING_CONFIG, fsg_string_config},
|
||||
#endif
|
||||
{FSG_STRING_INTERFACE, fsg_string_interface},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings fsg_stringtab = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = fsg_strings,
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* If the next two routines are called while the gadget is registered,
|
||||
* the caller must own fsg->filesem for writing. */
|
||||
|
||||
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
{
|
||||
int ro;
|
||||
struct file *filp = NULL;
|
||||
int rc = -EINVAL;
|
||||
struct inode *inode = NULL;
|
||||
loff_t size;
|
||||
loff_t num_sectors;
|
||||
loff_t min_sectors;
|
||||
|
||||
/* R/W if we can, R/O if we must */
|
||||
ro = curlun->initially_ro;
|
||||
if (!ro) {
|
||||
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
|
||||
if (-EROFS == PTR_ERR(filp))
|
||||
ro = 1;
|
||||
}
|
||||
if (ro)
|
||||
filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
|
||||
if (IS_ERR(filp)) {
|
||||
LINFO(curlun, "unable to open backing file: %s\n", filename);
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
ro = 1;
|
||||
|
||||
if (filp->f_path.dentry)
|
||||
inode = filp->f_path.dentry->d_inode;
|
||||
if (inode && S_ISBLK(inode->i_mode)) {
|
||||
if (bdev_read_only(inode->i_bdev))
|
||||
ro = 1;
|
||||
} else if (!inode || !S_ISREG(inode->i_mode)) {
|
||||
LINFO(curlun, "invalid file type: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we can't read the file, it's no good.
|
||||
* If we can't write the file, use it read-only. */
|
||||
if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
|
||||
LINFO(curlun, "file not readable: %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
if (!(filp->f_op->write || filp->f_op->aio_write))
|
||||
ro = 1;
|
||||
|
||||
size = i_size_read(inode->i_mapping->host);
|
||||
if (size < 0) {
|
||||
LINFO(curlun, "unable to find file size: %s\n", filename);
|
||||
rc = (int) size;
|
||||
goto out;
|
||||
}
|
||||
num_sectors = size >> 9; /* File size in 512-byte blocks */
|
||||
min_sectors = 1;
|
||||
if (curlun->cdrom) {
|
||||
num_sectors &= ~3; /* Reduce to a multiple of 2048 */
|
||||
min_sectors = 300*4; /* Smallest track is 300 frames */
|
||||
if (num_sectors >= 256*60*75*4) {
|
||||
num_sectors = (256*60*75 - 1) * 4;
|
||||
LINFO(curlun, "file too big: %s\n", filename);
|
||||
LINFO(curlun, "using only first %d blocks\n",
|
||||
(int) num_sectors);
|
||||
}
|
||||
}
|
||||
if (num_sectors < min_sectors) {
|
||||
LINFO(curlun, "file too small: %s\n", filename);
|
||||
rc = -ETOOSMALL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
get_file(filp);
|
||||
curlun->ro = ro;
|
||||
curlun->filp = filp;
|
||||
curlun->file_length = size;
|
||||
curlun->num_sectors = num_sectors;
|
||||
LDBG(curlun, "open backing file: %s\n", filename);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
filp_close(filp, current->files);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void fsg_lun_close(struct fsg_lun *curlun)
|
||||
{
|
||||
if (curlun->filp) {
|
||||
LDBG(curlun, "close backing file\n");
|
||||
fput(curlun->filp);
|
||||
curlun->filp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Sync the file data, don't bother with the metadata.
|
||||
* This code was copied from fs/buffer.c:sys_fdatasync(). */
|
||||
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
|
||||
{
|
||||
struct file *filp = curlun->filp;
|
||||
|
||||
if (curlun->ro || !filp)
|
||||
return 0;
|
||||
return vfs_fsync(filp, filp->f_path.dentry, 1);
|
||||
}
|
||||
|
||||
static void store_cdrom_address(u8 *dest, int msf, u32 addr)
|
||||
{
|
||||
if (msf) {
|
||||
/* Convert to Minutes-Seconds-Frames */
|
||||
addr >>= 2; /* Convert to 2048-byte frames */
|
||||
addr += 2*75; /* Lead-in occupies 2 seconds */
|
||||
dest[3] = addr % 75; /* Frames */
|
||||
addr /= 75;
|
||||
dest[2] = addr % 60; /* Seconds */
|
||||
addr /= 60;
|
||||
dest[1] = addr; /* Minutes */
|
||||
dest[0] = 0; /* Reserved */
|
||||
} else {
|
||||
/* Absolute sector */
|
||||
put_unaligned_be32(addr, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
|
||||
? curlun->ro
|
||||
: curlun->initially_ro);
|
||||
}
|
||||
|
||||
static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
|
||||
p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
|
||||
if (IS_ERR(p))
|
||||
rc = PTR_ERR(p);
|
||||
else {
|
||||
rc = strlen(p);
|
||||
memmove(buf, p, rc);
|
||||
buf[rc] = '\n'; /* Add a newline */
|
||||
buf[++rc] = 0;
|
||||
}
|
||||
} else { /* No file, return 0 bytes */
|
||||
*buf = 0;
|
||||
rc = 0;
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t rc = count;
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (sscanf(buf, "%d", &i) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allow the write-enable status to change only while the backing file
|
||||
* is closed. */
|
||||
down_read(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "read-only status change prevented\n");
|
||||
rc = -EBUSY;
|
||||
} else {
|
||||
curlun->ro = !!i;
|
||||
curlun->initially_ro = !!i;
|
||||
LDBG(curlun, "read-only status set to %d\n", curlun->ro);
|
||||
}
|
||||
up_read(filesem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
|
||||
struct rw_semaphore *filesem = dev_get_drvdata(dev);
|
||||
int rc = 0;
|
||||
|
||||
|
||||
#ifndef CONFIG_USB_ANDROID_MASS_STORAGE
|
||||
/* disabled in android because we need to allow closing the backing file
|
||||
* if the media was removed
|
||||
*/
|
||||
if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
|
||||
LDBG(curlun, "eject attempt prevented\n");
|
||||
return -EBUSY; /* "Door is locked" */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remove a trailing newline */
|
||||
if (count > 0 && buf[count-1] == '\n')
|
||||
((char *) buf)[count-1] = 0; /* Ugh! */
|
||||
|
||||
/* Eject current medium */
|
||||
down_write(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
|
||||
/* Load new medium */
|
||||
if (count > 0 && buf[0]) {
|
||||
rc = fsg_lun_open(curlun, buf);
|
||||
if (rc == 0)
|
||||
curlun->unit_attention_data =
|
||||
SS_NOT_READY_TO_READY_TRANSITION;
|
||||
}
|
||||
up_write(filesem);
|
||||
return (rc < 0 ? rc : count);
|
||||
}
|
@ -93,6 +93,13 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
|
||||
if (!gadget_supports_altsettings(gadget))
|
||||
return false;
|
||||
|
||||
/* SA1100 can do ECM, *without* status endpoint ... but we'll
|
||||
* only use it in non-ECM mode for backwards compatibility
|
||||
* (and since we currently require a status endpoint)
|
||||
*/
|
||||
if (gadget_is_sa1100(gadget))
|
||||
return false;
|
||||
|
||||
/* Everything else is *presumably* fine ... but this is a bit
|
||||
* chancy, so be **CERTAIN** there are no hardware issues with
|
||||
* your controller. Add it above if it can't handle CDC.
|
||||
@ -105,7 +112,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
int eem_bind_config(struct usb_configuration *c);
|
||||
|
||||
#if defined(USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS)
|
||||
#if defined(CONFIG_USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS)
|
||||
|
||||
int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
|
||||
|
||||
|
@ -70,11 +70,6 @@
|
||||
#else
|
||||
# define SLAB_NOTRACK 0x00000000UL
|
||||
#endif
|
||||
#ifdef CONFIG_FAILSLAB
|
||||
# define SLAB_FAILSLAB 0x02000000UL /* Fault injection mark */
|
||||
#else
|
||||
# define SLAB_FAILSLAB 0x00000000UL
|
||||
#endif
|
||||
|
||||
/* The following flags affect the page allocator grouping pages by mobility */
|
||||
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
|
||||
@ -106,7 +101,6 @@ int kmem_cache_shrink(struct kmem_cache *);
|
||||
void kmem_cache_free(struct kmem_cache *, void *);
|
||||
unsigned int kmem_cache_size(struct kmem_cache *);
|
||||
const char *kmem_cache_name(struct kmem_cache *);
|
||||
int kern_ptr_validate(const void *ptr, unsigned long size);
|
||||
int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
|
||||
|
||||
/*
|
||||
|
@ -27,6 +27,11 @@ struct android_usb_function {
|
||||
};
|
||||
|
||||
struct android_usb_product {
|
||||
/* Vendor ID for this set of functions.
|
||||
* Default vendor_id in platform data will be used if this is zero.
|
||||
*/
|
||||
__u16 vendor_id;
|
||||
|
||||
/* Default product ID. */
|
||||
__u16 product_id;
|
||||
|
||||
@ -79,6 +84,9 @@ struct usb_mass_storage_platform_data {
|
||||
|
||||
/* number of LUNS */
|
||||
int nluns;
|
||||
|
||||
/* bitmap of lun to indicate cdrom disk*/
|
||||
int cdrom_lun;
|
||||
};
|
||||
|
||||
/* Platform data for USB ethernet driver. */
|
||||
@ -88,9 +96,13 @@ struct usb_ether_platform_data {
|
||||
const char *vendorDescr;
|
||||
};
|
||||
|
||||
extern void android_usb_set_connected(int on);
|
||||
|
||||
extern void android_register_function(struct android_usb_function *f);
|
||||
|
||||
extern void android_enable_function(struct usb_function *f, int enable);
|
||||
|
||||
extern int android_get_model_id(void);
|
||||
|
||||
|
||||
#endif /* __LINUX_USB_ANDROID_H */
|
||||
|
@ -36,10 +36,8 @@
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/switch.h>
|
||||
|
||||
|
||||
struct usb_composite_dev;
|
||||
struct usb_configuration;
|
||||
|
||||
/**
|
||||
@ -102,9 +100,7 @@ struct usb_function {
|
||||
struct usb_descriptor_header **hs_descriptors;
|
||||
|
||||
struct usb_configuration *config;
|
||||
|
||||
/* disabled is zero if the function is enabled */
|
||||
int disabled;
|
||||
int hidden;
|
||||
|
||||
/* REVISIT: bind() functions can be marked __init, which
|
||||
* makes trouble for section mismatch analysis. See if
|
||||
@ -132,7 +128,6 @@ struct usb_function {
|
||||
/* private: */
|
||||
/* internals */
|
||||
struct list_head list;
|
||||
DECLARE_BITMAP(endpoints, 32);
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
@ -143,9 +138,6 @@ int usb_function_activate(struct usb_function *);
|
||||
|
||||
int usb_interface_id(struct usb_configuration *, struct usb_function *);
|
||||
|
||||
void usb_function_set_enabled(struct usb_function *, int);
|
||||
void usb_composite_force_reset(struct usb_composite_dev *);
|
||||
|
||||
/**
|
||||
* ep_choose - select descriptor endpoint at current device speed
|
||||
* @g: gadget, connected and running at some speed
|
||||
@ -340,7 +332,6 @@ struct usb_composite_dev {
|
||||
|
||||
/* private: */
|
||||
/* internals */
|
||||
unsigned int suspended:1;
|
||||
struct usb_device_descriptor desc;
|
||||
struct list_head configs;
|
||||
struct usb_composite_driver *driver;
|
||||
@ -353,15 +344,6 @@ struct usb_composite_dev {
|
||||
|
||||
/* protects at least deactivation count */
|
||||
spinlock_t lock;
|
||||
|
||||
/* switch indicating connected/disconnected state */
|
||||
struct switch_dev sw_connected;
|
||||
/* switch indicating current configuration */
|
||||
struct switch_dev sw_config;
|
||||
/* current connected state for sw_connected */
|
||||
bool connected;
|
||||
|
||||
struct work_struct switch_work;
|
||||
};
|
||||
|
||||
extern int usb_string_id(struct usb_composite_dev *c);
|
||||
|
@ -15,8 +15,6 @@
|
||||
#ifndef __LINUX_USB_GADGET_H
|
||||
#define __LINUX_USB_GADGET_H
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct usb_ep;
|
||||
|
||||
/**
|
||||
@ -494,13 +492,9 @@ static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
|
||||
{ dev_set_drvdata(&gadget->dev, data); }
|
||||
static inline void *get_gadget_data(struct usb_gadget *gadget)
|
||||
{ return dev_get_drvdata(&gadget->dev); }
|
||||
static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct usb_gadget, dev);
|
||||
}
|
||||
|
||||
/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
|
||||
#define gadget_for_each_ep(tmp, gadget) \
|
||||
#define gadget_for_each_ep(tmp,gadget) \
|
||||
list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user