From: Ziggy471 Date: Wed, 15 Dec 2010 23:49:43 +0000 (-0500) Subject: Update Android USB Gadgets to latest from the Legend tree X-Git-Url: https://www.ziggy471.com/git/gitweb.cgi?p=ziggy471-frankenstein-kernel.git;a=commitdiff;h=2b9ca3f6bba8bef7133bfcfef1f1001d262d5ddc Update Android USB Gadgets to latest from the Legend tree --- --- a/arch/arm/mach-msm/include/mach/msm_hsusb.h +++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h @@ -47,6 +47,10 @@ 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; @@ -76,8 +80,11 @@ 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); --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -33,6 +33,8 @@ #include #include "gadget_chips.h" +#include +#include /* * Kbuild is not very cooperative with respect to linking separately @@ -52,6 +54,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; +static struct wake_lock usb_rndis_idle_wake_lock; +static struct perf_lock usb_rndis_perf_lock; enum { USB_FUNCTION_UMS = 0, @@ -63,8 +67,13 @@ enum { USB_FUNCTION_FSYNC, USB_FUNCTION_MTP, USB_FUNCTION_MODEM, + USB_FUNCTION_ECM, + USB_FUNCTION_ACM, }; +#define PID_RNDIS 0x0ffe +#define PID_ECM 0x0ff8 +#define PID_ACM 0x0ff4 #ifdef CONFIG_USB_ANDROID_MTP #define MS_VENDOR_CODE 0x0b #define FEATURE_DESC_SIZE 64 @@ -104,6 +113,7 @@ static struct ms_comp_feature_descriptor .bFirstInterfaceNumber2 = 1, .resv4 = 1, }; + #endif /* Default vendor and product IDs, overridden by platform data */ @@ -431,7 +441,9 @@ int android_switch_function(unsigned fun 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")) @@ -439,10 +451,22 @@ int android_switch_function(unsigned fun else if ((func & (1 << USB_FUNCTION_ADB)) && !strcmp(f->name, "adb")) f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_ECM)) && + !strcmp(f->name, "cdc_ethernet")) + f->hidden = 0; + else if ((func & (1 << USB_FUNCTION_ACM)) && + !strcmp(f->name, "acm")) + f->hidden = 0; else if ((func & (1 << USB_FUNCTION_RNDIS)) && - !strcmp(f->name, "ether")) + !strcmp(f->name, "ether")) { + if (f->hidden) { + printk("%s: rndis perf lock\n", __func__); + wake_lock(&usb_rndis_idle_wake_lock); + if (!is_perf_lock_active(&usb_rndis_perf_lock)) + perf_lock(&usb_rndis_perf_lock); + } f->hidden = 0; - else if ((func & (1 << USB_FUNCTION_DIAG)) && + } else if ((func & (1 << USB_FUNCTION_DIAG)) && !strcmp(f->name, "diag")) f->hidden = 0; else if ((func & (1 << USB_FUNCTION_MODEM)) && @@ -461,8 +485,15 @@ int android_switch_function(unsigned fun else if ((func & (1 << USB_FUNCTION_PROJECTOR)) && !strcmp(f->name, "projector")) f->hidden = 0; - else + else { + if (!strcmp(f->name, "ether") && !f->hidden) { + printk("%s: rndis perf unlock\n", __func__); + wake_unlock(&usb_rndis_idle_wake_lock); + if (is_perf_lock_active(&usb_rndis_perf_lock)) + perf_unlock(&usb_rndis_perf_lock); + } f->hidden = 1; + } } product_id = get_product_id(dev); device_desc.idProduct = __constant_cpu_to_le16(product_id); @@ -472,7 +503,7 @@ int android_switch_function(unsigned fun /* We need to specify the COMM class in the device descriptor * if we are using RNDIS. */ - if (func & (1 << USB_FUNCTION_RNDIS)) + if (product_id == PID_RNDIS || product_id == PID_ECM || product_id == PID_ACM) dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; else dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; @@ -491,7 +522,7 @@ int android_switch_function(unsigned fun return 0; } -void android_enable_function(struct usb_function *f, int enable, bool reset) +void android_enable_function(struct usb_function *f, int enable) { struct android_dev *dev = _android_dev; int disable = !enable; @@ -508,16 +539,17 @@ void android_enable_function(struct usb_ /* We need to specify the COMM class in the device descriptor * if we are using RNDIS. */ - if (!strcmp(f->name, "ether")) { - if (enable) - dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; - else - dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; - } + if (product_id == PID_RNDIS) + dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; + else + dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; #endif + if (product_id == PID_ECM || product_id == PID_ACM) + dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; + else + dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; #ifdef CONFIG_USB_GADGET_MSM_72K - if (reset) msm_hsusb_request_reset(); #else /* force reenumeration */ @@ -596,6 +628,9 @@ static int __init init(void) dev->product_id = PRODUCT_ID; _android_dev = dev; + wake_lock_init(&usb_rndis_idle_wake_lock, WAKE_LOCK_IDLE, "rndis_idle_lock"); + perf_lock_init(&usb_rndis_perf_lock, PERF_LOCK_HIGHEST, "rndis"); + return platform_driver_register(&android_platform_driver); } module_init(init); --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -2013,9 +2013,6 @@ static int __init usba_udc_probe(struct } else { disable_irq(gpio_to_irq(udc->vbus_pin)); } - } else { - /* gpio_request fail so use -EINVAL for gpio_is_valid */ - udc->vbus_pin = -EINVAL; } } --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -26,6 +26,7 @@ #include #include +#include /* @@ -88,7 +89,7 @@ static ssize_t enable_store( sscanf(buf, "%d", &value); if (driver->enable_function) - driver->enable_function(f, value, true); + driver->enable_function(f, value); else f->hidden = !value; @@ -276,6 +277,7 @@ static struct usb_function *get_function struct usb_configuration *config = cdev->config; enum usb_device_speed speed = cdev->gadget->speed; struct usb_function *f; + struct usb_descriptor_header **descriptors; struct usb_descriptor_header *descriptor; struct usb_interface_descriptor *intf_desc; int i; @@ -285,7 +287,7 @@ static struct usb_function *get_function return NULL; if (f->hidden) continue; - +#if 0 if (speed == USB_SPEED_HIGH) descriptor = *(f->hs_descriptors); else @@ -294,6 +296,19 @@ static struct usb_function *get_function if (intf_desc->bDescriptorType == USB_DT_INTERFACE && intf_desc->bInterfaceNumber == intf) return f; +#endif + if (speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + + while ((descriptor = *descriptors++) != NULL) { + intf_desc = (struct usb_interface_descriptor *)descriptor; + if (intf_desc->bDescriptorType == USB_DT_INTERFACE && + intf_desc->bInterfaceNumber == intf) { + return f; + } + } } return NULL; } @@ -309,6 +324,9 @@ static int config_buf(struct usb_configu int status; int interfaceCount = 0; u8 *dest; +#if (defined(CONFIG_USB_ANDROID_ECM) || defined(CONFIG_USB_ANDROID_ACM)) + int is_cdc = 0; +#endif /* write the config descriptor */ c = buf; @@ -351,10 +369,47 @@ static int config_buf(struct usb_configu while ((descriptor = *descriptors++) != NULL) { intf = (struct usb_interface_descriptor *)dest; if (intf->bDescriptorType == USB_DT_INTERFACE) { - intf->bInterfaceNumber = interfaceCount; - intf = (struct usb_interface_descriptor *)descriptor; - intf->bInterfaceNumber = interfaceCount++; +#if (defined(CONFIG_USB_ANDROID_ECM) || defined(CONFIG_USB_ANDROID_ACM)) + /* CDC ACM/ECM */ + if (intf->bInterfaceClass == USB_CLASS_COMM && + (intf->bInterfaceSubClass == USB_CDC_SUBCLASS_ETHERNET || + intf->bInterfaceSubClass == USB_CDC_SUBCLASS_ACM)) + is_cdc = 1; + else + is_cdc = 0; +#endif + /* don't increment bInterfaceNumber for alternate settings */ + if (intf->bAlternateSetting == 0) { + intf->bInterfaceNumber = interfaceCount; + intf = (struct usb_interface_descriptor *)descriptor; + intf->bInterfaceNumber = interfaceCount++; + } else { + intf->bInterfaceNumber = interfaceCount - 1; + intf = (struct usb_interface_descriptor *)descriptor; + intf->bInterfaceNumber = interfaceCount - 1; + } + + } +#if (defined(CONFIG_USB_ANDROID_ECM) || defined(CONFIG_USB_ANDROID_ACM)) + /* set interface number dynamically for CDC interface descriptor */ + else if (is_cdc && intf->bDescriptorType == USB_DT_CS_INTERFACE) { + __u8 subtype = *(dest+2); + if (subtype == USB_CDC_UNION_TYPE) { + struct usb_cdc_union_desc *desc; + desc = (struct usb_cdc_union_desc *)dest; + desc->bMasterInterface0 = interfaceCount - 1; + desc->bSlaveInterface0 = interfaceCount; + } else if (subtype == USB_CDC_CALL_MANAGEMENT_TYPE) { + struct usb_cdc_call_mgmt_descriptor *desc; + desc = (struct usb_cdc_call_mgmt_descriptor *)dest; + desc->bDataInterface = interfaceCount; + } + } else if (intf->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) { + struct usb_interface_assoc_descriptor *desc; + desc = (struct usb_interface_assoc_descriptor *)dest; + desc->bFirstInterface = interfaceCount; } +#endif dest += intf->bLength; } @@ -472,6 +527,7 @@ static int set_config(struct usb_composi int result = -EINVAL; unsigned power = gadget_is_otg(gadget) ? 8 : 100; int tmp; + int interfaceCount = 0; if (cdev->config) reset_config(cdev); @@ -508,15 +564,18 @@ static int set_config(struct usb_composi if (!f) break; + if (f->hidden) + continue; - result = f->set_alt(f, tmp, 0); + result = f->set_alt(f, interfaceCount, 0); if (result < 0) { DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", - tmp, f->name, f, result); + interfaceCount, f->name, f, result); reset_config(cdev); goto done; } + interfaceCount++; } /* when we return, be sure our power usage is valid */ @@ -714,6 +773,8 @@ static int get_string(struct usb_composi return len; } list_for_each_entry(f, &c->functions, list) { + if (f->hidden) + continue; if (!f->strings) continue; len = lookup_string(f->strings, buf, language, id); --- a/drivers/usb/gadget/diag.c +++ b/drivers/usb/gadget/diag.c @@ -29,6 +29,8 @@ #include +/*#define DIAG_DEBUG*/ + #define NO_HDLC 1 #define ROUTE_TO_USERSPACE 1 @@ -72,6 +74,9 @@ static void TRACE(const char *tag, const } #endif + + + #define HDLC_MAX 4096 #define SMD_MAX 8192 @@ -79,8 +84,8 @@ static void TRACE(const char *tag, const #define RX_REQ_BUF_SZ 8192 /* number of tx/rx requests to allocate */ -#define TX_REQ_NUM 4 -#define RX_REQ_NUM 4 +#define TX_REQ_NUM 32 +#define RX_REQ_NUM 32 struct diag_context { struct usb_function function; @@ -219,6 +224,7 @@ static inline struct diag_context *func_ return container_of(f, struct diag_context, function); } +static int msm_diag_probe(struct platform_device *pdev); static void smd_try_to_send(struct diag_context *ctxt); static void smd_diag_notify(void *priv, unsigned event); @@ -334,6 +340,10 @@ static long diag_ioctl(struct file *file unsigned char temp_id_table[ID_TABLE_SZ]; printk(KERN_INFO "diag:diag_ioctl() cmd=%d\n", cmd); +#ifdef DIAG_DEBUG + printk(KERN_INFO "%s:%s(parent:%s): tgid=%d\n", __func__, + current->comm, current->parent->comm, current->tgid); +#endif if (_IOC_TYPE(cmd) != USB_DIAG_IOC_MAGIC) return -ENOTTY; @@ -343,7 +353,7 @@ static long diag_ioctl(struct file *file 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, true); + 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) @@ -456,6 +466,7 @@ static ssize_t diag_write(struct file *f ((req = req_get(ctxt, &ctxt->tx_req_idle)) || !ctxt->online)); mutex_lock(&ctxt->user_lock); + if (ret < 0) { pr_err("%s: wait_event_interruptible error %d\n", __func__, ret); @@ -503,11 +514,14 @@ static int diag_open(struct inode *ip, s int rc = 0; mutex_lock(&ctxt->user_lock); + if (ctxt->opened) { pr_err("%s: already opened\n", __func__); rc = -EBUSY; goto done; } + + ctxt->user_read_len = 0; ctxt->user_readp = 0; if (!ctxt->user_read_buf) { @@ -605,6 +619,7 @@ static int diag2arm9_release(struct inod printk(KERN_INFO "%s\n", __func__); mutex_lock(&ctxt->diag2arm9_lock); ctxt->diag2arm9_opened = false; + ctxt->is2ARM11 = 0; wake_up(&ctxt->read_arm9_wq); mutex_lock(&ctxt->diag2arm9_read_lock); while ((req = req_get(ctxt, &ctxt->rx_arm9_idle))) @@ -909,6 +924,7 @@ again: ctxt->rx_count += r; if (!ctxt->online) { + /* printk("$$$ discard %d\n", r);*/ req_put(ctxt, &ctxt->tx_req_idle, req); goto again; } @@ -1161,7 +1177,6 @@ static void diag_function_disable(struct usb_ep_disable(ctxt->in); usb_ep_disable(ctxt->out); } - #if defined(CONFIG_MSM_N_WAY_SMD) static void diag_qdsp_send(struct diag_context *ctxt) { @@ -1208,31 +1223,33 @@ static void diag_qdsp_notify(void *priv, diag_qdsp_send(ctxt); } +static struct platform_driver msm_smd_qdsp_ch1_driver = { + .probe = msm_diag_probe, + .driver = { + .name = "DSP_DIAG", + .owner = THIS_MODULE, + }, +}; +#endif + static int msm_diag_probe(struct platform_device *pdev) { struct diag_context *ctxt = &_context; ctxt->pdev = pdev; printk(KERN_INFO "diag:msm_diag_probe(), pdev->id=0x%x\n", pdev->id); +#if defined(CONFIG_MSM_N_WAY_SMD) if (pdev->id == 1) smd_open("DSP_DIAG", &ctxt->chqdsp, ctxt, diag_qdsp_notify); +#endif 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, true); + android_enable_function(&_context.function, enabled); _context.function_enable = !!enabled; smd_diag_enable("diag_set_enabled", enabled); return 0; @@ -1278,7 +1295,12 @@ int diag_bind_config(struct usb_configur ctxt->function.set_alt = diag_function_set_alt; ctxt->function.disable = diag_function_disable; +/* Workaround: enable diag first */ +#ifdef CONFIG_MACH_MECHA + ctxt->function.hidden = 0; +#else ctxt->function.hidden = !_context.function_enable; +#endif if (!ctxt->function.hidden) smd_diag_enable("diag_bind_config", 1); --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -32,6 +32,7 @@ #include #include +#include #define BULK_BUFFER_SIZE 4096 @@ -40,6 +41,7 @@ #define RX_REQ_MAX 32 static const char shortname[] = "android_adb"; +static struct wake_lock adb_idle_wake_lock; struct adb_dev { struct usb_function function; @@ -449,6 +451,7 @@ static ssize_t adb_write(struct file *fp r = -EIO; break; } + wake_lock_timeout(&adb_idle_wake_lock, HZ / 2); buf += xfer; count -= xfer; @@ -510,7 +513,7 @@ static int adb_enable_open(struct inode } printk(KERN_INFO "enabling adb\n"); - android_enable_function(&_adb_dev->function, 1, true); + android_enable_function(&_adb_dev->function, 1); return 0; } @@ -518,7 +521,7 @@ static int adb_enable_open(struct inode static int adb_enable_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "disabling adb\n"); - android_enable_function(&_adb_dev->function, 0, true); + android_enable_function(&_adb_dev->function, 0); atomic_dec(&adb_enable_excl); return 0; } @@ -697,6 +700,10 @@ static int adb_bind_config(struct usb_co if (board_mfg_mode() != 2) dev->function.hidden = 1; +/* Workaround: enable adb first */ +#ifdef CONFIG_MACH_MECHA + dev->function.hidden = 0; +#endif /* _adb_dev must be set before calling usb_gadget_register_driver */ _adb_dev = dev; @@ -732,6 +739,7 @@ static struct android_usb_function adb_f static int __init init(void) { printk(KERN_INFO "f_adb init\n"); + wake_lock_init(&adb_idle_wake_lock, WAKE_LOCK_IDLE, "adb_idle_lock"); android_register_function(&adb_function); return 0; } --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -74,6 +74,7 @@ #include #include #include +#include #include "gadget_chips.h" @@ -201,6 +202,7 @@ struct bulk_cs_wrap { #define SC_WRITE_6 0x0a #define SC_WRITE_10 0x2a #define SC_WRITE_12 0xaa +#define SC_PASCAL_MODE 0xff /* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ #define SS_NO_SENSE 0 @@ -357,7 +359,6 @@ struct fsg_dev { u32 usb_amount_left; unsigned int nluns; - unsigned int board_nluns; struct lun *luns; struct lun *curlun; @@ -415,7 +416,8 @@ static void fsg_set_ums_state(int connec printk(KERN_INFO "%s: %d\n", __func__, connect_status); /* USB connected */ if (connect_status == 1) { - if (!the_fsg->ums_state) { + /* only need to change state when connect to USB host */ + if (!the_fsg->ums_state && usb_get_connect_type() == 1) { the_fsg->ums_state = 1; printk(KERN_INFO "ums: set state 1\n"); switch_set_state(&the_fsg->sdev, 1); @@ -1541,7 +1543,7 @@ static int do_start_stop(struct fsg_dev if (backing_file_is_open(curlun)) { close_backing_file(fsg, curlun); curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; - if (curlun->cdrom || board_mfg_mode() == 1) { + if (curlun->cdrom) { printk(KERN_INFO "ums: eject\n"); kobject_uevent_env(&fsg->sdev.dev->kobj, KOBJ_CHANGE, envp); @@ -2164,6 +2166,15 @@ static int do_scsi_command(struct fsg_de "RESERVE(6)")) == 0) reply = do_reserve(fsg, bh); break; +#ifdef CONFIG_USB_ANDROID_ACM + case SC_PASCAL_MODE: + printk(KERN_INFO "SC_PASCAL_MODE\n"); + if (!strncmp("RDEVCHG=PASCAL", (char *)&fsg->cmnd[1], 14)) { + printk(KERN_INFO "usb: switch to CDC ACM\n"); + android_switch_function(0x400); + } + break; +#endif /* Some mandatory commands that we recognize but don't implement. * They don't mean much in this setting. It's left as an exercise * for anyone interested to implement RESERVE and RELEASE in terms @@ -3081,38 +3092,10 @@ static void fsg_function_disable(struct raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); } -static ssize_t store_lun_num(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned nluns; - struct fsg_dev *fsg = the_fsg; - nluns = simple_strtoul(buf, NULL, 10); - if (nluns > 0 && nluns <= fsg->board_nluns && (nluns != fsg->nluns)) { - fsg->nluns = nluns; - android_usb_set_connected(0); - msleep(10); - android_usb_set_connected(1); - } - return count; -} - -static ssize_t show_lun_num(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned length; - struct fsg_dev *fsg = the_fsg; - length = sprintf(buf, "%d\n", fsg->nluns); - return length; -} - -static DEVICE_ATTR(lun_num, 0644, show_lun_num, store_lun_num); - - static int __init fsg_probe(struct platform_device *pdev) { struct usb_mass_storage_platform_data *pdata = pdev->dev.platform_data; struct fsg_dev *fsg = the_fsg; - int rc; fsg->pdev = pdev; printk(KERN_INFO "fsg_probe pdata: %p\n", pdata); @@ -3126,13 +3109,9 @@ static int __init fsg_probe(struct platf if (pdata->release) fsg->release = pdata->release; - fsg->nluns = fsg->board_nluns = pdata->nluns; + fsg->nluns = pdata->nluns; fsg->cdrom_lun = pdata->cdrom_lun; } - rc = device_create_file(&the_fsg->pdev->dev, - &dev_attr_lun_num); - if (rc != 0) - printk(KERN_WARNING "dev_attr_lun_num failed\n"); return 0; } --- a/drivers/usb/gadget/f_projector.c +++ b/drivers/usb/gadget/f_projector.c @@ -710,7 +710,7 @@ static ssize_t store_enable(struct devic { int _enabled = simple_strtol(buf, NULL, 0); printk(KERN_INFO "projector: %d\n", _enabled); - android_enable_function(&_projector_dev.function, _enabled, true); + android_enable_function(&_projector_dev.function, _enabled); _projector_dev.enabled = _enabled; return count; } --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -118,8 +118,17 @@ static unsigned int bitrate(struct usb_g #define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ #define STATUS_BYTECOUNT 8 /* 8 bytes data */ - /* interface descriptor: */ +static struct usb_interface_assoc_descriptor rndis_iad = { + .bLength = sizeof rndis_iad, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 0, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_COMM, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = 0, + .iFunction = 0, +}; static struct usb_interface_descriptor rndis_control_intf __initdata = { .bLength = sizeof rndis_control_intf, @@ -210,6 +219,7 @@ static struct usb_endpoint_descriptor fs }; static struct usb_descriptor_header *eth_fs_function[] __initdata = { + (struct usb_descriptor_header *) &rndis_iad, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -254,6 +264,7 @@ static struct usb_endpoint_descriptor hs }; static struct usb_descriptor_header *eth_hs_function[] __initdata = { + (struct usb_descriptor_header *) &rndis_iad, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -273,6 +284,7 @@ static struct usb_descriptor_header *eth static struct usb_string rndis_string_defs[] = { [0].s = "RNDIS Communications Control", [1].s = "RNDIS Ethernet Data", + [2].s = "RNDIS", { } /* end of list */ }; @@ -798,6 +810,13 @@ int __init rndis_bind_config(struct usb_ return status; rndis_string_defs[1].id = status; rndis_data_intf.iInterface = status; + + /* function label */ + status = usb_string_id(c->cdev); + if (status > 0) { + rndis_iad.iFunction = status; + rndis_string_defs[2].id = status; + } } /* allocate and initialize one new instance */ --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -16,8 +16,12 @@ #include "u_serial.h" #include "gadget_chips.h" +#include #include +static struct wake_lock vbus_idle_wake_lock; +static struct perf_lock usb_perf_lock; + #define CONFIG_MODEM_SUPPORT /* * This function packages a simple "generic serial" port with no real @@ -248,9 +252,6 @@ static struct usb_gadget_strings *serial &serial_string_table, NULL, }; - -static struct perf_lock usb_perf_lock; - #ifdef CONFIG_MODEM_SUPPORT static void gser_complete_set_line_coding(struct usb_ep *ep, struct usb_request *req) @@ -795,14 +796,17 @@ static int modem_set_enabled(const char if (!gser) return 0; if (enabled) { + wake_lock(&vbus_idle_wake_lock); if (!is_perf_lock_active(&usb_perf_lock)) perf_lock(&usb_perf_lock); - } else { + } + else { + wake_unlock(&vbus_idle_wake_lock); if (is_perf_lock_active(&usb_perf_lock)) perf_unlock(&usb_perf_lock); } gser->disabled = !enabled; - android_enable_function(modem_function, enabled, false); + android_enable_function(modem_function, enabled); return 0; } @@ -823,14 +827,14 @@ static int serial_set_enabled(const char if (!gser) return 0; gser->disabled = !enabled; - android_enable_function(serial_function, enabled, true); + 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'); + /*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); @@ -857,7 +861,9 @@ static struct android_usb_function andro static int __init init(void) { printk(KERN_INFO "serial init\n"); + wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "modem_idle_lock"); perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb"); + android_register_function(&android_serial_function); return 0; } --- a/drivers/usb/gadget/msm72k_udc.c +++ b/drivers/usb/gadget/msm72k_udc.c @@ -49,11 +49,7 @@ #ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC #include #endif -#include -#include - -static struct wake_lock vbus_idle_wake_lock; -static struct perf_lock usb_perf_lock; +#include static const char driver_name[] = "msm72k_udc"; @@ -85,11 +81,14 @@ 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; -#ifdef CONFIG_USB_ACCESSORY_DETECT +#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(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,6 +98,12 @@ static struct switch_dev dock_switch = { #define DOCK_STATE_CAR (1 << 1) #endif +#include +#include + +static struct wake_lock vbus_idle_wake_lock; +static struct perf_lock usb_perf_lock; + struct msm_request { struct usb_request req; @@ -148,6 +153,10 @@ static void check_charger(struct work_st #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); @@ -206,6 +215,10 @@ 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); @@ -214,6 +227,7 @@ 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; @@ -238,10 +252,13 @@ 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; @@ -332,7 +349,7 @@ static int ulpi_write(struct usb_info *u 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"); @@ -812,6 +829,10 @@ static void handle_setup(struct usb_info 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; @@ -1326,13 +1347,17 @@ static ssize_t store_mfg_carkit_enable(s 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"); } @@ -1369,6 +1394,13 @@ static void usb_prepare(struct usb_info #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); @@ -1408,6 +1440,7 @@ static void usb_prepare(struct usb_info if (ret != 0) printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n"); #endif + } static int usb_wakeup_phy(struct usb_info *ui) @@ -1550,6 +1583,18 @@ static void usb_start(struct usb_info *u 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); } @@ -1647,6 +1692,77 @@ static void usb_lpm_exit(struct usb_info } } +#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) { + 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) { @@ -1704,7 +1820,7 @@ static void accessory_detect_by_adc(stru if (adc_value >= 0x2112 && adc_value <= 0x3D53) { printk(KERN_INFO "usb: headset inserted\n"); ui->accessory_type = 2; - headset_ext_detect(USB_HEADSET); + headset_ext_detect(USB_AUDIO_OUT); } else if (adc_value >= 0x88A && adc_value <= 0x1E38) { printk(KERN_INFO "usb: carkit inserted\n"); ui->accessory_type = 1; @@ -1718,7 +1834,7 @@ static void accessory_detect_by_adc(stru } else { if (ui->accessory_type == 2) { printk(KERN_INFO "usb: headset removed\n"); - headset_ext_detect(NO_DEVICE); + headset_ext_detect(USB_NO_HEADSET); } else if (ui->accessory_type == 1) { printk(KERN_INFO "usb: carkit removed\n"); switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED); @@ -1770,7 +1886,8 @@ static void accessory_detect_init(struct if (ui->usb_id_pin_gpio == 0) return; - ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio); + if (ui->idpin_irq == 0) + ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio); ret = request_irq(ui->idpin_irq, usbid_interrupt, IRQF_TRIGGER_LOW, @@ -1790,9 +1907,11 @@ static void accessory_detect_init(struct 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); @@ -1825,6 +1944,13 @@ static void charger_detect(struct usb_in 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); @@ -1836,6 +1962,7 @@ static void usb_do_work(struct work_stru unsigned long iflags; unsigned flags, _vbus; + for (;;) { spin_lock_irqsave(&ui->lock, iflags); flags = ui->flags; @@ -1852,6 +1979,8 @@ static void usb_do_work(struct work_stru pr_info("hsusb: IDLE -> ONLINE\n"); usb_lpm_exit(ui); usb_reset(ui); + + if (!ui->china_ac_detect) charger_detect(ui); ui->state = USB_STATE_ONLINE; @@ -1926,6 +2055,8 @@ static void usb_do_work(struct work_stru pr_info("hsusb: OFFLINE -> ONLINE\n"); usb_lpm_exit(ui); usb_reset(ui); + + if (!ui->china_ac_detect) charger_detect(ui); ui->state = USB_STATE_ONLINE; @@ -1944,6 +2075,7 @@ void msm_hsusb_set_vbus_state(int online { unsigned long flags = 0; struct usb_info *ui = the_usb_info; + int is_china_ac; printk(KERN_INFO "%s: %d\n", __func__, online); if (ui) @@ -1956,9 +2088,49 @@ void msm_hsusb_set_vbus_state(int 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(!online); + + if (online) { + if (ui->china_ac_detect) { + 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); + } 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); + } + queue_work(ui->usb_wq, &ui->work); } } @@ -2379,6 +2551,10 @@ static int msm72k_probe(struct platform_ 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", @@ -2386,6 +2562,15 @@ static int msm72k_probe(struct platform_ 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; } @@ -2475,8 +2660,7 @@ static int msm72k_probe(struct platform_ 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")); --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -291,13 +291,9 @@ gen_ndis_query_resp (int configNr, u32 O /* 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; --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +//#define DEBUG /* #define VERBOSE_DEBUG */ #include @@ -54,6 +55,10 @@ #define UETH__VERSION "29-May-2008" +/***********************************************************************/ +#define LOG_TAG1 "[ETH] " + +/***********************************************************************/ struct eth_dev { /* lock is held while accessing port_usb * or updating its backlink port_usb->ioport @@ -94,7 +99,8 @@ struct eth_dev { #ifdef CONFIG_USB_GADGET_DUALSPEED -static unsigned qmult = 5; +//static unsigned qmult = 5; +static unsigned qmult = 12; module_param(qmult, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(qmult, "queue length multiplier at high speed"); @@ -241,7 +247,7 @@ rx_submit(struct eth_dev *dev, struct us skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); if (skb == NULL) { - DBG(dev, "no rx skb\n"); + DBG(dev, LOG_TAG1 "no rx skb\n"); goto enomem; } @@ -261,7 +267,7 @@ rx_submit(struct eth_dev *dev, struct us enomem: defer_kevent(dev, WORK_RX_MEMORY); if (retval) { - DBG(dev, "rx submit --> %d\n", retval); + DBG(dev, LOG_TAG1 "rx submit --> %d\n", retval); if (skb) dev_kfree_skb_any(skb); spin_lock_irqsave(&dev->req_lock, flags); @@ -308,7 +314,7 @@ static void rx_complete(struct usb_ep *e || skb2->len > ETH_FRAME_LEN) { dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; - DBG(dev, "rx length %d\n", skb2->len); + DBG(dev, LOG_TAG1 "rx length %d\n", skb2->len); dev_kfree_skb_any(skb2); goto next_frame; } @@ -320,6 +326,8 @@ static void rx_complete(struct usb_ep *e * use skb buffers. */ status = netif_rx(skb2); + if (status != NET_RX_SUCCESS) + DBG(dev, LOG_TAG1 "%s@%d status=%d", __func__, __LINE__, status); next_frame: skb2 = skb_dequeue(&dev->rx_frames); } @@ -328,12 +336,12 @@ next_frame: /* software-driven interface shutdown */ case -ECONNRESET: /* unlink */ case -ESHUTDOWN: /* disconnect etc */ - VDBG(dev, "rx shutdown, code %d\n", status); + VDBG(dev, LOG_TAG1 "rx shutdown, code %d\n", status); goto quiesce; /* for hardware automagic (such as pxa) */ case -ECONNABORTED: /* endpoint reset */ - DBG(dev, "rx %s reset\n", ep->name); + DBG(dev, LOG_TAG1 "rx %s reset\n", ep->name); defer_kevent(dev, WORK_RX_MEMORY); quiesce: dev_kfree_skb_any(skb); @@ -346,7 +354,7 @@ quiesce: default: dev->net->stats.rx_errors++; - DBG(dev, "rx status %d\n", status); + DBG(dev, LOG_TAG1 "rx status %d\n", status); break; } @@ -380,7 +388,10 @@ static int prealloc(struct list_head *li while (i--) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (!req) + { + printk(KERN_ERR "%s@%d: usb_ep_alloc_request fail: %d\n", __func__, __LINE__, i); return list_empty(list) ? -ENOMEM : 0; + } list_add(&req->list, list); } return 0; @@ -409,10 +420,16 @@ static int alloc_requests(struct eth_dev spin_lock(&dev->req_lock); status = prealloc(&dev->tx_reqs, link->in_ep, n); if (status < 0) + { + ERROR(dev, "fail to alloc in_ep\n"); goto fail; + } status = prealloc(&dev->rx_reqs, link->out_ep, n); if (status < 0) + { + ERROR(dev, "fail to alloc out_ep\n"); goto fail; + } goto done; fail: DBG(dev, "can't alloc requests\n"); @@ -545,6 +562,7 @@ static netdev_tx_t eth_start_xmit(struct * network stack decided to xmit but before we got the spinlock. */ if (list_empty(&dev->tx_reqs)) { + DBG(dev, LOG_TAG1 "%s@%d: tx_reqs empty, NETDEV_TX_BUSY\n", __func__, __LINE__); spin_unlock_irqrestore(&dev->req_lock, flags); return NETDEV_TX_BUSY; } @@ -554,7 +572,10 @@ static netdev_tx_t eth_start_xmit(struct /* temporarily stop TX queue when the freelist empties */ if (list_empty(&dev->tx_reqs)) + { + DBG(dev, LOG_TAG1 "%s@%d: tx_reqs empty, netif_stop_queue\n", __func__, __LINE__); netif_stop_queue(net); + } spin_unlock_irqrestore(&dev->req_lock, flags); /* no buffer copies needed, unless the network stack did it @@ -609,7 +630,10 @@ drop: dev->net->stats.tx_dropped++; spin_lock_irqsave(&dev->req_lock, flags); if (list_empty(&dev->tx_reqs)) + { + DBG(dev, LOG_TAG1 "%s@%d: tx_reqs empty, netif_start_queue\n", __func__, __LINE__); netif_start_queue(net); + } list_add(&req->list, &dev->tx_reqs); spin_unlock_irqrestore(&dev->req_lock, flags); } @@ -765,8 +789,11 @@ int __init gether_setup(struct usb_gadge struct net_device *net; int status; - if (the_dev) + if (the_dev) { + if (ethaddr) + memcpy(ethaddr, the_dev->host_mac, ETH_ALEN); return -EBUSY; + } net = alloc_etherdev(sizeof *dev); if (!net) @@ -889,7 +916,7 @@ struct net_device *gether_connect(struct if (result == 0) { dev->zlp = link->is_zlp_ok; - DBG(dev, "qlen %d\n", qlen(dev->gadget)); + DBG(dev, LOG_TAG1 "qlen %d\n", qlen(dev->gadget)); dev->header_len = link->header_len; dev->unwrap = link->unwrap; @@ -941,6 +968,7 @@ void gether_disconnect(struct gether *li struct eth_dev *dev = link->ioport; struct usb_request *req; + /* WARN_ON(!dev); */ if (!dev) return; --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -28,7 +28,6 @@ #include "u_serial.h" - /* * This component encapsulates the TTY layer glue needed to provide basic * "serial port" functionality through the USB gadget stack. Each such @@ -77,9 +76,12 @@ * next layer of buffering. For TX that's a circular buffer; for RX * consider it a NOP. A third layer is provided by the TTY code. */ -#define QUEUE_SIZE 16 +#define QUEUE_SIZE 32 +#define RX_QUEUE_SIZE 96 #define WRITE_BUF_SIZE 8192 /* TX only */ +bool MODEM_DEBUG_ON; + static struct workqueue_struct *gs_tty_wq; /* circular buffer */ @@ -496,7 +498,9 @@ static void gs_rx_push(struct work_struc /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); + tty = port->port_tty; + while (!list_empty(queue)) { struct usb_request *req; @@ -506,26 +510,6 @@ static void gs_rx_push(struct work_struc if (!tty) goto recycle; - /* leave data queued if tty was rx throttled */ - if (test_bit(TTY_THROTTLED, &tty->flags)) - break; - - switch (req->status) { - case -ESHUTDOWN: - disconnect = true; - pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); - break; - - default: - /* presumably a transient fault */ - pr_warning(PREFIX "%d: unexpected RX status %d\n", - port->port_num, req->status); - /* FALLTHROUGH */ - case 0: - /* normal completion */ - break; - } - /* push data to (open) tty */ if (req->actual) { char *packet = req->buf; @@ -539,18 +523,23 @@ static void gs_rx_push(struct work_struc packet += n; size -= n; } - pr_vdebug(PREFIX "%d: tty_insert %d\n", port->port_num, - size); + + if (MODEM_DEBUG_ON) + printk("%d: tty_insert %d\n", port->port_num, size); + count = tty_insert_flip_string(tty, packet, size); if (count) do_push = true; if (count != size) { /* stop pushing; TTY layer can't handle more */ port->n_read += count; - pr_vdebug(PREFIX "%d: rx block %d/%d\n", - port->port_num, - count, req->actual); - break; + if (MODEM_DEBUG_ON) { + printk("%d: rx block %d/%d\n", + port->port_num, + count, req->actual); + list_move(&req->list, &port->read_pool); + break; + } } port->n_read = 0; } @@ -561,7 +550,7 @@ recycle: /* Push from tty to ldisc; this is immediate with low_latency, and * may trigger callbacks to this driver ... so drop the spinlock. */ - if (tty && do_push) { + if ((tty && do_push)) { spin_unlock_irq(&port->port_lock); tty_flip_buffer_push(tty); wake_up_interruptible(&tty->read_wait); @@ -599,22 +588,61 @@ recycle: static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) { - struct gs_port *port = ep->driver_data; - unsigned long flags; - pr_vdebug("%s: %d bytes\n", __func__, req->actual); + /* used global variable */ + struct gs_port *port = ep->driver_data; + struct tty_struct *tty; - /* Queue all received data until the tty layer is ready for it. */ - spin_lock_irqsave(&port->port_lock, flags); - list_add_tail(&req->list, &port->read_queue); - queue_work(gs_tty_wq, &port->push_work); - spin_unlock_irqrestore(&port->port_lock, flags); + tty = port->port_tty; + if (tty == NULL) { + printk(KERN_ERR "port_tty NULL\n"); + return; + } + + if (MODEM_DEBUG_ON) + printk("%s: %d bytes\n", __func__, req->actual); + + switch (req->status) { + case 0: + spin_lock(&port->port_lock); + if (!test_bit(TTY_THROTTLED, &tty->flags)) { + list_add_tail(&req->list, &port->read_queue); + queue_work(gs_tty_wq, &port->push_work); + } else { + printk("%s: TTY_THROTTLED\n", __func__); + list_add_tail(&req->list, &port->read_queue); + } + spin_unlock(&port->port_lock); + break; + case -ESHUTDOWN: + /* disconnect */ + printk("%s: ESHUTDOWN\n", __func__); + break; + case -ENODEV: + spin_lock(&port->port_lock); + printk("%s: ENODEV\n", __func__); + list_add_tail(&req->list, &port->read_pool); + /* Implemented handling in future if needed */ + spin_unlock(&port->port_lock); + break; + default: + spin_lock(&port->port_lock); + list_add_tail(&req->list, &port->read_pool); + printk(KERN_ERR + "gs_read_complete: unexpected status error, status=%d\n", + req->status); + spin_unlock(&port->port_lock); + /* goto requeue; */ + break; + } } static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) { struct gs_port *port = ep->driver_data; unsigned long flags; - pr_vdebug("%s: %d bytes\n", __func__, req->actual); + + if (MODEM_DEBUG_ON) + printk("%s: %d bytes\n", __func__, req->actual); spin_lock_irqsave(&port->port_lock, flags); list_add(&req->list, &port->write_pool); @@ -652,7 +680,7 @@ static void gs_free_requests(struct usb_ } static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, - void (*fn)(struct usb_ep *, struct usb_request *)) + void (*fn)(struct usb_ep *, struct usb_request *), int size) { int i; struct usb_request *req; @@ -661,7 +689,7 @@ static int gs_alloc_requests(struct usb_ * do quite that many this time, don't fail ... we just won't * be as speedy as we might otherwise be. */ - for (i = 0; i < QUEUE_SIZE; i++) { + for (i = 0; i < size; i++) { req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC); if (!req) return list_empty(head) ? -ENOMEM : 0; @@ -693,12 +721,12 @@ static int gs_start_io(struct gs_port *p * configurations may use different endpoints with a given port; * and high speed vs full speed changes packet sizes too. */ - status = gs_alloc_requests(ep, head, gs_read_complete); + status = gs_alloc_requests(ep, head, gs_read_complete, RX_QUEUE_SIZE); if (status) return status; status = gs_alloc_requests(port->port_usb->in, &port->write_pool, - gs_write_complete); + gs_write_complete, QUEUE_SIZE); if (status) { gs_free_requests(ep, head); return status; @@ -1007,7 +1035,8 @@ static void gs_unthrottle(struct tty_str * read queue backs up enough we'll be NAKing OUT packets. */ queue_work(gs_tty_wq, &port->push_work); - pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); + if (MODEM_DEBUG_ON) + printk("%d: unthrottle\n", port->port_num); } spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1174,6 +1203,9 @@ int gserial_setup(struct usb_gadget *g, if (count == 0 || count > N_PORTS) return -EINVAL; + if (gs_tty_driver) + return -EBUSY; + gs_tty_wq = create_singlethread_workqueue("gs_tty"); if (gs_tty_wq == 0) return -ENOMEM; @@ -1418,9 +1450,9 @@ void gserial_disconnect(struct gserial * /* REVISIT as above: how best to track this? */ port->port_line_coding = gser->port_line_coding; -#if 0 port->port_usb = NULL; gser->ioport = NULL; +#if 0 if (port->open_count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); if (port->port_tty) @@ -1447,3 +1479,14 @@ void gserial_disconnect(struct gserial * gs_free_requests(gser->in, &port->write_pool); spin_unlock_irqrestore(&port->port_lock, flags); } + +static int modem_debug_enabled(const char *val, struct kernel_param *kp) +{ + int enabled = simple_strtol(val, NULL, 0); + + MODEM_DEBUG_ON = (enabled) ? true : false; + return 0; +} + +module_param_call(modem_debug, modem_debug_enabled, NULL, NULL, 0664); + --- a/include/linux/usb/android_composite.h +++ b/include/linux/usb/android_composite.h @@ -89,9 +89,10 @@ extern void android_usb_set_connected(in extern void android_register_function(struct android_usb_function *f); -extern void android_enable_function(struct usb_function *f, int enable, bool reset); +extern void android_enable_function(struct usb_function *f, int enable); extern int android_get_model_id(void); +extern int android_switch_function(unsigned func); #endif /* __LINUX_USB_ANDROID_H */ --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -284,8 +284,7 @@ struct usb_composite_driver { void (*suspend)(struct usb_composite_dev *); void (*resume)(struct usb_composite_dev *); - void (*enable_function)(struct usb_function *f, int enable, bool reset); - + void (*enable_function)(struct usb_function *f, int enable); }; extern int usb_composite_register(struct usb_composite_driver *); --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -19,8 +19,4 @@ /* device can't handle its Configuration or Interface strings */ #define USB_QUIRK_CONFIG_INTF_STRINGS 0x00000008 -/* device needs a pause during initialization, after we read the device - descriptor */ -#define USB_QUIRK_DELAY_INIT 0x00000040 - #endif /* __LINUX_USB_QUIRKS_H */