usb: gadget: f_rndis: OS descriptors support
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Thu, 8 May 2014 12:06:24 +0000 (14:06 +0200)
committerFelipe Balbi <balbi@ti.com>
Wed, 14 May 2014 14:38:58 +0000 (09:38 -0500)
In order for usb functions to expose OS descriptors they
need to be made aware of OS descriptors. This involves
extending the "options" structure and setting up
appropriate associations.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/u_rndis.h

index 139bc9c6f7e0856e383c332968966dc2d53b867e..28d1891f11fa2860f526296cd6851f4e568decc8 100644 (file)
@@ -682,6 +682,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 
        rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);
 
+       if (cdev->use_os_string) {
+               f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
+                                          GFP_KERNEL);
+               if (!f->os_desc_table)
+                       return PTR_ERR(f->os_desc_table);
+               f->os_desc_n = 1;
+               f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
+       }
+
        /*
         * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
         * configurations are bound in sequence with list_for_each_entry,
@@ -693,14 +702,16 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
                gether_set_gadget(rndis_opts->net, cdev->gadget);
                status = gether_register_netdev(rndis_opts->net);
                if (status)
-                       return status;
+                       goto fail;
                rndis_opts->bound = true;
        }
 
        us = usb_gstrings_attach(cdev, rndis_strings,
                                 ARRAY_SIZE(rndis_string_defs));
-       if (IS_ERR(us))
-               return PTR_ERR(us);
+       if (IS_ERR(us)) {
+               status = PTR_ERR(us);
+               goto fail;
+       }
        rndis_control_intf.iInterface = us[0].id;
        rndis_data_intf.iInterface = us[1].id;
        rndis_iad_descriptor.iFunction = us[2].id;
@@ -802,6 +813,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
+       kfree(f->os_desc_table);
+       f->os_desc_n = 0;
        usb_free_all_descriptors(f);
 
        if (rndis->notify_req) {
@@ -892,6 +905,8 @@ static struct usb_function_instance *rndis_alloc_inst(void)
        opts = kzalloc(sizeof(*opts), GFP_KERNEL);
        if (!opts)
                return ERR_PTR(-ENOMEM);
+       opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id;
+
        mutex_init(&opts->lock);
        opts->func_inst.free_func_inst = rndis_free_inst;
        opts->net = gether_setup_default();
@@ -900,6 +915,7 @@ static struct usb_function_instance *rndis_alloc_inst(void)
                kfree(opts);
                return ERR_CAST(net);
        }
+       INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop);
 
        config_group_init_type_name(&opts->func_inst.group, "",
                                    &rndis_func_type);
@@ -925,6 +941,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        struct f_rndis          *rndis = func_to_rndis(f);
 
+       kfree(f->os_desc_table);
+       f->os_desc_n = 0;
        usb_free_all_descriptors(f);
 
        kfree(rndis->notify_req->buf);
index 7291b15c9dcefd0af5d11216a6d16ea9c2f3ae6e..e902aa42a29730e1c2e8efda878a1f8e95a26455 100644 (file)
@@ -26,6 +26,9 @@ struct f_rndis_opts {
        bool                            bound;
        bool                            borrowed_net;
 
+       struct usb_os_desc              rndis_os_desc;
+       char                            rndis_ext_compat_id[16];
+
        /*
         * Read/write access to configfs attributes is handled by configfs.
         *