diff options
author | codeworkx <codeworkx@cyanogenmod.com> | 2012-09-22 09:48:20 +0200 |
---|---|---|
committer | codeworkx <codeworkx@cyanogenmod.com> | 2012-09-22 14:02:16 +0200 |
commit | 2489007e7d740ccbc3e0a202914e243ad5178787 (patch) | |
tree | b8e6380ea7b1da63474ad68a5dba997e01146043 /drivers/usb/gadget/android.c | |
parent | 5f67568eb31e3a813c7c52461dcf66ade15fc2e7 (diff) | |
download | kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.zip kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.gz kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.bz2 |
merge opensource jb u5
Change-Id: I1aaec157aa196f3448eff8636134fce89a814cf2
Diffstat (limited to 'drivers/usb/gadget/android.c')
-rw-r--r-- | drivers/usb/gadget/android.c | 220 |
1 files changed, 190 insertions, 30 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 699cf29..c528f4b 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -45,6 +45,7 @@ #include "epautoconf.c" #include "composite.c" +#include "f_audio_source.c" #include "f_mass_storage.c" #include "u_serial.c" #ifdef CONFIG_USB_DUN_SUPPORT @@ -61,6 +62,7 @@ #define USB_ETH_RNDIS y #include "f_rndis.c" #include "rndis.c" +#include "f_diag.c" #include "f_dm.c" MODULE_AUTHOR("Mike Lockwood"); @@ -95,10 +97,11 @@ struct android_usb_function { int (*init)(struct android_usb_function *, struct usb_composite_dev *); /* Optional: cleanup during gadget unbind */ void (*cleanup)(struct android_usb_function *); - /* Optional: called when the function is added the list of enabled functions */ - void (*enable)(struct android_usb_function *); - /* Optional: called when it is removed */ - void (*disable)(struct android_usb_function *); + /* Optional: called when the function is added the list of + * enabled functions */ + void (*enable)(struct android_usb_function *); + /* Optional: called when it is removed */ + void (*disable)(struct android_usb_function *); int (*bind_config)(struct android_usb_function *, struct usb_configuration *); @@ -117,7 +120,7 @@ struct android_dev { struct device *dev; bool enabled; - int disable_depth; + int disable_depth; struct mutex mutex; bool connected; bool sw_connected; @@ -142,6 +145,7 @@ static char serial_string[256]; #ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE #include "u_ncm.c" +#include "u_composite_notifier.c" #endif #include "u_ether.c" @@ -207,6 +211,14 @@ static void android_work(struct work_struct *data) kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp); printk(KERN_DEBUG "usb: %s sent uevent %s\n", __func__, uevent_envp[0]); +#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE + if (uevent_envp != connected) + blocking_notifier_call_chain( + &usb_composite_notifier_list, + (unsigned long)dev->connected, + (void *)function_lists_string); +#endif + } else { printk(KERN_DEBUG "usb: %s did not send uevent (%d %d %p)\n", __func__, dev->connected, dev->sw_connected, cdev->config); @@ -217,8 +229,8 @@ static void android_enable(struct android_dev *dev) { struct usb_composite_dev *cdev = dev->cdev; - if (WARN_ON(!dev->disable_depth)) - return; + BUG_ON(!mutex_is_locked(&dev->mutex)); + BUG_ON(!dev->disable_depth); if (--dev->disable_depth == 0) { usb_add_config(cdev, &android_config_driver, @@ -231,6 +243,8 @@ static void android_disable(struct android_dev *dev) { struct usb_composite_dev *cdev = dev->cdev; + BUG_ON(!mutex_is_locked(&dev->mutex)); + if (dev->disable_depth++ == 0) { usb_gadget_disconnect(cdev->gadget); /* Cancel pending control requests */ @@ -249,9 +263,9 @@ struct adb_data { static int adb_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { - f->config = kzalloc(sizeof(struct adb_data), GFP_KERNEL); - if (!f->config) - return -ENOMEM; + f->config = kzalloc(sizeof(struct adb_data), GFP_KERNEL); + if (!f->config) + return -ENOMEM; return adb_setup(); } @@ -259,7 +273,7 @@ static int adb_function_init(struct android_usb_function *f, struct usb_composit static void adb_function_cleanup(struct android_usb_function *f) { adb_cleanup(); - kfree(f->config); + kfree(f->config); } static int adb_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) @@ -678,6 +692,7 @@ static int mass_storage_function_init(struct android_usb_function *f, int err; #ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE int i; + unsigned int cdfs = 0; #endif config = kzalloc(sizeof(struct mass_storage_function_config), GFP_KERNEL); @@ -685,26 +700,28 @@ static int mass_storage_function_init(struct android_usb_function *f, return -ENOMEM; #ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE - if (android_usb_pdata && android_usb_pdata->nluns != 0) { + if (android_usb_pdata && (android_usb_pdata->nluns != 0 + || android_usb_pdata->cdfs_support != 0)) { /* Some device use sd card or not. * If you want to modify nluns, * please change nluns of standard android USB platform data * Please do not modify nluns directly in this function. * Every model uses same android file. */ - printk(KERN_DEBUG "usb: %s pdata->nluns=%d\n", __func__, - android_usb_pdata->nluns); - config->fsg.nluns = android_usb_pdata->nluns; + printk(KERN_DEBUG "usb: %s pdata->nluns=%d, cdfs = %d\n", + __func__, android_usb_pdata->nluns, + android_usb_pdata->cdfs_support); + cdfs = android_usb_pdata->cdfs_support; + config->fsg.nluns = android_usb_pdata->nluns + cdfs; + for (i = 0; i < android_usb_pdata->nluns; i++) { -#if defined(CONFIG_MACH_M0_CTC) - /*FOR CTC PC-MODEM START*/ - if (2 == i) { - printk(KERN_DEBUG "%s Enable cdfs\n", __func__); - config->fsg.luns[i].ro = 1; - config->fsg.luns[i].cdrom = 1; - } - /*FOR CTC PC-MODEM END*/ -#endif + + config->fsg.luns[i].removable = 1; + config->fsg.luns[i].nofua = 1; + } + + if (cdfs) { + config->fsg.luns[i].cdrom = 1; config->fsg.luns[i].removable = 1; config->fsg.luns[i].nofua = 1; } @@ -732,6 +749,23 @@ static int mass_storage_function_init(struct android_usb_function *f, return err; } } + if (cdfs) { + char luns[4]; + err = snprintf(luns, 4, "lun"); + if (err == 0) { + printk(KERN_ERR "usb: %s cdfs snprintf error\n", + __func__); + kfree(config); + return err; + } + err = sysfs_create_link(&f->dev->kobj, + &common->luns[i].dev.kobj, + luns); + if (err) { + kfree(config); + return err; + } + } } else { #endif /* original mainline code */ @@ -906,6 +940,63 @@ static struct android_usb_function accessory_function = { .ctrlrequest = accessory_function_ctrlrequest, }; +/* DIAG : enabled DIAG clients- "diag[,diag_mdm]" */ +static char diag_clients[32]; +static ssize_t clients_store( + struct device *device, struct device_attribute *attr, + const char *buff, size_t size) +{ + strlcpy(diag_clients, buff, sizeof(diag_clients)); + + return size; +} + +static DEVICE_ATTR(clients, S_IWUSR, NULL, clients_store); +static struct device_attribute *diag_function_attributes[] = { + &dev_attr_clients, NULL }; + +static int diag_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) +{ + return diag_setup(); +} + +static void diag_function_cleanup(struct android_usb_function *f) +{ + diag_cleanup(); +} + +static int diag_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + char *name; + char buf[32], *b; + int once = 0, err = -1; + int (*notify)(uint32_t, const char *) = NULL; + + strlcpy(buf, diag_clients, sizeof(buf)); + b = strim(buf); + while (b) { + notify = NULL; + name = strsep(&b, ","); + + if (name) { + err = diag_function_add(c, name, notify); + if (err) + pr_err("%s : usb: diag: Cannot open channel '%s\r\n", + __func__, name); + } + } + return err; +} + +static struct android_usb_function diag_function = { + .name = "diag", + .init = diag_function_init, + .cleanup = diag_function_cleanup, + .bind_config = diag_function_bind_config, + .attributes = diag_function_attributes, +}; static int dm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) @@ -918,6 +1009,68 @@ static struct android_usb_function dm_function = { .bind_config = dm_function_bind_config, }; +static int audio_source_function_init(struct android_usb_function *f, + struct usb_composite_dev *cdev) +{ + struct audio_source_config *config; + + config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL); + if (!config) + return -ENOMEM; + config->card = -1; + config->device = -1; + f->config = config; + return 0; +} + +static void audio_source_function_cleanup(struct android_usb_function *f) +{ + kfree(f->config); +} + +static int audio_source_function_bind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + struct audio_source_config *config = f->config; + + return audio_source_bind_config(c, config); +} + +static void audio_source_function_unbind_config(struct android_usb_function *f, + struct usb_configuration *c) +{ + struct audio_source_config *config = f->config; + + config->card = -1; + config->device = -1; +} + +static ssize_t audio_source_pcm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct android_usb_function *f = dev_get_drvdata(dev); + struct audio_source_config *config = f->config; + + /* print PCM card and device numbers */ + return sprintf(buf, "%d %d\n", config->card, config->device); +} + +static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL); + +static struct device_attribute *audio_source_function_attributes[] = { + &dev_attr_pcm, + NULL +}; + +static struct android_usb_function audio_source_function = { + .name = "audio_source", + .init = audio_source_function_init, + .cleanup = audio_source_function_cleanup, + .bind_config = audio_source_function_bind_config, + .unbind_config = audio_source_function_unbind_config, + .attributes = audio_source_function_attributes, +}; + static struct android_usb_function *supported_functions[] = { &adb_function, &acm_function, @@ -929,7 +1082,9 @@ static struct android_usb_function *supported_functions[] = { #endif &mass_storage_function, &accessory_function, + &diag_function, &dm_function, + &audio_source_function, NULL }; @@ -1092,6 +1247,9 @@ functions_store(struct device *pdev, struct device_attribute *attr, printk(KERN_DEBUG "usb: %s buff=%s\n", __func__, buff); strncpy(buf, buff, sizeof(buf)); b = strim(buf); +#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE + strncpy(function_lists_string, b, sizeof(buf)); +#endif while (b) { name = strsep(&b, ","); @@ -1140,7 +1298,7 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, { struct android_dev *dev = dev_get_drvdata(pdev); struct usb_composite_dev *cdev = dev->cdev; - struct android_usb_function *f; + struct android_usb_function *f; int enabled = 0; mutex_lock(&dev->mutex); @@ -1273,10 +1431,7 @@ field ## _store(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t size) \ { \ if (size >= sizeof(buffer)) return -EINVAL; \ - if (sscanf(buf, "%s", buffer) == 1) { \ - return size; \ - } \ - return -1; \ + return strlcpy(buffer, buf, sizeof(buffer)); \ } \ static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); @@ -1480,6 +1635,11 @@ static void android_disconnect(struct usb_gadget *gadget) unsigned long flags; composite_disconnect(gadget); + /* accessory HID support can be active while the + accessory function is not actually enabled, + so we need to inform it when we are disconnected. + */ + acc_disconnect(); spin_lock_irqsave(&cdev->lock, flags); dev->connected = 0; @@ -1570,7 +1730,7 @@ static int __init init(void) if (!dev) return -ENOMEM; - dev->disable_depth = 1; + dev->disable_depth = 1; dev->functions = supported_functions; INIT_LIST_HEAD(&dev->enabled_functions); INIT_WORK(&dev->work, android_work); |