usb: gadget: rndis: remove the limit of available rndis connections
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Fri, 6 Feb 2015 12:43:30 +0000 (13:43 +0100)
committerFelipe Balbi <balbi@ti.com>
Thu, 7 May 2015 18:47:17 +0000 (13:47 -0500)
RNDIS function has a limitation on the number of allowed instances.
So far it has been RNDIS_MAX_CONFIGS, which happens to be one.
In order to eliminate this kind of arbitrary limitation we should not
preallocate a predefined (RNDIS_MAX_CONFIGS) array of struct rndis_params
instances but instead allow allocating them on demand.

This patch allocates struct rndis_params on demand in rndis_register().
Coversly, the structure is free()'d in rndis_deregister().
If CONFIG_USB_GADGET_DEBUG_FILES is set, the proc files are created which
is the same behaviour as before, but the moment of creation is delayed
until struct rndis_params is actually allocated.

rnids_init() and rndis_exit() have nothing to do, so they are eliminated.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Documentation/usb/gadget-testing.txt
drivers/usb/gadget/function/f_rndis.c
drivers/usb/gadget/function/rndis.c
drivers/usb/gadget/function/u_rndis.h

index 7769eee3b1b5ce965060fbcedf34a49d4f06ca8e..592678009c15c393d59b9ce190b6a96057486160 100644 (file)
@@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
 configuration. The ifname is read-only and contains the name of the interface
 which was assigned by the net core, e. g. usb0.
 
-By default there can be only 1 RNDIS interface in the system.
-
 Testing the RNDIS function
 --------------------------
 
index 2dafe728ca2dc10fe5f966d75269f8606a91c8e9..32985dade8385145b6c4493a153656cc6b1aea22 100644 (file)
@@ -1012,26 +1012,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
        return &rndis->port.func;
 }
 
-DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc);
-
-static int __init rndis_mod_init(void)
-{
-       int ret;
-
-       ret = rndis_init();
-       if (ret)
-               return ret;
-
-       return usb_function_register(&rndisusb_func);
-}
-module_init(rndis_mod_init);
-
-static void __exit rndis_mod_exit(void)
-{
-       usb_function_unregister(&rndisusb_func);
-       rndis_exit();
-}
-module_exit(rndis_mod_exit);
-
+DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Brownell");
index 01a3b589165607c5ed8ace14a60adac91d65a095..dd6800017ade77fd69f1dd20fe14e381a4e6afbe 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/idr.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
@@ -57,10 +58,13 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
 #define rndis_debug            0
 #endif
 
-#define RNDIS_MAX_CONFIGS      1
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
 
+#define        NAME_TEMPLATE "driver/rndis-%03d"
 
-static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+static DEFINE_IDA(rndis_ida);
 
 /* Driver Version */
 static const __le32 rndis_driver_version = cpu_to_le32(1);
@@ -69,6 +73,11 @@ static const __le32 rndis_driver_version = cpu_to_le32(1);
 static rndis_resp_t *rndis_add_response(struct rndis_params *params,
                                        u32 length);
 
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static const struct file_operations rndis_proc_fops;
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /* supported OIDs */
 static const u32 oid_supported_list[] =
@@ -850,38 +859,93 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
 }
 EXPORT_SYMBOL_GPL(rndis_msg_parser);
 
+static inline int rndis_get_nr(void)
+{
+       return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
+}
+
+static inline void rndis_put_nr(int nr)
+{
+       ida_simple_remove(&rndis_ida, nr);
+}
+
 struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
 {
+       struct rndis_params *params;
        u8 i;
 
        if (!resp_avail)
                return ERR_PTR(-EINVAL);
 
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               if (!rndis_per_dev_params[i].used) {
-                       rndis_per_dev_params[i].used = 1;
-                       rndis_per_dev_params[i].resp_avail = resp_avail;
-                       rndis_per_dev_params[i].v = v;
-                       pr_debug("%s: configNr = %d\n", __func__, i);
-                       return &rndis_per_dev_params[i];
+       i = rndis_get_nr();
+       if (i < 0) {
+               pr_debug("failed\n");
+
+               return ERR_PTR(-ENODEV);
+       }
+
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params) {
+               rndis_put_nr(i);
+
+               return ERR_PTR(-ENOMEM);
+       }
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+       {
+               struct proc_dir_entry *proc_entry;
+               char name[20];
+
+               sprintf(name, NAME_TEMPLATE, i);
+               proc_entry = proc_create_data(name, 0660, NULL,
+                                             &rndis_proc_fops, params);
+               if (!proc_entry) {
+                       kfree(params);
+                       rndis_put_nr(i);
+
+                       return ERR_PTR(-EIO);
                }
        }
-       pr_debug("failed\n");
+#endif
 
-       return ERR_PTR(-ENODEV);
+       params->confignr = i;
+       params->used = 1;
+       params->state = RNDIS_UNINITIALIZED;
+       params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
+       params->resp_avail = resp_avail;
+       params->v = v;
+       INIT_LIST_HEAD(&(params->resp_queue));
+       pr_debug("%s: configNr = %d\n", __func__, i);
+
+       return params;
 }
 EXPORT_SYMBOL_GPL(rndis_register);
 
 void rndis_deregister(struct rndis_params *params)
 {
+       u8 i;
+
        pr_debug("%s:\n", __func__);
 
        if (!params)
                return;
-       params->used = 0;
+
+       i = params->confignr;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+       {
+               u8 i;
+               char name[20];
+
+               sprintf(name, NAME_TEMPLATE, i);
+               remove_proc_entry(name, NULL);
+       }
+#endif
+
+       kfree(params);
+       rndis_put_nr(i);
 }
 EXPORT_SYMBOL_GPL(rndis_deregister);
-
 int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
                        u16 *cdc_filter)
 {
@@ -1114,54 +1178,4 @@ static const struct file_operations rndis_proc_fops = {
 
 #define        NAME_TEMPLATE "driver/rndis-%03d"
 
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
-
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-
-int rndis_init(void)
-{
-       u8 i;
-
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-               char name [20];
-
-               sprintf(name, NAME_TEMPLATE, i);
-               rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
-                                       &rndis_proc_fops,
-                                       (void *)(rndis_per_dev_params + i));
-               if (!rndis_connect_state[i]) {
-                       pr_debug("%s: remove entries", __func__);
-                       while (i) {
-                               sprintf(name, NAME_TEMPLATE, --i);
-                               remove_proc_entry(name, NULL);
-                       }
-                       pr_debug("\n");
-                       return -EIO;
-               }
-#endif
-               rndis_per_dev_params[i].confignr = i;
-               rndis_per_dev_params[i].used = 0;
-               rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
-               rndis_per_dev_params[i].media_state
-                               = RNDIS_MEDIA_STATE_DISCONNECTED;
-               INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
-       }
-
-       return 0;
-}
-
-void rndis_exit(void)
-{
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-       u8 i;
-       char name[20];
-
-       for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-               sprintf(name, NAME_TEMPLATE, i);
-               remove_proc_entry(name, NULL);
-       }
-#endif
-}
-
index e902aa42a29730e1c2e8efda878a1f8e95a26455..4eafd50505458cf10d2b58e48b8ba1dcd092ed4d 100644 (file)
@@ -39,8 +39,6 @@ struct f_rndis_opts {
        int                             refcnt;
 };
 
-int rndis_init(void);
-void rndis_exit(void);
 void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
 
 #endif /* U_RNDIS_H */
This page took 0.031433 seconds and 5 git commands to generate.