usb: gadget: rndis: remove the limit of available rndis connections
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>
This commit is contained in:
parent
6122b151c7
commit
d6d22922d9
|
@ -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
|
configuration. The ifname is read-only and contains the name of the interface
|
||||||
which was assigned by the net core, e. g. usb0.
|
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
|
Testing the RNDIS function
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
@ -1012,26 +1012,6 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
|
||||||
return &rndis->port.func;
|
return &rndis->port.func;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc);
|
DECLARE_USB_FUNCTION_INIT(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);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("David Brownell");
|
MODULE_AUTHOR("David Brownell");
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -57,10 +58,13 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
|
||||||
#define rndis_debug 0
|
#define rndis_debug 0
|
||||||
#endif
|
#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 */
|
/* Driver Version */
|
||||||
static const __le32 rndis_driver_version = cpu_to_le32(1);
|
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,
|
static rndis_resp_t *rndis_add_response(struct rndis_params *params,
|
||||||
u32 length);
|
u32 length);
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||||
|
|
||||||
|
static const struct file_operations rndis_proc_fops;
|
||||||
|
|
||||||
|
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
||||||
|
|
||||||
/* supported OIDs */
|
/* supported OIDs */
|
||||||
static const u32 oid_supported_list[] =
|
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);
|
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 *rndis_register(void (*resp_avail)(void *v), void *v)
|
||||||
{
|
{
|
||||||
|
struct rndis_params *params;
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
if (!resp_avail)
|
if (!resp_avail)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
|
i = rndis_get_nr();
|
||||||
if (!rndis_per_dev_params[i].used) {
|
if (i < 0) {
|
||||||
rndis_per_dev_params[i].used = 1;
|
pr_debug("failed\n");
|
||||||
rndis_per_dev_params[i].resp_avail = resp_avail;
|
|
||||||
rndis_per_dev_params[i].v = v;
|
return ERR_PTR(-ENODEV);
|
||||||
pr_debug("%s: configNr = %d\n", __func__, i);
|
}
|
||||||
return &rndis_per_dev_params[i];
|
|
||||||
|
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);
|
EXPORT_SYMBOL_GPL(rndis_register);
|
||||||
|
|
||||||
void rndis_deregister(struct rndis_params *params)
|
void rndis_deregister(struct rndis_params *params)
|
||||||
{
|
{
|
||||||
|
u8 i;
|
||||||
|
|
||||||
pr_debug("%s:\n", __func__);
|
pr_debug("%s:\n", __func__);
|
||||||
|
|
||||||
if (!params)
|
if (!params)
|
||||||
return;
|
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);
|
EXPORT_SYMBOL_GPL(rndis_deregister);
|
||||||
|
|
||||||
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
|
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
|
||||||
u16 *cdc_filter)
|
u16 *cdc_filter)
|
||||||
{
|
{
|
||||||
|
@ -1114,54 +1178,4 @@ static const struct file_operations rndis_proc_fops = {
|
||||||
|
|
||||||
#define NAME_TEMPLATE "driver/rndis-%03d"
|
#define NAME_TEMPLATE "driver/rndis-%03d"
|
||||||
|
|
||||||
static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
|
|
||||||
|
|
||||||
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,6 @@ struct f_rndis_opts {
|
||||||
int refcnt;
|
int refcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rndis_init(void);
|
|
||||||
void rndis_exit(void);
|
|
||||||
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
|
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
|
||||||
|
|
||||||
#endif /* U_RNDIS_H */
|
#endif /* U_RNDIS_H */
|
||||||
|
|
Loading…
Reference in a new issue