Commit 17b80976 authored by Andrzej Pietrasiewicz's avatar Andrzej Pietrasiewicz Committed by Felipe Balbi

usb: gadget: f_eem: add configfs support

f_eem learns about our configfs interface so we
can remove in-kernel gadget drivers in future.
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 998da497
What: /config/usb-gadget/gadget/functions/eem.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
...@@ -544,6 +544,21 @@ choice ...@@ -544,6 +544,21 @@ 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_EEM
bool "Ethernet Emulation Model (EEM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
select USB_F_EEM
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and
EEM are designed for different applications. The ECM model extends
the network interface to the target (e.g. a USB cable modem), and the
EEM model is for mobile devices to communicate with hosts using
ethernet over USB. For Linux gadgets, however, the interface with
the host is the same (a usbX device), so the differences are minimal.
config USB_CONFIGFS_PHONET config USB_CONFIGFS_PHONET
boolean "Phonet protocol" boolean "Phonet protocol"
depends on USB_CONFIGFS depends on USB_CONFIGFS
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "u_ether.h" #include "u_ether.h"
#include "u_ether_configfs.h"
#include "u_eem.h" #include "u_eem.h"
#define EEM_HLEN 2 #define EEM_HLEN 2
...@@ -263,8 +264,10 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -263,8 +264,10 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
* with regard to eem_opts->bound access * with regard to eem_opts->bound access
*/ */
if (!eem_opts->bound) { if (!eem_opts->bound) {
mutex_lock(&eem_opts->lock);
gether_set_gadget(eem_opts->net, cdev->gadget); gether_set_gadget(eem_opts->net, cdev->gadget);
status = gether_register_netdev(eem_opts->net); status = gether_register_netdev(eem_opts->net);
mutex_unlock(&eem_opts->lock);
if (status) if (status)
return status; return status;
eem_opts->bound = true; eem_opts->bound = true;
...@@ -533,6 +536,41 @@ static int eem_unwrap(struct gether *port, ...@@ -533,6 +536,41 @@ static int eem_unwrap(struct gether *port,
return status; return status;
} }
static inline struct f_eem_opts *to_f_eem_opts(struct config_item *item)
{
return container_of(to_config_group(item), struct f_eem_opts,
func_inst.group);
}
/* f_eem_item_ops */
USB_ETHERNET_CONFIGFS_ITEM(eem);
/* f_eem_opts_dev_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(eem);
/* f_eem_opts_host_addr */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(eem);
/* f_eem_opts_qmult */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(eem);
/* f_eem_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(eem);
static struct configfs_attribute *eem_attrs[] = {
&f_eem_opts_dev_addr.attr,
&f_eem_opts_host_addr.attr,
&f_eem_opts_qmult.attr,
&f_eem_opts_ifname.attr,
NULL,
};
static struct config_item_type eem_func_type = {
.ct_item_ops = &eem_item_ops,
.ct_attrs = eem_attrs,
.ct_owner = THIS_MODULE,
};
static void eem_free_inst(struct usb_function_instance *f) static void eem_free_inst(struct usb_function_instance *f)
{ {
struct f_eem_opts *opts; struct f_eem_opts *opts;
...@@ -552,20 +590,28 @@ static struct usb_function_instance *eem_alloc_inst(void) ...@@ -552,20 +590,28 @@ static struct usb_function_instance *eem_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 = eem_free_inst; opts->func_inst.free_func_inst = eem_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, "", &eem_func_type);
return &opts->func_inst; return &opts->func_inst;
} }
static void eem_free(struct usb_function *f) static void eem_free(struct usb_function *f)
{ {
struct f_eem *eem; struct f_eem *eem;
struct f_eem_opts *opts;
eem = func_to_eem(f); eem = func_to_eem(f);
opts = container_of(f->fi, struct f_eem_opts, func_inst);
kfree(eem); kfree(eem);
mutex_lock(&opts->lock);
opts->refcnt--;
mutex_unlock(&opts->lock);
} }
static void eem_unbind(struct usb_configuration *c, struct usb_function *f) static void eem_unbind(struct usb_configuration *c, struct usb_function *f)
...@@ -586,8 +632,11 @@ struct usb_function *eem_alloc(struct usb_function_instance *fi) ...@@ -586,8 +632,11 @@ struct usb_function *eem_alloc(struct usb_function_instance *fi)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
opts = container_of(fi, struct f_eem_opts, func_inst); opts = container_of(fi, struct f_eem_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
eem->port.ioport = netdev_priv(opts->net); eem->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
eem->port.cdc_filter = DEFAULT_FILTER; eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem"; eem->port.func.name = "cdc_eem";
......
...@@ -22,6 +22,15 @@ struct f_eem_opts { ...@@ -22,6 +22,15 @@ struct f_eem_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_EEM_H */ #endif /* U_EEM_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