OSDN Git Service

usb: gadget: Multiple ACM gadget instances
authorJohn Michelau <john.michelau@motorola.com>
Tue, 9 Nov 2010 00:05:37 +0000 (18:05 -0600)
committerBrian Swetland <swetland@google.com>
Tue, 29 Mar 2011 20:57:46 +0000 (13:57 -0700)
- Added multiple ACM instance support in Android gadget
- Fixed multiple instance naming issue in ACM function
- Increased max instances from 4 to 8

Change-Id: I65f1b0be94da859bab7ec0ad7cd804b896c7c4c5
Signed-off-by: John Michelau <john.michelau@motorola.com>
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/u_serial.c
include/linux/usb/android_composite.h

index ddbb988..cf2e7fc 100644 (file)
@@ -698,6 +698,7 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
                usb_free_descriptors(f->hs_descriptors);
        usb_free_descriptors(f->descriptors);
        gs_free_req(acm->notify, acm->notify_req);
+       kfree(acm->port.func.name);
        kfree(acm);
 }
 
@@ -769,7 +770,11 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num)
        acm->port.disconnect = acm_disconnect;
        acm->port.send_break = acm_send_break;
 
-       acm->port.func.name = "acm";
+       acm->port.func.name = kasprintf(GFP_KERNEL, "acm%u", port_num);
+       if (!acm->port.func.name) {
+               kfree(acm);
+               return -ENOMEM;
+       }
        acm->port.func.strings = acm_strings;
        /* descriptors are per-instance copies */
        acm->port.func.bind = acm_bind;
@@ -785,12 +790,38 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num)
 }
 
 #ifdef CONFIG_USB_ANDROID_ACM
+#include <linux/platform_device.h>
+
+static struct acm_platform_data *acm_pdata;
+
+static int acm_probe(struct platform_device *pdev)
+{
+       acm_pdata = pdev->dev.platform_data;
+       return 0;
+}
+
+static struct platform_driver acm_platform_driver = {
+       .driver = { .name = "acm", },
+       .probe = acm_probe,
+};
 
 int acm_function_bind_config(struct usb_configuration *c)
 {
-       int ret = acm_bind_config(c, 0);
-       if (ret == 0)
-               gserial_setup(c->cdev->gadget, 1);
+       int i;
+       u8 num_inst = acm_pdata ? acm_pdata->num_inst : 1;
+       int ret = gserial_setup(c->cdev->gadget, num_inst);
+
+       if (ret)
+               return ret;
+
+       for (i = 0; i < num_inst; i++) {
+               ret = acm_bind_config(c, i);
+               if (ret) {
+                       pr_err("Could not bind acm%u config\n", i);
+                       break;
+               }
+       }
+
        return ret;
 }
 
@@ -802,6 +833,7 @@ static struct android_usb_function acm_function = {
 static int __init init(void)
 {
        printk(KERN_INFO "f_acm init\n");
+       platform_driver_register(&acm_platform_driver);
        android_register_function(&acm_function);
        return 0;
 }
index 40f7716..3dcbeca 100644 (file)
@@ -122,7 +122,7 @@ struct gs_port {
 };
 
 /* increase N_PORTS if you need more */
-#define N_PORTS                4
+#define N_PORTS                8
 static struct portmaster {
        struct mutex    lock;                   /* protect open/close */
        struct gs_port  *port;
index ac09dcb..62e72e3 100644 (file)
@@ -88,6 +88,11 @@ struct usb_ether_platform_data {
        const char *vendorDescr;
 };
 
+/* Platform data for ACM driver. */
+struct acm_platform_data {
+       u8      num_inst;
+};
+
 extern void android_register_function(struct android_usb_function *f);
 
 extern void android_enable_function(struct usb_function *f, int enable);