Commit 02832e56 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Felipe Balbi

usb: gadget: f_subset: add configfs support

f_subset learns about configfs so we can, eventually,
remove in-kernel gadget drivers.
Signed-off-by: default avatarAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 74bf963d
What: /config/usb-gadget/gadget/functions/geth.name
Date: May 2013
KenelVersion: 3.11
Description:
The attributes:
ifname - network device interface name associated with
this function instance
qmult - queue length multiplier for high and
super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
...@@ -547,6 +547,16 @@ choice ...@@ -547,6 +547,16 @@ choice
# this first set of drivers all depend on bulk-capable hardware. # this first set of drivers all depend on bulk-capable hardware.
config USB_CONFIGFS_ECM_SUBSET
boolean "Ethernet Control Model (CDC ECM) subset"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_SUBSET
help
On hardware that can't implement the full protocol,
a simple CDC subset is used, placing fewer demands on USB.
config USB_CONFIGFS_EEM config USB_CONFIGFS_EEM
bool "Ethernet Emulation Model (EEM)" bool "Ethernet Emulation Model (EEM)"
depends on USB_CONFIGFS depends on USB_CONFIGFS
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include "u_ether.h" #include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_gether.h" #include "u_gether.h"
/* /*
...@@ -313,8 +314,10 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -313,8 +314,10 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
* with regard to gether_opts->bound access * with regard to gether_opts->bound access
*/ */
if (!gether_opts->bound) { if (!gether_opts->bound) {
mutex_lock(&gether_opts->lock);
gether_set_gadget(gether_opts->net, cdev->gadget); gether_set_gadget(gether_opts->net, cdev->gadget);
status = gether_register_netdev(gether_opts->net); status = gether_register_netdev(gether_opts->net);
mutex_unlock(&gether_opts->lock);
if (status) if (status)
return status; return status;
gether_opts->bound = true; gether_opts->bound = true;
...@@ -445,6 +448,41 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], ...@@ -445,6 +448,41 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
#else #else
static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_gether_opts,
func_inst.group);
}
/* f_gether_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(gether);
/* f_gether_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(gether);
/* f_gether_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(gether);
/* f_gether_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(gether);
/* f_gether_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(gether);
static struct configfs_attribute *gether_attrs[] = {
&f_gether_opts_dev_addr.attr,
&f_gether_opts_host_addr.attr,
&f_gether_opts_qmult.attr,
&f_gether_opts_ifname.attr,
NULL,
};
static struct config_item_type gether_func_type = {
.ct_item_ops = &gether_item_ops,
.ct_attrs = gether_attrs,
.ct_owner = THIS_MODULE,
};
static void geth_free_inst(struct usb_function_instance *f) static void geth_free_inst(struct usb_function_instance *f)
{ {
struct f_gether_opts *opts; struct f_gether_opts *opts;
...@@ -464,12 +502,15 @@ static struct usb_function_instance *geth_alloc_inst(void) ...@@ -464,12 +502,15 @@ static struct usb_function_instance *geth_alloc_inst(void)
opts = kzalloc(sizeof(*opts), GFP_KERNEL); opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts) if (!opts)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = geth_free_inst; opts->func_inst.free_func_inst = geth_free_inst;
opts->net = gether_setup_default(); opts->net = gether_setup_default();
if (IS_ERR(opts->net)) if (IS_ERR(opts->net))
return ERR_CAST(opts->net); return ERR_CAST(opts->net);
config_group_init_type_name(&opts->func_inst.group, "",
&gether_func_type);
return &opts->func_inst; return &opts->func_inst;
} }
...@@ -500,6 +541,8 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi) ...@@ -500,6 +541,8 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
opts = container_of(fi, struct f_gether_opts, func_inst); opts = container_of(fi, struct f_gether_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
/* export host's Ethernet address in CDC format */ /* export host's Ethernet address in CDC format */
status = gether_get_host_addr_cdc(opts->net, geth->ethaddr, status = gether_get_host_addr_cdc(opts->net, geth->ethaddr,
sizeof(geth->ethaddr)); sizeof(geth->ethaddr));
...@@ -510,6 +553,7 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi) ...@@ -510,6 +553,7 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
geth_string_defs[1].s = geth->ethaddr; geth_string_defs[1].s = geth->ethaddr;
geth->port.ioport = netdev_priv(opts->net); geth->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
geth->port.cdc_filter = DEFAULT_FILTER; geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset"; geth->port.func.name = "cdc_subset";
......
...@@ -22,6 +22,15 @@ struct f_gether_opts { ...@@ -22,6 +22,15 @@ struct f_gether_opts {
struct usb_function_instance func_inst; struct usb_function_instance func_inst;
struct net_device *net; struct net_device *net;
bool bound; bool bound;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This is to protect the data from concurrent access by read/write
* and create symlink/remove symlink.
*/
struct mutex lock;
int refcnt;
}; };
#endif /* U_GETHER_H */ #endif /* U_GETHER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment