usb: gadget: f_ncm: allocate/free net device upon driver bind/unbind
Driver registers net device in bind but does not unregister it upon driver unbind. Upon composition switch ncm net device is no longer in use, hence unregister and free it in driver unbind. Unregistering net device sends notification to user space which can be used by user space entities to perform necessary actions for example updating UI. Symmetrically allocate and register net device in driver bind. Change-Id: Ie1bb781aba8efee20cc98c1d6bf264403c3b087e Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
parent
aa810ad47c
commit
d50dafdc03
@@ -1404,17 +1404,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
*/
|
||||
if (!ncm_opts->bound) {
|
||||
mutex_lock(&ncm_opts->lock);
|
||||
ncm_opts->net = gether_setup_default();
|
||||
if (IS_ERR(ncm_opts->net)) {
|
||||
status = PTR_ERR(ncm_opts->net);
|
||||
mutex_unlock(&ncm_opts->lock);
|
||||
goto error;
|
||||
}
|
||||
gether_set_gadget(ncm_opts->net, cdev->gadget);
|
||||
status = gether_register_netdev(ncm_opts->net);
|
||||
mutex_unlock(&ncm_opts->lock);
|
||||
if (status)
|
||||
return status;
|
||||
if (status) {
|
||||
free_netdev(ncm_opts->net);
|
||||
goto error;
|
||||
}
|
||||
ncm_opts->bound = true;
|
||||
}
|
||||
|
||||
/* export host's Ethernet address in CDC format */
|
||||
status = gether_get_host_addr_cdc(ncm_opts->net, ncm->ethaddr,
|
||||
sizeof(ncm->ethaddr));
|
||||
if (status < 12) { /* strlen("01234567890a") */
|
||||
ERROR(cdev, "%s: failed to get host eth addr, err %d\n",
|
||||
__func__, status);
|
||||
status = -EINVAL;
|
||||
goto netdev_cleanup;
|
||||
}
|
||||
ncm->port.ioport = netdev_priv(ncm_opts->net);
|
||||
|
||||
us = usb_gstrings_attach(cdev, ncm_strings,
|
||||
ARRAY_SIZE(ncm_string_defs));
|
||||
if (IS_ERR(us))
|
||||
return PTR_ERR(us);
|
||||
if (IS_ERR(us)) {
|
||||
status = PTR_ERR(us);
|
||||
goto netdev_cleanup;
|
||||
}
|
||||
ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
|
||||
ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
|
||||
ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
|
||||
@@ -1514,7 +1536,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
kfree(ncm->notify_req->buf);
|
||||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
}
|
||||
netdev_cleanup:
|
||||
gether_cleanup(netdev_priv(ncm_opts->net));
|
||||
|
||||
error:
|
||||
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
|
||||
|
||||
return status;
|
||||
@@ -1562,8 +1587,6 @@ static void ncm_free_inst(struct usb_function_instance *f)
|
||||
opts = container_of(f, struct f_ncm_opts, func_inst);
|
||||
if (opts->bound)
|
||||
gether_cleanup(netdev_priv(opts->net));
|
||||
else
|
||||
free_netdev(opts->net);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
@@ -1576,12 +1599,6 @@ static struct usb_function_instance *ncm_alloc_inst(void)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mutex_init(&opts->lock);
|
||||
opts->func_inst.free_func_inst = ncm_free_inst;
|
||||
opts->net = gether_setup_default();
|
||||
if (IS_ERR(opts->net)) {
|
||||
struct net_device *net = opts->net;
|
||||
kfree(opts);
|
||||
return ERR_CAST(net);
|
||||
}
|
||||
|
||||
config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
|
||||
|
||||
@@ -1604,6 +1621,8 @@ static void ncm_free(struct usb_function *f)
|
||||
static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_ncm *ncm = func_to_ncm(f);
|
||||
struct f_ncm_opts *opts = container_of(f->fi, struct f_ncm_opts,
|
||||
func_inst);
|
||||
|
||||
DBG(c->cdev, "ncm unbind\n");
|
||||
|
||||
@@ -1614,13 +1633,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
kfree(ncm->notify_req->buf);
|
||||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
|
||||
gether_cleanup(netdev_priv(opts->net));
|
||||
opts->bound = false;
|
||||
}
|
||||
|
||||
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_ncm *ncm;
|
||||
struct f_ncm_opts *opts;
|
||||
int status;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
|
||||
@@ -1630,20 +1651,9 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
|
||||
opts = container_of(fi, struct f_ncm_opts, func_inst);
|
||||
mutex_lock(&opts->lock);
|
||||
opts->refcnt++;
|
||||
|
||||
/* export host's Ethernet address in CDC format */
|
||||
status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
|
||||
sizeof(ncm->ethaddr));
|
||||
if (status < 12) { /* strlen("01234567890a") */
|
||||
kfree(ncm);
|
||||
mutex_unlock(&opts->lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
|
||||
|
||||
spin_lock_init(&ncm->lock);
|
||||
ncm_reset_values(ncm);
|
||||
ncm->port.ioport = netdev_priv(opts->net);
|
||||
mutex_unlock(&opts->lock);
|
||||
ncm->port.is_fixed = true;
|
||||
ncm->port.supports_multi_frame = true;
|
||||
|
||||
Reference in New Issue
Block a user