Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff25c3b1 authored by Hemant Kumar's avatar Hemant Kumar Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarHemant Kumar <hemantk@codeaurora.org>
parent f89a92d3
Loading
Loading
Loading
Loading
+34 −24
Original line number Diff line number Diff line
@@ -1422,17 +1422,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;
@@ -1533,7 +1555,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;
@@ -1628,8 +1653,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);
}

@@ -1642,12 +1665,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);

@@ -1678,6 +1695,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");

@@ -1689,13 +1708,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);
@@ -1705,20 +1726,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;