From d400f209b4afe4a196baac276128eccac6a11b31 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 16 May 2013 19:42:55 +0530 Subject: ARM: tegra: finalize USB EHCI and PHY bindings The existing Tegra USB bindings have a few issues: 1) Many properties are documented as being part of the EHCI controller node, yet they apply more to the PHY device. They should be moved. 2) Some registers in PHY1 are shared with PHY3, and hence PHY3 needs a reg entry to point at PHY1's register space. We can't assume the PHY1 driver is present, so the PHY3 driver will directly access those registers. 3) The list of clocks required by the PHY was missing some required entries. 4) UTMI PHY Timing parameters are added 5) VBUS control is now specified using a regulator rather than a plain GPIO 6) Added nvidia,is-wired property to indicate whether the device is hard wired on the board, or pluggable. This patch fixes the binding definition to resolve these issues. Signed-off-by: Venu Byravarasu Signed-off-by: Stephen Warren --- .../bindings/usb/nvidia,tegra20-ehci.txt | 27 +++----------- .../bindings/usb/nvidia,tegra20-usb-phy.txt | 41 ++++++++++++++++++++-- 2 files changed, 43 insertions(+), 25 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index 34c952883276..df0933043a5b 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -6,27 +6,10 @@ Practice : Universal Serial Bus" with the following modifications and additions : Required properties : - - compatible : Should be "nvidia,tegra20-ehci" for USB controllers - used in host mode. - - phy_type : Should be one of "ulpi" or "utmi". - - nvidia,vbus-gpio : If present, specifies a gpio that needs to be - activated for the bus to be powered. - - nvidia,phy : phandle of the PHY instance, the controller is connected to. - -Required properties for phy_type == ulpi: - - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. + - compatible : Should be "nvidia,tegra20-ehci". + - nvidia,phy : phandle of the PHY that the controller is connected to. + - clocks : Contains a single entry which defines the USB controller's clock. Optional properties: - - dr_mode : dual role mode. Indicates the working mode for - nvidia,tegra20-ehci compatible controllers. Can be "host", "peripheral", - or "otg". Default to "host" if not defined for backward compatibility. - host means this is a host controller - peripheral means it is device controller - otg means it can operate as either ("on the go") - - nvidia,has-legacy-mode : boolean indicates whether this controller can - operate in legacy mode (as APX 2500 / 2600). In legacy mode some - registers are accessed through the APB_MISC base address instead of - the USB controller. Since this is a legacy issue it probably does not - warrant a compatible string of its own. - - nvidia,needs-double-reset : boolean is to be set for some of the Tegra2 - USB ports, which need reset twice due to hardware issues. + - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 + USB ports, which need reset twice due to hardware issues. diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt index 6bdaba2f0aa1..c4c9e9e664aa 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt @@ -4,14 +4,49 @@ The device node for Tegra SOC USB PHY: Required properties : - compatible : Should be "nvidia,tegra20-usb-phy". - - reg : Address and length of the register set for the USB PHY interface. - - phy_type : Should be one of "ulpi" or "utmi". + - reg : Defines the following set of registers, in the order listed: + - The PHY's own register set. + Always present. + - The register set of the PHY containing the UTMI pad control registers. + Present if-and-only-if phy_type == utmi. + - phy_type : Should be one of "utmi", "ulpi" or "hsic". + - clocks : Defines the clocks listed in the clock-names property. + - clock-names : The following clock names must be present: + - reg: The clock needed to access the PHY's own registers. This is the + associated EHCI controller's clock. Always present. + - pll_u: PLL_U. Always present. + - timer: The timeout clock (clk_m). Present if phy_type == utmi. + - utmi-pads: The clock needed to access the UTMI pad control registers. + Present if phy_type == utmi. + - ulpi-link: The clock Tegra provides to the ULPI PHY (cdev2). + Present if phy_type == ulpi, and ULPI link mode is in use. Required properties for phy_type == ulpi: - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. +Required PHY timing params for utmi phy: + - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before + start of sync launches RxActive + - nvidia,elastic-limit : Variable FIFO Depth of elastic input store + - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait + before declare IDLE. + - nvidia,term-range-adj : Range adjusment on terminations + - nvidia,xcvr-setup : HS driver output control + - nvidia,xcvr-lsfslew : LS falling slew rate control. + - nvidia,xcvr-lsrslew : LS rising slew rate control. + Optional properties: - nvidia,has-legacy-mode : boolean indicates whether this controller can operate in legacy mode (as APX 2500 / 2600). In legacy mode some registers are accessed through the APB_MISC base address instead of - the USB controller. \ No newline at end of file + the USB controller. + - nvidia,is-wired : boolean. Indicates whether we can do certain kind of power + optimizations for the devices that are always connected. e.g. modem. + - dr_mode : dual role mode. Indicates the working mode for the PHY. Can be + "host", "peripheral", or "otg". Defaults to "host" if not defined. + host means this is a host controller + peripheral means it is device controller + otg means it can operate as either ("on the go") + +Required properties for dr_mode == otg: + - vbus-supply: regulator for VBUS -- cgit v1.2.3 From 83408745b202695e8911d71a9854c517e565c343 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 23 May 2013 10:51:15 +0200 Subject: usb: gadget: f_phonet: add configfs support f_phonet learns about configfs so we can remove in-kernel gadget drivers. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-phonet | 8 ++++ drivers/usb/gadget/Kconfig | 10 ++++ drivers/usb/gadget/f_phonet.c | 56 ++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-phonet (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-phonet b/Documentation/ABI/testing/configfs-usb-gadget-phonet new file mode 100644 index 000000000000..19b67d3eab94 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-phonet @@ -0,0 +1,8 @@ +What: /config/usb-gadget/gadget/functions/phonet.name +Date: May 2013 +KenelVersion: 3.11 +Description: + + This item contains just one readonly attribute: ifname. + It contains the network interface name assigned during + network device registration. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5022c2d3e365..d6c4e601d711 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -541,6 +541,16 @@ choice # this first set of drivers all depend on bulk-capable hardware. +config USB_CONFIGFS_PHONET + boolean "Phonet protocol" + depends on USB_CONFIGFS + depends on NET + depends on PHONET + select USB_U_ETHER + select USB_F_PHONET + help + The Phonet protocol implementation for USB device. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 5dd774876168..7944fb0efe3b 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -26,6 +26,7 @@ #include #include "u_phonet.h" +#include "u_ether.h" #define PN_MEDIA_USB 0x1B #define MAXPACKET 512 @@ -581,6 +582,58 @@ err: return status; } +static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_phonet_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_phonet_opts); +static ssize_t f_phonet_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct f_phonet_opts *opts = to_f_phonet_opts(item); + struct f_phonet_opts_attribute *f_phonet_opts_attr = + container_of(attr, struct f_phonet_opts_attribute, attr); + ssize_t ret = 0; + + if (f_phonet_opts_attr->show) + ret = f_phonet_opts_attr->show(opts, page); + return ret; +} + +static void phonet_attr_release(struct config_item *item) +{ + struct f_phonet_opts *opts = to_f_phonet_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations phonet_item_ops = { + .release = phonet_attr_release, + .show_attribute = f_phonet_attr_show, +}; + +static ssize_t f_phonet_ifname_show(struct f_phonet_opts *opts, char *page) +{ + return gether_get_ifname(opts->net, page, PAGE_SIZE); +} + +static struct f_phonet_opts_attribute f_phonet_ifname = + __CONFIGFS_ATTR_RO(ifname, f_phonet_ifname_show); + +static struct configfs_attribute *phonet_attrs[] = { + &f_phonet_ifname.attr, + NULL, +}; + +static struct config_item_type phonet_func_type = { + .ct_item_ops = &phonet_item_ops, + .ct_attrs = phonet_attrs, + .ct_owner = THIS_MODULE, +}; + static void phonet_free_inst(struct usb_function_instance *f) { struct f_phonet_opts *opts; @@ -606,6 +659,9 @@ static struct usb_function_instance *phonet_alloc_inst(void) if (IS_ERR(opts->net)) return ERR_PTR(PTR_ERR(opts->net)); + config_group_init_type_name(&opts->func_inst.group, "", + &phonet_func_type); + return &opts->func_inst; } -- cgit v1.2.3 From 17b80976f0aa28842593dae8b05fae9274b51375 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:51 +0200 Subject: 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: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-eem | 14 +++++++ drivers/usb/gadget/Kconfig | 15 +++++++ drivers/usb/gadget/f_eem.c | 49 +++++++++++++++++++++++ drivers/usb/gadget/u_eem.h | 9 +++++ 4 files changed, 87 insertions(+) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-eem (limited to 'Documentation') 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 @@ +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 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 # 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 boolean "Phonet protocol" 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 @@ #include #include "u_ether.h" +#include "u_ether_configfs.h" #include "u_eem.h" #define EEM_HLEN 2 @@ -263,8 +264,10 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) * with regard to eem_opts->bound access */ if (!eem_opts->bound) { + mutex_lock(&eem_opts->lock); gether_set_gadget(eem_opts->net, cdev->gadget); status = gether_register_netdev(eem_opts->net); + mutex_unlock(&eem_opts->lock); if (status) return status; eem_opts->bound = true; @@ -533,6 +536,41 @@ error: 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) { struct f_eem_opts *opts; @@ -552,20 +590,28 @@ static struct usb_function_instance *eem_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); + mutex_init(&opts->lock); opts->func_inst.free_func_inst = eem_free_inst; opts->net = gether_setup_default(); if (IS_ERR(opts->net)) return ERR_CAST(opts->net); + config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type); + return &opts->func_inst; } static void eem_free(struct usb_function *f) { struct f_eem *eem; + struct f_eem_opts *opts; eem = func_to_eem(f); + opts = container_of(f->fi, struct f_eem_opts, func_inst); kfree(eem); + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); } 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) return ERR_PTR(-ENOMEM); opts = container_of(fi, struct f_eem_opts, func_inst); + mutex_lock(&opts->lock); + opts->refcnt++; eem->port.ioport = netdev_priv(opts->net); + mutex_unlock(&opts->lock); eem->port.cdc_filter = DEFAULT_FILTER; 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 { struct usb_function_instance func_inst; struct net_device *net; 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 */ -- cgit v1.2.3 From 02832e56f88a981474ee4c7c141f46fc1b4454f4 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:56 +0200 Subject: usb: gadget: f_subset: add configfs support f_subset learns about configfs so we can, eventually, remove in-kernel gadget drivers. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-subset | 14 +++++++ drivers/usb/gadget/Kconfig | 10 +++++ drivers/usb/gadget/f_subset.c | 46 +++++++++++++++++++++- drivers/usb/gadget/u_gether.h | 9 +++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-subset (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-subset b/Documentation/ABI/testing/configfs-usb-gadget-subset new file mode 100644 index 000000000000..f47170a2f7dc --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-subset @@ -0,0 +1,14 @@ +What: /config/usb-gadget/gadget/functions/geth.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 diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 0a444f39109f..3a72b9dbf7f0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -547,6 +547,16 @@ choice # this first set of drivers all depend on bulk-capable hardware. +config USB_CONFIGFS_ECM_SUBSET + boolean "Ethernet Control Model (CDC ECM) subset" + depends on USB_CONFIGFS + depends on NET + select USB_U_ETHER + select USB_F_SUBSET + help + On hardware that can't implement the full protocol, + a simple CDC subset is used, placing fewer demands on USB. + config USB_CONFIGFS_EEM bool "Ethernet Emulation Model (EEM)" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 089881a530d5..fbc7a24942e4 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -17,6 +17,7 @@ #include #include "u_ether.h" +#include "u_ether_configfs.h" #include "u_gether.h" /* @@ -313,8 +314,10 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) * with regard to gether_opts->bound access */ if (!gether_opts->bound) { + mutex_lock(&gether_opts->lock); gether_set_gadget(gether_opts->net, cdev->gadget); status = gether_register_netdev(gether_opts->net); + mutex_unlock(&gether_opts->lock); if (status) return status; gether_opts->bound = true; @@ -445,6 +448,41 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], #else +static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_gether_opts, + func_inst.group); +} + +/* f_gether_item_ops */ +USB_ETHERNET_CONFIGFS_ITEM(gether); + +/* f_gether_opts_dev_addr */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(gether); + +/* f_gether_opts_host_addr */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(gether); + +/* f_gether_opts_qmult */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(gether); + +/* f_gether_opts_ifname */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(gether); + +static struct configfs_attribute *gether_attrs[] = { + &f_gether_opts_dev_addr.attr, + &f_gether_opts_host_addr.attr, + &f_gether_opts_qmult.attr, + &f_gether_opts_ifname.attr, + NULL, +}; + +static struct config_item_type gether_func_type = { + .ct_item_ops = &gether_item_ops, + .ct_attrs = gether_attrs, + .ct_owner = THIS_MODULE, +}; + static void geth_free_inst(struct usb_function_instance *f) { struct f_gether_opts *opts; @@ -464,12 +502,15 @@ static struct usb_function_instance *geth_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); - + mutex_init(&opts->lock); opts->func_inst.free_func_inst = geth_free_inst; opts->net = gether_setup_default(); if (IS_ERR(opts->net)) return ERR_CAST(opts->net); + config_group_init_type_name(&opts->func_inst.group, "", + &gether_func_type); + return &opts->func_inst; } @@ -500,6 +541,8 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_gether_opts, func_inst); + mutex_lock(&opts->lock); + opts->refcnt++; /* export host's Ethernet address in CDC format */ status = gether_get_host_addr_cdc(opts->net, geth->ethaddr, sizeof(geth->ethaddr)); @@ -510,6 +553,7 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi) geth_string_defs[1].s = geth->ethaddr; geth->port.ioport = netdev_priv(opts->net); + mutex_unlock(&opts->lock); geth->port.cdc_filter = DEFAULT_FILTER; geth->port.func.name = "cdc_subset"; diff --git a/drivers/usb/gadget/u_gether.h b/drivers/usb/gadget/u_gether.h index 3a4a2bf61cdc..d4078426ba5d 100644 --- a/drivers/usb/gadget/u_gether.h +++ b/drivers/usb/gadget/u_gether.h @@ -22,6 +22,15 @@ struct f_gether_opts { struct usb_function_instance func_inst; struct net_device *net; 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_GETHER_H */ -- cgit v1.2.3 From b3df2faacb40da7d9c4ed1a0b5304cf346e46ca0 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:16:01 +0200 Subject: usb: gadget: f_rndis: add configfs support f_rndis learns about configfs so we can, eventually, remove in-kernel gadget drivers. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-rndis | 14 +++++++ drivers/usb/gadget/Kconfig | 16 +++++++ drivers/usb/gadget/f_rndis.c | 49 +++++++++++++++++++++- drivers/usb/gadget/u_rndis.h | 9 ++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-rndis (limited to 'Documentation') 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 @@ +What: /config/usb-gadget/gadget/functions/rndis.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 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 On hardware that can't implement the full protocol, a simple CDC subset is used, placing fewer demands on USB. +config USB_CONFIGFS_RNDIS + bool "RNDIS" + depends on USB_CONFIGFS + depends on NET + select USB_U_ETHER + select USB_F_RNDIS + help + Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, + and Microsoft provides redistributable binary RNDIS drivers for + older versions of Windows. + + To make MS-Windows work with this, use Documentation/usb/linux.inf + as the "driver info file". For versions of MS-Windows older than + XP, you'll need to download drivers from Microsoft's website; a URL + is given in comments found in that info file. + config USB_CONFIGFS_EEM bool "Ethernet Emulation Model (EEM)" 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 @@ #include #include "u_ether.h" +#include "u_ether_configfs.h" #include "u_rndis.h" #include "rndis.h" @@ -903,6 +904,41 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) } EXPORT_SYMBOL(rndis_borrow_net); +static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_rndis_opts, + func_inst.group); +} + +/* f_rndis_item_ops */ +USB_ETHERNET_CONFIGFS_ITEM(rndis); + +/* f_rndis_opts_dev_addr */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(rndis); + +/* f_rndis_opts_host_addr */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(rndis); + +/* f_rndis_opts_qmult */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis); + +/* f_rndis_opts_ifname */ +USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); + +static struct configfs_attribute *rndis_attrs[] = { + &f_rndis_opts_dev_addr.attr, + &f_rndis_opts_host_addr.attr, + &f_rndis_opts_qmult.attr, + &f_rndis_opts_ifname.attr, + NULL, +}; + +static struct config_item_type rndis_func_type = { + .ct_item_ops = &rndis_item_ops, + .ct_attrs = rndis_attrs, + .ct_owner = THIS_MODULE, +}; + static void rndis_free_inst(struct usb_function_instance *f) { struct f_rndis_opts *opts; @@ -924,22 +960,30 @@ static struct usb_function_instance *rndis_alloc_inst(void) opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); - + mutex_init(&opts->lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); if (IS_ERR(opts->net)) return ERR_CAST(opts->net); + config_group_init_type_name(&opts->func_inst.group, "", + &rndis_func_type); + return &opts->func_inst; } static void rndis_free(struct usb_function *f) { struct f_rndis *rndis; + struct f_rndis_opts *opts; rndis = func_to_rndis(f); rndis_deregister(rndis->config); + opts = container_of(f->fi, struct f_rndis_opts, func_inst); kfree(rndis); + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); } 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) return ERR_PTR(-ENOMEM); opts = container_of(fi, struct f_rndis_opts, func_inst); + mutex_lock(&opts->lock); + opts->refcnt++; gether_get_host_addr_u8(opts->net, rndis->ethaddr); rndis->vendorID = opts->vendor_id; rndis->manufacturer = opts->manufacturer; rndis->port.ioport = netdev_priv(opts->net); + mutex_unlock(&opts->lock); /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; 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 { struct net_device *net; bool bound; bool borrowed_net; + + /* + * 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; }; void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); -- cgit v1.2.3