diff options
-rw-r--r-- | Documentation/ABI/testing/configfs-usb-gadget-eem | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/Kconfig | 15 | ||||
-rw-r--r-- | drivers/usb/gadget/f_eem.c | 49 | ||||
-rw-r--r-- | drivers/usb/gadget/u_eem.h | 9 |
4 files changed, 87 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-eem b/Documentation/ABI/testing/configfs-usb-gadget-eem new file mode 100644 index 000000000000..10e87d67fa2e --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-eem | |||
@@ -0,0 +1,14 @@ | |||
1 | What: /config/usb-gadget/gadget/functions/eem.name | ||
2 | Date: May 2013 | ||
3 | KenelVersion: 3.11 | ||
4 | Description: | ||
5 | The attributes: | ||
6 | |||
7 | ifname - network device interface name associated with | ||
8 | this function instance | ||
9 | qmult - queue length multiplier for high and | ||
10 | super speed | ||
11 | host_addr - MAC address of host's end of this | ||
12 | Ethernet over USB link | ||
13 | dev_addr - MAC address of device's end of this | ||
14 | Ethernet over USB link | ||
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 159393d58912..d5b0ffe26118 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -544,6 +544,21 @@ choice | |||
544 | 544 | ||
545 | # this first set of drivers all depend on bulk-capable hardware. | 545 | # this first set of drivers all depend on bulk-capable hardware. |
546 | 546 | ||
547 | config USB_CONFIGFS_EEM | ||
548 | bool "Ethernet Emulation Model (EEM)" | ||
549 | depends on USB_CONFIGFS | ||
550 | depends on NET | ||
551 | select USB_U_ETHER | ||
552 | select USB_F_EEM | ||
553 | help | ||
554 | CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM | ||
555 | and therefore can be supported by more hardware. Technically ECM and | ||
556 | EEM are designed for different applications. The ECM model extends | ||
557 | the network interface to the target (e.g. a USB cable modem), and the | ||
558 | EEM model is for mobile devices to communicate with hosts using | ||
559 | ethernet over USB. For Linux gadgets, however, the interface with | ||
560 | the host is the same (a usbX device), so the differences are minimal. | ||
561 | |||
547 | config USB_CONFIGFS_PHONET | 562 | config USB_CONFIGFS_PHONET |
548 | boolean "Phonet protocol" | 563 | boolean "Phonet protocol" |
549 | depends on USB_CONFIGFS | 564 | depends on USB_CONFIGFS |
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 31a2cb7ebe82..90ee8022e8d8 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | 20 | ||
21 | #include "u_ether.h" | 21 | #include "u_ether.h" |
22 | #include "u_ether_configfs.h" | ||
22 | #include "u_eem.h" | 23 | #include "u_eem.h" |
23 | 24 | ||
24 | #define EEM_HLEN 2 | 25 | #define EEM_HLEN 2 |
@@ -263,8 +264,10 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) | |||
263 | * with regard to eem_opts->bound access | 264 | * with regard to eem_opts->bound access |
264 | */ | 265 | */ |
265 | if (!eem_opts->bound) { | 266 | if (!eem_opts->bound) { |
267 | mutex_lock(&eem_opts->lock); | ||
266 | gether_set_gadget(eem_opts->net, cdev->gadget); | 268 | gether_set_gadget(eem_opts->net, cdev->gadget); |
267 | status = gether_register_netdev(eem_opts->net); | 269 | status = gether_register_netdev(eem_opts->net); |
270 | mutex_unlock(&eem_opts->lock); | ||
268 | if (status) | 271 | if (status) |
269 | return status; | 272 | return status; |
270 | eem_opts->bound = true; | 273 | eem_opts->bound = true; |
@@ -533,6 +536,41 @@ error: | |||
533 | return status; | 536 | return status; |
534 | } | 537 | } |
535 | 538 | ||
539 | static inline struct f_eem_opts *to_f_eem_opts(struct config_item *item) | ||
540 | { | ||
541 | return container_of(to_config_group(item), struct f_eem_opts, | ||
542 | func_inst.group); | ||
543 | } | ||
544 | |||
545 | /* f_eem_item_ops */ | ||
546 | USB_ETHERNET_CONFIGFS_ITEM(eem); | ||
547 | |||
548 | /* f_eem_opts_dev_addr */ | ||
549 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(eem); | ||
550 | |||
551 | /* f_eem_opts_host_addr */ | ||
552 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(eem); | ||
553 | |||
554 | /* f_eem_opts_qmult */ | ||
555 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(eem); | ||
556 | |||
557 | /* f_eem_opts_ifname */ | ||
558 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(eem); | ||
559 | |||
560 | static struct configfs_attribute *eem_attrs[] = { | ||
561 | &f_eem_opts_dev_addr.attr, | ||
562 | &f_eem_opts_host_addr.attr, | ||
563 | &f_eem_opts_qmult.attr, | ||
564 | &f_eem_opts_ifname.attr, | ||
565 | NULL, | ||
566 | }; | ||
567 | |||
568 | static struct config_item_type eem_func_type = { | ||
569 | .ct_item_ops = &eem_item_ops, | ||
570 | .ct_attrs = eem_attrs, | ||
571 | .ct_owner = THIS_MODULE, | ||
572 | }; | ||
573 | |||
536 | static void eem_free_inst(struct usb_function_instance *f) | 574 | static void eem_free_inst(struct usb_function_instance *f) |
537 | { | 575 | { |
538 | struct f_eem_opts *opts; | 576 | struct f_eem_opts *opts; |
@@ -552,20 +590,28 @@ static struct usb_function_instance *eem_alloc_inst(void) | |||
552 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | 590 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
553 | if (!opts) | 591 | if (!opts) |
554 | return ERR_PTR(-ENOMEM); | 592 | return ERR_PTR(-ENOMEM); |
593 | mutex_init(&opts->lock); | ||
555 | opts->func_inst.free_func_inst = eem_free_inst; | 594 | opts->func_inst.free_func_inst = eem_free_inst; |
556 | opts->net = gether_setup_default(); | 595 | opts->net = gether_setup_default(); |
557 | if (IS_ERR(opts->net)) | 596 | if (IS_ERR(opts->net)) |
558 | return ERR_CAST(opts->net); | 597 | return ERR_CAST(opts->net); |
559 | 598 | ||
599 | config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type); | ||
600 | |||
560 | return &opts->func_inst; | 601 | return &opts->func_inst; |
561 | } | 602 | } |
562 | 603 | ||
563 | static void eem_free(struct usb_function *f) | 604 | static void eem_free(struct usb_function *f) |
564 | { | 605 | { |
565 | struct f_eem *eem; | 606 | struct f_eem *eem; |
607 | struct f_eem_opts *opts; | ||
566 | 608 | ||
567 | eem = func_to_eem(f); | 609 | eem = func_to_eem(f); |
610 | opts = container_of(f->fi, struct f_eem_opts, func_inst); | ||
568 | kfree(eem); | 611 | kfree(eem); |
612 | mutex_lock(&opts->lock); | ||
613 | opts->refcnt--; | ||
614 | mutex_unlock(&opts->lock); | ||
569 | } | 615 | } |
570 | 616 | ||
571 | static void eem_unbind(struct usb_configuration *c, struct usb_function *f) | 617 | 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 | return ERR_PTR(-ENOMEM); | 632 | return ERR_PTR(-ENOMEM); |
587 | 633 | ||
588 | opts = container_of(fi, struct f_eem_opts, func_inst); | 634 | opts = container_of(fi, struct f_eem_opts, func_inst); |
635 | mutex_lock(&opts->lock); | ||
636 | opts->refcnt++; | ||
589 | 637 | ||
590 | eem->port.ioport = netdev_priv(opts->net); | 638 | eem->port.ioport = netdev_priv(opts->net); |
639 | mutex_unlock(&opts->lock); | ||
591 | eem->port.cdc_filter = DEFAULT_FILTER; | 640 | eem->port.cdc_filter = DEFAULT_FILTER; |
592 | 641 | ||
593 | eem->port.func.name = "cdc_eem"; | 642 | eem->port.func.name = "cdc_eem"; |
diff --git a/drivers/usb/gadget/u_eem.h b/drivers/usb/gadget/u_eem.h index 8f432f2a5e57..e3ae97874c4f 100644 --- a/drivers/usb/gadget/u_eem.h +++ b/drivers/usb/gadget/u_eem.h | |||
@@ -22,6 +22,15 @@ struct f_eem_opts { | |||
22 | struct usb_function_instance func_inst; | 22 | struct usb_function_instance func_inst; |
23 | struct net_device *net; | 23 | struct net_device *net; |
24 | bool bound; | 24 | bool bound; |
25 | |||
26 | /* | ||
27 | * Read/write access to configfs attributes is handled by configfs. | ||
28 | * | ||
29 | * This is to protect the data from concurrent access by read/write | ||
30 | * and create symlink/remove symlink. | ||
31 | */ | ||
32 | struct mutex lock; | ||
33 | int refcnt; | ||
25 | }; | 34 | }; |
26 | 35 | ||
27 | #endif /* U_EEM_H */ | 36 | #endif /* U_EEM_H */ |