diff options
-rw-r--r-- | Documentation/ABI/testing/configfs-usb-gadget-rndis | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 49 | ||||
-rw-r--r-- | drivers/usb/gadget/u_rndis.h | 9 |
4 files changed, 87 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis new file mode 100644 index 000000000000..ff127ddb807c --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis | |||
@@ -0,0 +1,14 @@ | |||
1 | What: /config/usb-gadget/gadget/functions/rndis.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 19373a300ec4..b6cd4bd74cb2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -560,6 +560,22 @@ config USB_CONFIGFS_ECM_SUBSET | |||
560 | On hardware that can't implement the full protocol, | 560 | On hardware that can't implement the full protocol, |
561 | a simple CDC subset is used, placing fewer demands on USB. | 561 | a simple CDC subset is used, placing fewer demands on USB. |
562 | 562 | ||
563 | config USB_CONFIGFS_RNDIS | ||
564 | bool "RNDIS" | ||
565 | depends on USB_CONFIGFS | ||
566 | depends on NET | ||
567 | select USB_U_ETHER | ||
568 | select USB_F_RNDIS | ||
569 | help | ||
570 | Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, | ||
571 | and Microsoft provides redistributable binary RNDIS drivers for | ||
572 | older versions of Windows. | ||
573 | |||
574 | To make MS-Windows work with this, use Documentation/usb/linux.inf | ||
575 | as the "driver info file". For versions of MS-Windows older than | ||
576 | XP, you'll need to download drivers from Microsoft's website; a URL | ||
577 | is given in comments found in that info file. | ||
578 | |||
563 | config USB_CONFIGFS_EEM | 579 | config USB_CONFIGFS_EEM |
564 | bool "Ethernet Emulation Model (EEM)" | 580 | bool "Ethernet Emulation Model (EEM)" |
565 | depends on USB_CONFIGFS | 581 | depends on USB_CONFIGFS |
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 4045ca24e7c8..191df35ae69d 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/atomic.h> | 24 | #include <linux/atomic.h> |
25 | 25 | ||
26 | #include "u_ether.h" | 26 | #include "u_ether.h" |
27 | #include "u_ether_configfs.h" | ||
27 | #include "u_rndis.h" | 28 | #include "u_rndis.h" |
28 | #include "rndis.h" | 29 | #include "rndis.h" |
29 | 30 | ||
@@ -903,6 +904,41 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) | |||
903 | } | 904 | } |
904 | EXPORT_SYMBOL(rndis_borrow_net); | 905 | EXPORT_SYMBOL(rndis_borrow_net); |
905 | 906 | ||
907 | static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item) | ||
908 | { | ||
909 | return container_of(to_config_group(item), struct f_rndis_opts, | ||
910 | func_inst.group); | ||
911 | } | ||
912 | |||
913 | /* f_rndis_item_ops */ | ||
914 | USB_ETHERNET_CONFIGFS_ITEM(rndis); | ||
915 | |||
916 | /* f_rndis_opts_dev_addr */ | ||
917 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(rndis); | ||
918 | |||
919 | /* f_rndis_opts_host_addr */ | ||
920 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(rndis); | ||
921 | |||
922 | /* f_rndis_opts_qmult */ | ||
923 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); | ||
924 | |||
925 | /* f_rndis_opts_ifname */ | ||
926 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); | ||
927 | |||
928 | static struct configfs_attribute *rndis_attrs[] = { | ||
929 | &f_rndis_opts_dev_addr.attr, | ||
930 | &f_rndis_opts_host_addr.attr, | ||
931 | &f_rndis_opts_qmult.attr, | ||
932 | &f_rndis_opts_ifname.attr, | ||
933 | NULL, | ||
934 | }; | ||
935 | |||
936 | static struct config_item_type rndis_func_type = { | ||
937 | .ct_item_ops = &rndis_item_ops, | ||
938 | .ct_attrs = rndis_attrs, | ||
939 | .ct_owner = THIS_MODULE, | ||
940 | }; | ||
941 | |||
906 | static void rndis_free_inst(struct usb_function_instance *f) | 942 | static void rndis_free_inst(struct usb_function_instance *f) |
907 | { | 943 | { |
908 | struct f_rndis_opts *opts; | 944 | struct f_rndis_opts *opts; |
@@ -924,22 +960,30 @@ static struct usb_function_instance *rndis_alloc_inst(void) | |||
924 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | 960 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
925 | if (!opts) | 961 | if (!opts) |
926 | return ERR_PTR(-ENOMEM); | 962 | return ERR_PTR(-ENOMEM); |
927 | 963 | mutex_init(&opts->lock); | |
928 | opts->func_inst.free_func_inst = rndis_free_inst; | 964 | opts->func_inst.free_func_inst = rndis_free_inst; |
929 | opts->net = gether_setup_default(); | 965 | opts->net = gether_setup_default(); |
930 | if (IS_ERR(opts->net)) | 966 | if (IS_ERR(opts->net)) |
931 | return ERR_CAST(opts->net); | 967 | return ERR_CAST(opts->net); |
932 | 968 | ||
969 | config_group_init_type_name(&opts->func_inst.group, "", | ||
970 | &rndis_func_type); | ||
971 | |||
933 | return &opts->func_inst; | 972 | return &opts->func_inst; |
934 | } | 973 | } |
935 | 974 | ||
936 | static void rndis_free(struct usb_function *f) | 975 | static void rndis_free(struct usb_function *f) |
937 | { | 976 | { |
938 | struct f_rndis *rndis; | 977 | struct f_rndis *rndis; |
978 | struct f_rndis_opts *opts; | ||
939 | 979 | ||
940 | rndis = func_to_rndis(f); | 980 | rndis = func_to_rndis(f); |
941 | rndis_deregister(rndis->config); | 981 | rndis_deregister(rndis->config); |
982 | opts = container_of(f->fi, struct f_rndis_opts, func_inst); | ||
942 | kfree(rndis); | 983 | kfree(rndis); |
984 | mutex_lock(&opts->lock); | ||
985 | opts->refcnt--; | ||
986 | mutex_unlock(&opts->lock); | ||
943 | } | 987 | } |
944 | 988 | ||
945 | static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) | 989 | static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) |
@@ -964,12 +1008,15 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) | |||
964 | return ERR_PTR(-ENOMEM); | 1008 | return ERR_PTR(-ENOMEM); |
965 | 1009 | ||
966 | opts = container_of(fi, struct f_rndis_opts, func_inst); | 1010 | opts = container_of(fi, struct f_rndis_opts, func_inst); |
1011 | mutex_lock(&opts->lock); | ||
1012 | opts->refcnt++; | ||
967 | 1013 | ||
968 | gether_get_host_addr_u8(opts->net, rndis->ethaddr); | 1014 | gether_get_host_addr_u8(opts->net, rndis->ethaddr); |
969 | rndis->vendorID = opts->vendor_id; | 1015 | rndis->vendorID = opts->vendor_id; |
970 | rndis->manufacturer = opts->manufacturer; | 1016 | rndis->manufacturer = opts->manufacturer; |
971 | 1017 | ||
972 | rndis->port.ioport = netdev_priv(opts->net); | 1018 | rndis->port.ioport = netdev_priv(opts->net); |
1019 | mutex_unlock(&opts->lock); | ||
973 | /* RNDIS activates when the host changes this filter */ | 1020 | /* RNDIS activates when the host changes this filter */ |
974 | rndis->port.cdc_filter = 0; | 1021 | rndis->port.cdc_filter = 0; |
975 | 1022 | ||
diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h index d274df56ce75..c62ba82e9600 100644 --- a/drivers/usb/gadget/u_rndis.h +++ b/drivers/usb/gadget/u_rndis.h | |||
@@ -25,6 +25,15 @@ struct f_rndis_opts { | |||
25 | struct net_device *net; | 25 | struct net_device *net; |
26 | bool bound; | 26 | bool bound; |
27 | bool borrowed_net; | 27 | bool borrowed_net; |
28 | |||
29 | /* | ||
30 | * Read/write access to configfs attributes is handled by configfs. | ||
31 | * | ||
32 | * This is to protect the data from concurrent access by read/write | ||
33 | * and create symlink/remove symlink. | ||
34 | */ | ||
35 | struct mutex lock; | ||
36 | int refcnt; | ||
28 | }; | 37 | }; |
29 | 38 | ||
30 | void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); | 39 | void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); |