Revert "usb: gadget: Backport Android drivers from 2.6.35 for HD2 by tytung."

This reverts commit 70f8304d7ae4683734b435abeacaa069e33863c9.
This commit is contained in:
tytung 2012-01-13 02:00:30 +08:00
parent 52203a8404
commit 79b69f0bfb
18 changed files with 3359 additions and 4748 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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"));

View File

@ -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;

View File

@ -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);
}

View File

@ -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]);

View File

@ -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);
/*

View File

@ -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 */

View File

@ -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);

View File

@ -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)