aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorBenoit Goby <benoit@android.com>2012-03-23 12:52:10 -0700
committerBenoit Goby <benoit@android.com>2012-03-23 12:52:10 -0700
commit25aa939c33749752b811d0c631789e4e3cf4371f (patch)
treed7716aa2f8bbab2d6bc6a0747554c5e5e757f421 /drivers/usb/gadget
parentb43c0161fbca901e586e9ade321a5d8e616f94b9 (diff)
parentd993be54c164ea473816f04745ae4f0504dbccfb (diff)
downloadkernel_samsung_aries-25aa939c33749752b811d0c631789e4e3cf4371f.zip
kernel_samsung_aries-25aa939c33749752b811d0c631789e4e3cf4371f.tar.gz
kernel_samsung_aries-25aa939c33749752b811d0c631789e4e3cf4371f.tar.bz2
Merge branch 'android-3.0' into android-samsung-3.0-wip
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/android.c118
-rw-r--r--drivers/usb/gadget/f_adb.c11
2 files changed, 120 insertions, 9 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 8df739c..1d661ad 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -82,6 +82,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 *);
int (*bind_config)(struct android_usb_function *, struct usb_configuration *);
@@ -100,6 +105,7 @@ struct android_dev {
struct device *dev;
bool enabled;
+ int disable_depth;
struct mutex mutex;
bool connected;
bool sw_connected;
@@ -182,18 +188,55 @@ static void android_work(struct work_struct *data)
}
}
+static void android_enable(struct android_dev *dev)
+{
+ struct usb_composite_dev *cdev = dev->cdev;
+
+ BUG_ON(!mutex_is_locked(&dev->mutex));
+ BUG_ON(!dev->disable_depth);
+
+ if (--dev->disable_depth == 0) {
+ usb_add_config(cdev, &android_config_driver,
+ android_bind_config);
+ usb_gadget_connect(cdev->gadget);
+ }
+}
+
+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 */
+ usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
+ usb_remove_config(cdev, &android_config_driver);
+ }
+}
/*-------------------------------------------------------------------------*/
/* Supported functions initialization */
+struct adb_data {
+ bool opened;
+ bool enabled;
+};
+
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;
+
return adb_setup();
}
static void adb_function_cleanup(struct android_usb_function *f)
{
adb_cleanup();
+ kfree(f->config);
}
static int adb_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
@@ -201,13 +244,69 @@ static int adb_function_bind_config(struct android_usb_function *f, struct usb_c
return adb_bind_config(c);
}
+static void adb_android_function_enable(struct android_usb_function *f)
+{
+ struct android_dev *dev = _android_dev;
+ struct adb_data *data = f->config;
+
+ data->enabled = true;
+
+ /* Disable the gadget until adbd is ready */
+ if (!data->opened)
+ android_disable(dev);
+}
+
+static void adb_android_function_disable(struct android_usb_function *f)
+{
+ struct android_dev *dev = _android_dev;
+ struct adb_data *data = f->config;
+
+ data->enabled = false;
+
+ /* Balance the disable that was called in closed_callback */
+ if (!data->opened)
+ android_enable(dev);
+}
+
static struct android_usb_function adb_function = {
.name = "adb",
+ .enable = adb_android_function_enable,
+ .disable = adb_android_function_disable,
.init = adb_function_init,
.cleanup = adb_function_cleanup,
.bind_config = adb_function_bind_config,
};
+static void adb_ready_callback(void)
+{
+ struct android_dev *dev = _android_dev;
+ struct adb_data *data = adb_function.config;
+
+ mutex_lock(&dev->mutex);
+
+ data->opened = true;
+
+ if (data->enabled)
+ android_enable(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static void adb_closed_callback(void)
+{
+ struct android_dev *dev = _android_dev;
+ struct adb_data *data = adb_function.config;
+
+ mutex_lock(&dev->mutex);
+
+ data->opened = false;
+
+ if (data->enabled)
+ android_disable(dev);
+
+ mutex_unlock(&dev->mutex);
+}
+
#define MAX_ACM_INSTANCES 4
struct acm_function_config {
@@ -832,6 +931,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;
int enabled = 0;
mutex_lock(&dev->mutex);
@@ -845,15 +945,18 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
cdev->desc.bDeviceClass = device_desc.bDeviceClass;
cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
- usb_add_config(cdev, &android_config_driver,
- android_bind_config);
- usb_gadget_connect(cdev->gadget);
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ if (f->enable)
+ f->enable(f);
+ }
+ android_enable(dev);
dev->enabled = true;
} else if (!enabled && dev->enabled) {
- usb_gadget_disconnect(cdev->gadget);
- /* Cancel pending control requests */
- usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
- usb_remove_config(cdev, &android_config_driver);
+ android_disable(dev);
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ if (f->disable)
+ f->disable(f);
+ }
dev->enabled = false;
} else {
pr_err("android_usb: already %s\n",
@@ -1148,6 +1251,7 @@ static int __init init(void)
if (!dev)
return -ENOMEM;
+ dev->disable_depth = 1;
dev->functions = supported_functions;
INIT_LIST_HEAD(&dev->enabled_functions);
INIT_WORK(&dev->work, android_work);
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index fe4455e..1c0166c 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -111,6 +111,8 @@ static struct usb_descriptor_header *hs_adb_descs[] = {
NULL,
};
+static void adb_ready_callback(void);
+static void adb_closed_callback(void);
/* temporary variable used between adb_open() and adb_gadget_bind() */
static struct adb_dev *_adb_dev;
@@ -406,7 +408,7 @@ static ssize_t adb_write(struct file *fp, const char __user *buf,
static int adb_open(struct inode *ip, struct file *fp)
{
- printk(KERN_INFO "adb_open\n");
+ pr_info("adb_open\n");
if (!_adb_dev)
return -ENODEV;
@@ -418,12 +420,17 @@ static int adb_open(struct inode *ip, struct file *fp)
/* clear the error latch */
_adb_dev->error = 0;
+ adb_ready_callback();
+
return 0;
}
static int adb_release(struct inode *ip, struct file *fp)
{
- printk(KERN_INFO "adb_release\n");
+ pr_info("adb_release\n");
+
+ adb_closed_callback();
+
adb_unlock(&_adb_dev->open_excl);
return 0;
}