aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget-rndis14
-rw-r--r--drivers/usb/gadget/Kconfig16
-rw-r--r--drivers/usb/gadget/f_rndis.c49
-rw-r--r--drivers/usb/gadget/u_rndis.h9
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 @@
1What: /config/usb-gadget/gadget/functions/rndis.name
2Date: May 2013
3KenelVersion: 3.11
4Description:
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
563config 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
563config USB_CONFIGFS_EEM 579config 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}
904EXPORT_SYMBOL(rndis_borrow_net); 905EXPORT_SYMBOL(rndis_borrow_net);
905 906
907static 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 */
914USB_ETHERNET_CONFIGFS_ITEM(rndis);
915
916/* f_rndis_opts_dev_addr */
917USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(rndis);
918
919/* f_rndis_opts_host_addr */
920USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(rndis);
921
922/* f_rndis_opts_qmult */
923USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);
924
925/* f_rndis_opts_ifname */
926USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis);
927
928static 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
936static 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
906static void rndis_free_inst(struct usb_function_instance *f) 942static 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
936static void rndis_free(struct usb_function *f) 975static 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
945static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) 989static 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
30void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); 39void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);