Skip to content

Commit

Permalink
usb gadget: fix adb root, use two luns
Browse files Browse the repository at this point in the history
When adb is enabled, only connect the gadget when adbd is ready. If adbd
dies or is restarted (e.g. "adb root"), the gadget is disconnected when
the adb device is close, and it is re-connected once adb re-open the
device.

- Add callbacks to adb, similar to FunctionFs callbacks, to notify the
  gadget when the daemon is ready or closed.
- Refcount calls to android_enable/android_disable to enable the gadget
  only once all the function daemons are ready.
- Add enable/disble to android_usb_function to notify the function when
  it is added/removed from the list of enabled functions.

Signed-off-by: Benoit Goby <benoit@android.com>

Conflicts:

	drivers/usb/gadget/android.c
  • Loading branch information
codeworkx authored and Gokhan Moral committed Sep 4, 2012
1 parent b0a3f7d commit 356b28a
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 34 deletions.
167 changes: 138 additions & 29 deletions drivers/usb/gadget/android.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ 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 *);

Expand All @@ -115,6 +119,7 @@ struct android_dev {
struct device *dev;

bool enabled;
int disable_depth;
struct mutex mutex;
bool connected;
bool sw_connected;
Expand Down Expand Up @@ -202,40 +207,130 @@ static void android_work(struct work_struct *data)

if (uevent_envp) {
kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
printk(KERN_DEBUG "usb: %s sent uevent %s\n",
__func__, uevent_envp[0]);
pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
} else {
printk(KERN_DEBUG "usb: %s did not send uevent (%d %d %p)\n",
__func__, dev->connected, dev->sw_connected, cdev->config);
pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
dev->connected, dev->sw_connected, cdev->config);
}
}

static void android_enable(struct android_dev *dev)
{
struct usb_composite_dev *cdev = dev->cdev;

if (WARN_ON(!dev->disable_depth))
return;

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;

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)
{
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 {
Expand Down Expand Up @@ -693,24 +788,33 @@ static int mass_storage_function_init(struct android_usb_function *f,
}
} else {
#endif
/* original mainline code */
printk(KERN_DEBUG "usb: %s pdata is not available. nluns=1\n",
__func__);
config->fsg.nluns = 1;
config->fsg.luns[0].removable = 1;

common = fsg_common_init(NULL, cdev, &config->fsg);
if (IS_ERR(common)) {
kfree(config);
return PTR_ERR(common);
}

err = sysfs_create_link(&f->dev->kobj,
&common->luns[0].dev.kobj,
"lun");
if (err) {
kfree(config);
return err;
// default number of luns
config->fsg.nluns = 2;
for (i = 0; i < config->fsg.nluns; i++) {
config->fsg.luns[i].removable = 1;
config->fsg.luns[i].nofua = 1;
}

common = fsg_common_init(NULL, cdev, &config->fsg);
if (IS_ERR(common)) {
kfree(config);
return PTR_ERR(common);
}

for (i = 0; i < config->fsg.nluns; i++) {
char luns[5];
err = snprintf(luns, 5, "lun%d", i);
if (err == 0) {
printk(KERN_ERR "usb: %s snprintf error\n", __func__);
return err;
}
err = sysfs_create_link(&f->dev->kobj,
&common->luns[i].dev.kobj,
luns);
if (err) {
kfree(config);
return err;
}
}
#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
}
Expand Down Expand Up @@ -1172,6 +1276,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);
Expand Down Expand Up @@ -1218,9 +1323,11 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
cdev->desc.bDeviceProtocol);
printk(KERN_DEBUG "usb: %s next cmd : usb_add_config\n",
__func__);
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) {
#ifdef CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE
Expand All @@ -1229,10 +1336,11 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
*/
cdev->mute_switch = true;
#endif
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;
mdelay(5);
} else if (!enabled) {
Expand Down Expand Up @@ -1598,6 +1706,7 @@ int late_init_android_gadget(int romtype)
if (!dev)
return -ENOMEM;

dev->disable_depth = 1;
if(!romtype) dev->functions = supported3sung_functions;
else dev->functions = supported_functions;
INIT_LIST_HEAD(&dev->enabled_functions);
Expand Down
13 changes: 8 additions & 5 deletions drivers/usb/gadget/f_adb.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ struct adb_dev {
int rx_done;
};

static void adb_ready_callback(void);
static void adb_closed_callback(void);

static struct usb_interface_descriptor adb_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
Expand Down Expand Up @@ -441,7 +444,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;

Expand All @@ -453,12 +456,15 @@ 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;
}
Expand All @@ -478,9 +484,6 @@ static struct miscdevice adb_device = {
.fops = &adb_fops,
};




static int
adb_function_bind(struct usb_configuration *c, struct usb_function *f)
{
Expand Down

0 comments on commit 356b28a

Please sign in to comment.