mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 04:12:04 -04:00
Merge remote-tracking branch 'sm8350/lineage-20' into lineage-22.2
* sm8350/lineage-20: usb: gadget: f_ncm: Always set current gadget in ncm_bind() FROMGIT: usb: gadget: u_ether: support configuring interface names. usb: gadget: f_ncm: Revert to upstream Change-Id: I22e19c48a42cc4f436131de72b59dfb87aca6e3c
This commit is contained in:
commit
3da233d881
5 changed files with 102 additions and 96 deletions
|
|
@ -91,9 +91,9 @@ The ECM function provides these attributes in its function directory:
|
|||
|
||||
and after creating the functions/ecm.<instance name> they contain default
|
||||
values: qmult is 5, dev_addr and host_addr are randomly selected.
|
||||
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.
|
||||
The ifname can be written to if the function is not bound. A write must be an
|
||||
interface pattern such as "usb%d", which will cause the net core to choose the
|
||||
next free usbX interface. By default, it is set to "usb%d".
|
||||
|
||||
Testing the ECM function
|
||||
------------------------
|
||||
|
|
@ -131,9 +131,9 @@ The ECM subset function provides these attributes in its function directory:
|
|||
|
||||
and after creating the functions/ecm.<instance name> they contain default
|
||||
values: qmult is 5, dev_addr and host_addr are randomly selected.
|
||||
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.
|
||||
The ifname can be written to if the function is not bound. A write must be an
|
||||
interface pattern such as "usb%d", which will cause the net core to choose the
|
||||
next free usbX interface. By default, it is set to "usb%d".
|
||||
|
||||
Testing the ECM subset function
|
||||
-------------------------------
|
||||
|
|
@ -171,9 +171,9 @@ The EEM function provides these attributes in its function directory:
|
|||
|
||||
and after creating the functions/eem.<instance name> they contain default
|
||||
values: qmult is 5, dev_addr and host_addr are randomly selected.
|
||||
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.
|
||||
The ifname can be written to if the function is not bound. A write must be an
|
||||
interface pattern such as "usb%d", which will cause the net core to choose the
|
||||
next free usbX interface. By default, it is set to "usb%d".
|
||||
|
||||
Testing the EEM function
|
||||
------------------------
|
||||
|
|
@ -453,9 +453,9 @@ The NCM function provides these attributes in its function directory:
|
|||
|
||||
and after creating the functions/ncm.<instance name> they contain default
|
||||
values: qmult is 5, dev_addr and host_addr are randomly selected.
|
||||
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.
|
||||
The ifname can be written to if the function is not bound. A write must be an
|
||||
interface pattern such as "usb%d", which will cause the net core to choose the
|
||||
next free usbX interface. By default, it is set to "usb%d".
|
||||
|
||||
Testing the NCM function
|
||||
------------------------
|
||||
|
|
@ -591,9 +591,9 @@ The RNDIS function provides these attributes in its function directory:
|
|||
|
||||
and after creating the functions/rndis.<instance name> they contain default
|
||||
values: qmult is 5, dev_addr and host_addr are randomly selected.
|
||||
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.
|
||||
The ifname can be written to if the function is not bound. A write must be an
|
||||
interface pattern such as "usb%d", which will cause the net core to choose the
|
||||
next free usbX interface. By default, it is set to "usb%d".
|
||||
|
||||
Testing the RNDIS function
|
||||
--------------------------
|
||||
|
|
|
|||
|
|
@ -1461,47 +1461,22 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
f->os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc;
|
||||
}
|
||||
|
||||
/*
|
||||
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
|
||||
* configurations are bound in sequence with list_for_each_entry,
|
||||
* in each configuration its functions are bound in sequence
|
||||
* with list_for_each_entry, so we assume no race condition
|
||||
* with regard to ncm_opts->bound access
|
||||
*/
|
||||
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);
|
||||
mutex_lock(&ncm_opts->lock);
|
||||
gether_set_gadget(ncm_opts->net, cdev->gadget);
|
||||
if (!ncm_opts->bound)
|
||||
status = gether_register_netdev(ncm_opts->net);
|
||||
mutex_unlock(&ncm_opts->lock);
|
||||
if (status) {
|
||||
free_netdev(ncm_opts->net);
|
||||
goto error;
|
||||
}
|
||||
ncm_opts->bound = true;
|
||||
}
|
||||
mutex_unlock(&ncm_opts->lock);
|
||||
|
||||
/* 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);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
ncm_opts->bound = true;
|
||||
|
||||
us = usb_gstrings_attach(cdev, ncm_strings,
|
||||
ARRAY_SIZE(ncm_string_defs));
|
||||
if (IS_ERR(us)) {
|
||||
status = PTR_ERR(us);
|
||||
goto netdev_cleanup;
|
||||
goto fail;
|
||||
}
|
||||
ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
|
||||
ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
|
||||
|
|
@ -1609,10 +1584,7 @@ fail:
|
|||
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;
|
||||
|
|
@ -1660,7 +1632,8 @@ 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->ncm_interf_group);
|
||||
kfree(opts);
|
||||
}
|
||||
|
|
@ -1679,6 +1652,12 @@ static struct usb_function_instance *ncm_alloc_inst(void)
|
|||
|
||||
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);
|
||||
}
|
||||
INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
|
||||
|
||||
descs[0] = &opts->ncm_os_desc;
|
||||
|
|
@ -1713,13 +1692,9 @@ 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");
|
||||
|
||||
opts->bound = false;
|
||||
|
||||
hrtimer_cancel(&ncm->task_timer);
|
||||
|
||||
kfree(f->os_desc_table);
|
||||
|
|
@ -1735,14 +1710,13 @@ 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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -1752,9 +1726,20 @@ 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;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ struct eth_dev {
|
|||
|
||||
bool zlp;
|
||||
bool no_skb_reserve;
|
||||
bool ifname_set;
|
||||
u8 host_mac[ETH_ALEN];
|
||||
u8 dev_mac[ETH_ALEN];
|
||||
};
|
||||
|
|
@ -979,15 +980,45 @@ EXPORT_SYMBOL_GPL(gether_get_qmult);
|
|||
|
||||
int gether_get_ifname(struct net_device *net, char *name, int len)
|
||||
{
|
||||
struct eth_dev *dev = netdev_priv(net);
|
||||
int ret;
|
||||
|
||||
rtnl_lock();
|
||||
ret = scnprintf(name, len, "%s\n", netdev_name(net));
|
||||
ret = scnprintf(name, len, "%s\n",
|
||||
dev->ifname_set ? net->name : netdev_name(net));
|
||||
rtnl_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_get_ifname);
|
||||
|
||||
int gether_set_ifname(struct net_device *net, const char *name, int len)
|
||||
{
|
||||
struct eth_dev *dev = netdev_priv(net);
|
||||
char tmp[IFNAMSIZ];
|
||||
const char *p;
|
||||
|
||||
if (name[len - 1] == '\n')
|
||||
len--;
|
||||
|
||||
if (len >= sizeof(tmp))
|
||||
return -E2BIG;
|
||||
|
||||
strscpy(tmp, name, len + 1);
|
||||
if (!dev_valid_name(tmp))
|
||||
return -EINVAL;
|
||||
|
||||
/* Require exactly one %d, so binding will not fail with EEXIST. */
|
||||
p = strchr(name, '%');
|
||||
if (!p || p[1] != 'd' || strchr(p + 2, '%'))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(net->name, tmp, sizeof(net->name));
|
||||
dev->ifname_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gether_set_ifname);
|
||||
|
||||
/**
|
||||
* gether_cleanup - remove Ethernet-over-USB device
|
||||
* Context: may sleep
|
||||
|
|
|
|||
|
|
@ -244,6 +244,18 @@ unsigned gether_get_qmult(struct net_device *net);
|
|||
*/
|
||||
int gether_get_ifname(struct net_device *net, char *name, int len);
|
||||
|
||||
/**
|
||||
* gether_set_ifname - set an ethernet-over-usb link interface name
|
||||
* @net: device representing this link
|
||||
* @name: new interface name
|
||||
* @len: length of @name
|
||||
*
|
||||
* This sets the interface name of this ethernet-over-usb link.
|
||||
* A single terminating newline, if any, is ignored.
|
||||
* Returns zero on success, else negative errno.
|
||||
*/
|
||||
int gether_set_ifname(struct net_device *net, const char *name, int len);
|
||||
|
||||
void gether_cleanup(struct eth_dev *dev);
|
||||
|
||||
/* connect/disconnect is handled by individual functions */
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int result; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -50,11 +45,6 @@
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int ret; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
if (opts->refcnt) { \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -77,11 +67,6 @@
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int result; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -95,11 +80,6 @@
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int ret; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
if (opts->refcnt) { \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -122,11 +102,6 @@
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
unsigned qmult; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
qmult = gether_get_qmult(opts->net); \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -140,11 +115,6 @@
|
|||
u8 val; \
|
||||
int ret; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
if (opts->refcnt) { \
|
||||
ret = -EBUSY; \
|
||||
|
|
@ -171,11 +141,6 @@ out: \
|
|||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int ret; \
|
||||
\
|
||||
if (opts->bound == false) { \
|
||||
pr_err("Gadget function do not bind yet.\n"); \
|
||||
return -ENODEV; \
|
||||
} \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
ret = gether_get_ifname(opts->net, page, PAGE_SIZE); \
|
||||
mutex_unlock(&opts->lock); \
|
||||
|
|
@ -183,7 +148,20 @@ out: \
|
|||
return ret; \
|
||||
} \
|
||||
\
|
||||
CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
|
||||
static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
|
||||
const char *page, size_t len)\
|
||||
{ \
|
||||
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
|
||||
int ret = -EBUSY; \
|
||||
\
|
||||
mutex_lock(&opts->lock); \
|
||||
if (!opts->refcnt) \
|
||||
ret = gether_set_ifname(opts->net, page, len); \
|
||||
mutex_unlock(&opts->lock); \
|
||||
return ret ?: len; \
|
||||
} \
|
||||
\
|
||||
CONFIGFS_ATTR(_f_##_opts_, ifname)
|
||||
|
||||
#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_) \
|
||||
static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\
|
||||
|
|
|
|||
Loading…
Reference in a new issue