diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/cdc2.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/ether.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/f_ecm.c | 149 | ||||
-rw-r--r-- | drivers/usb/gadget/g_ffs.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/multi.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/nokia.c | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/u_ecm.h | 27 |
9 files changed, 174 insertions, 14 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bf7ad7317b5d..6f1afd7553e0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -514,6 +514,9 @@ config USB_F_OBEX | |||
514 | config USB_F_NCM | 514 | config USB_F_NCM |
515 | tristate | 515 | tristate |
516 | 516 | ||
517 | config USB_F_ECM | ||
518 | tristate | ||
519 | |||
517 | choice | 520 | choice |
518 | tristate "USB Gadget Drivers" | 521 | tristate "USB Gadget Drivers" |
519 | default USB_ETH | 522 | default USB_ETH |
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 34b117eec36e..66152f513afd 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -50,6 +50,8 @@ u_rndis-y := rndis.o | |||
50 | obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o | 50 | obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o |
51 | usb_f_ncm-y := f_ncm.o | 51 | usb_f_ncm-y := f_ncm.o |
52 | obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o | 52 | obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o |
53 | usb_f_ecm-y := f_ecm.o | ||
54 | obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o | ||
53 | 55 | ||
54 | # | 56 | # |
55 | # USB gadget drivers | 57 | # USB gadget drivers |
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index bffa997fd040..ceedaf7cabc6 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c | |||
@@ -44,6 +44,7 @@ USB_ETHERNET_MODULE_PARAMETERS(); | |||
44 | * the runtime footprint, and giving us at least some parts of what | 44 | * the runtime footprint, and giving us at least some parts of what |
45 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 45 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
46 | */ | 46 | */ |
47 | #define USBF_ECM_INCLUDED | ||
47 | #include "f_ecm.c" | 48 | #include "f_ecm.c" |
48 | 49 | ||
49 | /*-------------------------------------------------------------------------*/ | 50 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 6bff24f193a2..862ef656e8a1 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c | |||
@@ -102,6 +102,7 @@ static inline bool has_rndis(void) | |||
102 | * the runtime footprint, and giving us at least some parts of what | 102 | * the runtime footprint, and giving us at least some parts of what |
103 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 103 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
104 | */ | 104 | */ |
105 | #define USBF_ECM_INCLUDED | ||
105 | #include "f_ecm.c" | 106 | #include "f_ecm.c" |
106 | #include "f_subset.c" | 107 | #include "f_subset.c" |
107 | #ifdef USB_ETH_RNDIS | 108 | #ifdef USB_ETH_RNDIS |
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index abf8a31ae146..1b5aeb280d4b 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c | |||
@@ -14,10 +14,12 @@ | |||
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | ||
17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
18 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
19 | 20 | ||
20 | #include "u_ether.h" | 21 | #include "u_ether.h" |
22 | #include "u_ecm.h" | ||
21 | 23 | ||
22 | 24 | ||
23 | /* | 25 | /* |
@@ -687,6 +689,40 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) | |||
687 | int status; | 689 | int status; |
688 | struct usb_ep *ep; | 690 | struct usb_ep *ep; |
689 | 691 | ||
692 | #ifndef USBF_ECM_INCLUDED | ||
693 | struct f_ecm_opts *ecm_opts; | ||
694 | |||
695 | if (!can_support_ecm(cdev->gadget)) | ||
696 | return -EINVAL; | ||
697 | |||
698 | ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); | ||
699 | |||
700 | /* | ||
701 | * in drivers/usb/gadget/configfs.c:configfs_composite_bind() | ||
702 | * configurations are bound in sequence with list_for_each_entry, | ||
703 | * in each configuration its functions are bound in sequence | ||
704 | * with list_for_each_entry, so we assume no race condition | ||
705 | * with regard to ecm_opts->bound access | ||
706 | */ | ||
707 | if (!ecm_opts->bound) { | ||
708 | gether_set_gadget(ecm_opts->net, cdev->gadget); | ||
709 | status = gether_register_netdev(ecm_opts->net); | ||
710 | if (status) | ||
711 | return status; | ||
712 | ecm_opts->bound = true; | ||
713 | } | ||
714 | #endif | ||
715 | if (ecm_string_defs[0].id == 0) { | ||
716 | status = usb_string_ids_tab(c->cdev, ecm_string_defs); | ||
717 | if (status) | ||
718 | return status; | ||
719 | |||
720 | ecm_control_intf.iInterface = ecm_string_defs[0].id; | ||
721 | ecm_data_intf.iInterface = ecm_string_defs[2].id; | ||
722 | ecm_desc.iMACAddress = ecm_string_defs[1].id; | ||
723 | ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; | ||
724 | } | ||
725 | |||
690 | /* allocate instance-specific interface IDs */ | 726 | /* allocate instance-specific interface IDs */ |
691 | status = usb_interface_id(c, f); | 727 | status = usb_interface_id(c, f); |
692 | if (status < 0) | 728 | if (status < 0) |
@@ -796,8 +832,10 @@ fail: | |||
796 | return status; | 832 | return status; |
797 | } | 833 | } |
798 | 834 | ||
835 | #ifdef USBF_ECM_INCLUDED | ||
836 | |||
799 | static void | 837 | static void |
800 | ecm_unbind(struct usb_configuration *c, struct usb_function *f) | 838 | ecm_old_unbind(struct usb_configuration *c, struct usb_function *f) |
801 | { | 839 | { |
802 | struct f_ecm *ecm = func_to_ecm(f); | 840 | struct f_ecm *ecm = func_to_ecm(f); |
803 | 841 | ||
@@ -834,17 +872,6 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | |||
834 | if (!can_support_ecm(c->cdev->gadget) || !ethaddr) | 872 | if (!can_support_ecm(c->cdev->gadget) || !ethaddr) |
835 | return -EINVAL; | 873 | return -EINVAL; |
836 | 874 | ||
837 | if (ecm_string_defs[0].id == 0) { | ||
838 | status = usb_string_ids_tab(c->cdev, ecm_string_defs); | ||
839 | if (status) | ||
840 | return status; | ||
841 | |||
842 | ecm_control_intf.iInterface = ecm_string_defs[0].id; | ||
843 | ecm_data_intf.iInterface = ecm_string_defs[2].id; | ||
844 | ecm_desc.iMACAddress = ecm_string_defs[1].id; | ||
845 | ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; | ||
846 | } | ||
847 | |||
848 | /* allocate and initialize one new instance */ | 875 | /* allocate and initialize one new instance */ |
849 | ecm = kzalloc(sizeof *ecm, GFP_KERNEL); | 876 | ecm = kzalloc(sizeof *ecm, GFP_KERNEL); |
850 | if (!ecm) | 877 | if (!ecm) |
@@ -861,7 +888,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | |||
861 | ecm->port.func.strings = ecm_strings; | 888 | ecm->port.func.strings = ecm_strings; |
862 | /* descriptors are per-instance copies */ | 889 | /* descriptors are per-instance copies */ |
863 | ecm->port.func.bind = ecm_bind; | 890 | ecm->port.func.bind = ecm_bind; |
864 | ecm->port.func.unbind = ecm_unbind; | 891 | ecm->port.func.unbind = ecm_old_unbind; |
865 | ecm->port.func.set_alt = ecm_set_alt; | 892 | ecm->port.func.set_alt = ecm_set_alt; |
866 | ecm->port.func.get_alt = ecm_get_alt; | 893 | ecm->port.func.get_alt = ecm_get_alt; |
867 | ecm->port.func.setup = ecm_setup; | 894 | ecm->port.func.setup = ecm_setup; |
@@ -872,3 +899,99 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | |||
872 | kfree(ecm); | 899 | kfree(ecm); |
873 | return status; | 900 | return status; |
874 | } | 901 | } |
902 | |||
903 | #else | ||
904 | |||
905 | static void ecm_free_inst(struct usb_function_instance *f) | ||
906 | { | ||
907 | struct f_ecm_opts *opts; | ||
908 | |||
909 | opts = container_of(f, struct f_ecm_opts, func_inst); | ||
910 | if (opts->bound) | ||
911 | gether_cleanup(netdev_priv(opts->net)); | ||
912 | else | ||
913 | free_netdev(opts->net); | ||
914 | kfree(opts); | ||
915 | } | ||
916 | |||
917 | static struct usb_function_instance *ecm_alloc_inst(void) | ||
918 | { | ||
919 | struct f_ecm_opts *opts; | ||
920 | |||
921 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
922 | if (!opts) | ||
923 | return ERR_PTR(-ENOMEM); | ||
924 | |||
925 | opts->func_inst.free_func_inst = ecm_free_inst; | ||
926 | opts->net = gether_setup_default(); | ||
927 | if (IS_ERR(opts->net)) | ||
928 | return ERR_PTR(PTR_ERR(opts->net)); | ||
929 | |||
930 | return &opts->func_inst; | ||
931 | } | ||
932 | |||
933 | static void ecm_free(struct usb_function *f) | ||
934 | { | ||
935 | struct f_ecm *ecm; | ||
936 | |||
937 | ecm = func_to_ecm(f); | ||
938 | kfree(ecm); | ||
939 | } | ||
940 | |||
941 | static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) | ||
942 | { | ||
943 | struct f_ecm *ecm = func_to_ecm(f); | ||
944 | |||
945 | DBG(c->cdev, "ecm unbind\n"); | ||
946 | |||
947 | ecm_string_defs[0].id = 0; | ||
948 | usb_free_all_descriptors(f); | ||
949 | |||
950 | kfree(ecm->notify_req->buf); | ||
951 | usb_ep_free_request(ecm->notify, ecm->notify_req); | ||
952 | } | ||
953 | |||
954 | struct usb_function *ecm_alloc(struct usb_function_instance *fi) | ||
955 | { | ||
956 | struct f_ecm *ecm; | ||
957 | struct f_ecm_opts *opts; | ||
958 | int status; | ||
959 | |||
960 | /* allocate and initialize one new instance */ | ||
961 | ecm = kzalloc(sizeof(*ecm), GFP_KERNEL); | ||
962 | if (!ecm) | ||
963 | return ERR_PTR(-ENOMEM); | ||
964 | |||
965 | opts = container_of(fi, struct f_ecm_opts, func_inst); | ||
966 | |||
967 | /* export host's Ethernet address in CDC format */ | ||
968 | status = gether_get_host_addr_cdc(opts->net, ecm->ethaddr, | ||
969 | sizeof(ecm->ethaddr)); | ||
970 | if (status < 12) { | ||
971 | kfree(ecm); | ||
972 | return ERR_PTR(-EINVAL); | ||
973 | } | ||
974 | ecm_string_defs[1].s = ecm->ethaddr; | ||
975 | |||
976 | ecm->port.ioport = netdev_priv(opts->net); | ||
977 | ecm->port.cdc_filter = DEFAULT_FILTER; | ||
978 | |||
979 | ecm->port.func.name = "cdc_ethernet"; | ||
980 | ecm->port.func.strings = ecm_strings; | ||
981 | /* descriptors are per-instance copies */ | ||
982 | ecm->port.func.bind = ecm_bind; | ||
983 | ecm->port.func.unbind = ecm_unbind; | ||
984 | ecm->port.func.set_alt = ecm_set_alt; | ||
985 | ecm->port.func.get_alt = ecm_get_alt; | ||
986 | ecm->port.func.setup = ecm_setup; | ||
987 | ecm->port.func.disable = ecm_disable; | ||
988 | ecm->port.func.free_func = ecm_free; | ||
989 | |||
990 | return &ecm->port.func; | ||
991 | } | ||
992 | |||
993 | DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc); | ||
994 | MODULE_LICENSE("GPL"); | ||
995 | MODULE_AUTHOR("David Brownell"); | ||
996 | |||
997 | #endif | ||
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index fbfdb53a2db5..d38a073efd5d 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | # define USB_ETH_RNDIS y | 28 | # define USB_ETH_RNDIS y |
29 | # endif | 29 | # endif |
30 | 30 | ||
31 | #define USBF_ECM_INCLUDED | ||
31 | # include "f_ecm.c" | 32 | # include "f_ecm.c" |
32 | # include "f_subset.c" | 33 | # include "f_subset.c" |
33 | # ifdef USB_ETH_RNDIS | 34 | # ifdef USB_ETH_RNDIS |
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index ce21e9f8203e..61643938d36b 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c | |||
@@ -43,6 +43,7 @@ MODULE_LICENSE("GPL"); | |||
43 | */ | 43 | */ |
44 | #include "f_mass_storage.c" | 44 | #include "f_mass_storage.c" |
45 | 45 | ||
46 | #define USBF_ECM_INCLUDED | ||
46 | #include "f_ecm.c" | 47 | #include "f_ecm.c" |
47 | #include "f_subset.c" | 48 | #include "f_subset.c" |
48 | #ifdef USB_ETH_RNDIS | 49 | #ifdef USB_ETH_RNDIS |
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 39f6cb5f984d..8e42c88b453b 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c | |||
@@ -37,8 +37,9 @@ | |||
37 | * the runtime footprint, and giving us at least some parts of what | 37 | * the runtime footprint, and giving us at least some parts of what |
38 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 38 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
39 | */ | 39 | */ |
40 | #define USBF_OBEX_INCLUDED | 40 | #define USBF_ECM_INCLUDED |
41 | #include "f_ecm.c" | 41 | #include "f_ecm.c" |
42 | #define USBF_OBEX_INCLUDED | ||
42 | #include "f_obex.c" | 43 | #include "f_obex.c" |
43 | #include "f_phonet.c" | 44 | #include "f_phonet.c" |
44 | #include "u_ether.h" | 45 | #include "u_ether.h" |
diff --git a/drivers/usb/gadget/u_ecm.h b/drivers/usb/gadget/u_ecm.h new file mode 100644 index 000000000000..99b6b995988f --- /dev/null +++ b/drivers/usb/gadget/u_ecm.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * u_ecm.h | ||
3 | * | ||
4 | * Utility definitions for the ecm function | ||
5 | * | ||
6 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | ||
7 | * http://www.samsung.com | ||
8 | * | ||
9 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef U_ECM_H | ||
17 | #define U_ECM_H | ||
18 | |||
19 | #include <linux/usb/composite.h> | ||
20 | |||
21 | struct f_ecm_opts { | ||
22 | struct usb_function_instance func_inst; | ||
23 | struct net_device *net; | ||
24 | bool bound; | ||
25 | }; | ||
26 | |||
27 | #endif /* U_ECM_H */ | ||