usb: gadget: android: Update android gadget driver
* Functions and the device descriptor are configured from user space:
echo 0 > /sys/class/android_usb/android0/enable
echo adb,acm > /sys/class/android_usb/android0/functions
echo 2 > /sys/class/android_usb/android0/f_acm/instances
echo 1 > /sys/class/android_usb/android0/enable
* Driver does not require platform data anymore
* Moved function initialization to android.c instead of each
function file
* Replaced switches by uevents
Signed-off-by: Benoit Goby <benoit@android.com>
Signed-off-by: Mike Lockwood <lockwood@android.com>
Change-Id: If5ad9267c111ad0a442f0d87a0d31082dc5381b6
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 92dd89b..c892ec8 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -34,10 +34,9 @@
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/usb/ch9.h>
-#include <linux/usb/android_composite.h>
#include <linux/usb/f_mtp.h>
-#define BULK_BUFFER_SIZE 16384
+#define MTP_BULK_BUFFER_SIZE 16384
#define INTR_BUFFER_SIZE 28
/* String IDs */
@@ -67,7 +66,7 @@
#define MTP_RESPONSE_OK 0x2001
#define MTP_RESPONSE_DEVICE_BUSY 0x2019
-static const char shortname[] = "mtp_usb";
+static const char mtp_shortname[] = "mtp_usb";
struct mtp_dev {
struct usb_function function;
@@ -273,7 +272,7 @@
/* temporary variable used between mtp_open() and mtp_gadget_bind() */
static struct mtp_dev *_mtp_dev;
-static inline struct mtp_dev *func_to_dev(struct usb_function *f)
+static inline struct mtp_dev *func_to_mtp(struct usb_function *f)
{
return container_of(f, struct mtp_dev, function);
}
@@ -302,7 +301,7 @@
}
}
-static inline int _lock(atomic_t *excl)
+static inline int mtp_lock(atomic_t *excl)
{
if (atomic_inc_return(excl) == 1) {
return 0;
@@ -312,13 +311,13 @@
}
}
-static inline void _unlock(atomic_t *excl)
+static inline void mtp_unlock(atomic_t *excl)
{
atomic_dec(excl);
}
/* add a request to the tail of a list */
-static void req_put(struct mtp_dev *dev, struct list_head *head,
+static void mtp_req_put(struct mtp_dev *dev, struct list_head *head,
struct usb_request *req)
{
unsigned long flags;
@@ -329,7 +328,8 @@
}
/* remove a request from the head of a list */
-static struct usb_request *req_get(struct mtp_dev *dev, struct list_head *head)
+static struct usb_request
+*mtp_req_get(struct mtp_dev *dev, struct list_head *head)
{
unsigned long flags;
struct usb_request *req;
@@ -352,7 +352,7 @@
if (req->status != 0)
dev->state = STATE_ERROR;
- req_put(dev, &dev->tx_idle, req);
+ mtp_req_put(dev, &dev->tx_idle, req);
wake_up(&dev->write_wq);
}
@@ -379,7 +379,7 @@
dev->state = STATE_ERROR;
}
-static int __init create_bulk_endpoints(struct mtp_dev *dev,
+static int mtp_create_bulk_endpoints(struct mtp_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc,
struct usb_endpoint_descriptor *intr_desc)
@@ -429,14 +429,14 @@
/* now allocate requests for our endpoints */
for (i = 0; i < TX_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_in, BULK_BUFFER_SIZE);
+ req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE);
if (!req)
goto fail;
req->complete = mtp_complete_in;
- req_put(dev, &dev->tx_idle, req);
+ mtp_req_put(dev, &dev->tx_idle, req);
}
for (i = 0; i < RX_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_out, BULK_BUFFER_SIZE);
+ req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE);
if (!req)
goto fail;
req->complete = mtp_complete_out;
@@ -466,7 +466,7 @@
DBG(cdev, "mtp_read(%d)\n", count);
- if (count > BULK_BUFFER_SIZE)
+ if (count > MTP_BULK_BUFFER_SIZE)
return -EINVAL;
/* we will block until we're online */
@@ -579,15 +579,15 @@
/* get an idle tx request to use */
req = 0;
ret = wait_event_interruptible(dev->write_wq,
- ((req = req_get(dev, &dev->tx_idle))
+ ((req = mtp_req_get(dev, &dev->tx_idle))
|| dev->state != STATE_BUSY));
if (!req) {
r = ret;
break;
}
- if (count > BULK_BUFFER_SIZE)
- xfer = BULK_BUFFER_SIZE;
+ if (count > MTP_BULK_BUFFER_SIZE)
+ xfer = MTP_BULK_BUFFER_SIZE;
else
xfer = count;
if (xfer && copy_from_user(req->buf, buf, xfer)) {
@@ -611,7 +611,7 @@
}
if (req)
- req_put(dev, &dev->tx_idle, req);
+ mtp_req_put(dev, &dev->tx_idle, req);
spin_lock_irq(&dev->lock);
if (dev->state == STATE_CANCELED)
@@ -659,7 +659,7 @@
/* get an idle tx request to use */
req = 0;
ret = wait_event_interruptible(dev->write_wq,
- (req = req_get(dev, &dev->tx_idle))
+ (req = mtp_req_get(dev, &dev->tx_idle))
|| dev->state != STATE_BUSY);
if (dev->state == STATE_CANCELED) {
r = -ECANCELED;
@@ -670,8 +670,8 @@
break;
}
- if (count > BULK_BUFFER_SIZE)
- xfer = BULK_BUFFER_SIZE;
+ if (count > MTP_BULK_BUFFER_SIZE)
+ xfer = MTP_BULK_BUFFER_SIZE;
else
xfer = count;
ret = vfs_read(filp, req->buf, xfer, &offset);
@@ -697,7 +697,7 @@
}
if (req)
- req_put(dev, &dev->tx_idle, req);
+ mtp_req_put(dev, &dev->tx_idle, req);
DBG(cdev, "send_file_work returning %d\n", r);
/* write the result */
@@ -731,8 +731,8 @@
read_req = dev->rx_req[cur_buf];
cur_buf = (cur_buf + 1) % RX_REQ_MAX;
- read_req->length = (count > BULK_BUFFER_SIZE
- ? BULK_BUFFER_SIZE : count);
+ read_req->length = (count > MTP_BULK_BUFFER_SIZE
+ ? MTP_BULK_BUFFER_SIZE : count);
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
if (ret < 0) {
@@ -824,7 +824,7 @@
struct file *filp = NULL;
int ret = -EINVAL;
- if (_lock(&dev->ioctl_excl))
+ if (mtp_lock(&dev->ioctl_excl))
return -EBUSY;
switch (code) {
@@ -922,7 +922,7 @@
dev->state = STATE_READY;
spin_unlock_irq(&dev->lock);
out:
- _unlock(&dev->ioctl_excl);
+ mtp_unlock(&dev->ioctl_excl);
DBG(dev->cdev, "ioctl returning %d\n", ret);
return ret;
}
@@ -930,7 +930,7 @@
static int mtp_open(struct inode *ip, struct file *fp)
{
printk(KERN_INFO "mtp_open\n");
- if (_lock(&_mtp_dev->open_excl))
+ if (mtp_lock(&_mtp_dev->open_excl))
return -EBUSY;
/* clear any error condition */
@@ -945,7 +945,7 @@
{
printk(KERN_INFO "mtp_release\n");
- _unlock(&_mtp_dev->open_excl);
+ mtp_unlock(&_mtp_dev->open_excl);
return 0;
}
@@ -961,15 +961,52 @@
static struct miscdevice mtp_device = {
.minor = MISC_DYNAMIC_MINOR,
- .name = shortname,
+ .name = mtp_shortname,
.fops = &mtp_fops,
};
+static int mtp_ctrlrequest(struct usb_composite_dev *cdev,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct mtp_dev *dev = _mtp_dev;
+ 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);
+
+ VDBG(cdev, "mtp_ctrlrequest "
+ "%02x.%02x v%04x i%04x l%u\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+
+ /* Handle MTP OS string */
+ if (dev->interface_mode == MTP_INTERFACE_MODE_MTP
+ && ctrl->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
+ && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
+ && (w_value >> 8) == USB_DT_STRING
+ && (w_value & 0xFF) == MTP_OS_STRING_ID) {
+ value = (w_length < sizeof(mtp_os_string)
+ ? w_length : sizeof(mtp_os_string));
+ memcpy(cdev->req->buf, mtp_os_string, value);
+ }
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ int rc;
+ cdev->req->zero = value < w_length;
+ cdev->req->length = value;
+ rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+ if (rc < 0)
+ ERROR(cdev, "%s setup response queue error\n", __func__);
+ }
+ return value;
+}
+
static int
mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
- struct mtp_dev *dev = func_to_dev(f);
+ struct mtp_dev *dev = func_to_mtp(f);
int id;
int ret;
@@ -983,7 +1020,7 @@
mtp_interface_desc.bInterfaceNumber = id;
/* allocate endpoints */
- ret = create_bulk_endpoints(dev, &mtp_fullspeed_in_desc,
+ ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc,
&mtp_fullspeed_out_desc, &mtp_intr_desc);
if (ret)
return ret;
@@ -1005,28 +1042,22 @@
static void
mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
{
- struct mtp_dev *dev = func_to_dev(f);
+ struct mtp_dev *dev = func_to_mtp(f);
struct usb_request *req;
int i;
- spin_lock_irq(&dev->lock);
- while ((req = req_get(dev, &dev->tx_idle)))
+ while ((req = mtp_req_get(dev, &dev->tx_idle)))
mtp_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
mtp_request_free(dev->rx_req[i], dev->ep_out);
mtp_request_free(dev->intr_req, dev->ep_intr);
dev->state = STATE_OFFLINE;
- spin_unlock_irq(&dev->lock);
-
- misc_deregister(&mtp_device);
- kfree(_mtp_dev);
- _mtp_dev = NULL;
}
static int mtp_function_setup(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
- struct mtp_dev *dev = func_to_dev(f);
+ struct mtp_dev *dev = func_to_mtp(f);
struct usb_composite_dev *cdev = dev->cdev;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@@ -1034,28 +1065,11 @@
u16 w_length = le16_to_cpu(ctrl->wLength);
unsigned long flags;
- /* do nothing if we are disabled */
- if (dev->function.disabled)
- return value;
-
VDBG(cdev, "mtp_function_setup "
"%02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
- /* Handle MTP OS string */
- if (dev->interface_mode == MTP_INTERFACE_MODE_MTP
- && ctrl->bRequestType ==
- (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)
- && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR
- && (w_value >> 8) == USB_DT_STRING
- && (w_value & 0xFF) == MTP_OS_STRING_ID) {
- value = (w_length < sizeof(mtp_os_string)
- ? w_length : sizeof(mtp_os_string));
- memcpy(cdev->req->buf, mtp_os_string, value);
- /* return here since composite.c will send for us */
- return value;
- }
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
/* Handle MTP OS descriptor */
DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n",
@@ -1135,7 +1149,7 @@
static int mtp_function_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
- struct mtp_dev *dev = func_to_dev(f);
+ struct mtp_dev *dev = func_to_mtp(f);
struct usb_composite_dev *cdev = f->config->cdev;
int ret;
@@ -1169,7 +1183,7 @@
static void mtp_function_disable(struct usb_function *f)
{
- struct mtp_dev *dev = func_to_dev(f);
+ struct mtp_dev *dev = func_to_mtp(f);
struct usb_composite_dev *cdev = dev->cdev;
DBG(cdev, "mtp_function_disable\n");
@@ -1186,15 +1200,11 @@
static int mtp_bind_config(struct usb_configuration *c)
{
- struct mtp_dev *dev;
+ struct mtp_dev *dev = _mtp_dev;
int ret = 0;
printk(KERN_INFO "mtp_bind_config\n");
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
/* allocate a string ID for our interface */
if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) {
ret = usb_string_id(c->cdev);
@@ -1204,19 +1214,6 @@
mtp_interface_desc.iInterface = ret;
}
- spin_lock_init(&dev->lock);
- init_waitqueue_head(&dev->read_wq);
- init_waitqueue_head(&dev->write_wq);
- atomic_set(&dev->open_excl, 0);
- atomic_set(&dev->ioctl_excl, 0);
- INIT_LIST_HEAD(&dev->tx_idle);
-
- dev->wq = create_singlethread_workqueue("f_mtp");
- if (!dev->wq)
- goto err1;
- INIT_WORK(&dev->send_file_work, send_file_work);
- INIT_WORK(&dev->receive_file_work, receive_file_work);
-
dev->cdev = c->cdev;
dev->function.name = "mtp";
dev->function.strings = mtp_strings,
@@ -1231,38 +1228,59 @@
/* MTP mode by default */
dev->interface_mode = MTP_INTERFACE_MODE_MTP;
- /* _mtp_dev must be set before calling usb_gadget_register_driver */
+ return usb_add_function(c, &dev->function);
+}
+
+static int mtp_setup(void)
+{
+ struct mtp_dev *dev;
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ spin_lock_init(&dev->lock);
+ init_waitqueue_head(&dev->read_wq);
+ init_waitqueue_head(&dev->write_wq);
+ atomic_set(&dev->open_excl, 0);
+ atomic_set(&dev->ioctl_excl, 0);
+ INIT_LIST_HEAD(&dev->tx_idle);
+
+ dev->wq = create_singlethread_workqueue("f_mtp");
+ if (!dev->wq) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+ INIT_WORK(&dev->send_file_work, send_file_work);
+ INIT_WORK(&dev->receive_file_work, receive_file_work);
+
_mtp_dev = dev;
ret = misc_register(&mtp_device);
if (ret)
- goto err1;
-
- ret = usb_add_function(c, &dev->function);
- if (ret)
goto err2;
return 0;
err2:
- misc_deregister(&mtp_device);
+ destroy_workqueue(dev->wq);
err1:
- if (dev->wq)
- destroy_workqueue(dev->wq);
+ _mtp_dev = NULL;
kfree(dev);
printk(KERN_ERR "mtp gadget driver failed to initialize\n");
return ret;
}
-static struct android_usb_function mtp_function = {
- .name = "mtp",
- .bind_config = mtp_bind_config,
-};
-
-static int __init init(void)
+static void mtp_cleanup(void)
{
- printk(KERN_INFO "f_mtp init\n");
- android_register_function(&mtp_function);
- return 0;
+ struct mtp_dev *dev = _mtp_dev;
+
+ if (!dev)
+ return;
+
+ misc_deregister(&mtp_device);
+ destroy_workqueue(dev->wq);
+ _mtp_dev = NULL;
+ kfree(dev);
}
-module_init(init);