From f1a1823ff24fa4e3412b5078f20021cf40834946 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 23 May 2013 09:22:03 +0200 Subject: usb: gadget: u_ether: convert into module u_ether.c has been #include'd by all gadgets which implement USB Ethernet functions. In order to add configfs support, the f_ecm.c, f_eem.c, f_ncm.c, f_subset.c, f_rndis.c need to be converted into modules and must not be #include'd. Consequently, the u_ether.c needs to be a module too, in a manner similar to u_serial.c. The resulting module should not take any parameters, so they are pushed to the current users of it, that is ether.c, g_ffs.c, multi.c, ncm.c, nokia.c. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/ether.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 56c8ecae9bc3..75418c7050fb 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -107,11 +107,12 @@ static inline bool has_rndis(void) #include "rndis.c" #endif #include "f_eem.c" -#include "u_ether.c" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); +USB_ETHERNET_MODULE_PARAMETERS(); + /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ @@ -206,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; -static u8 hostaddr[ETH_ALEN]; +static u8 host_mac[ETH_ALEN]; static struct eth_dev *the_dev; /*-------------------------------------------------------------------------*/ @@ -224,7 +225,7 @@ static int __init rndis_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return rndis_bind_config(c, hostaddr, the_dev); + return rndis_bind_config(c, host_mac, the_dev); } static struct usb_configuration rndis_config_driver = { @@ -259,9 +260,9 @@ static int __init eth_do_config(struct usb_configuration *c) if (use_eem) return eem_bind_config(c, the_dev); else if (can_support_ecm(c->cdev->gadget)) - return ecm_bind_config(c, hostaddr, the_dev); + return ecm_bind_config(c, host_mac, the_dev); else - return geth_bind_config(c, hostaddr, the_dev); + return geth_bind_config(c, host_mac, the_dev); } static struct usb_configuration eth_config_driver = { @@ -279,7 +280,8 @@ static int __init eth_bind(struct usb_composite_dev *cdev) int status; /* set up network link layer */ - the_dev = gether_setup(cdev->gadget, hostaddr); + the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, + qmult); if (IS_ERR(the_dev)) return PTR_ERR(the_dev); -- cgit v1.2.3 From cbbd14a9021140a306a01f8fcaa645faafae18a5 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 24 May 2013 10:23:02 +0200 Subject: usb: gadget: rndis: convert into module In order to convert to configfs the usb functions need to be converted to a new interface and compiled as modules. This patch creates an rndis module which will be used by the new functions. After all users of f_rndis are converted to the new interface, this module can be merged with f_rndis module. Acked-by: Michal Nazarewicz Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 6 ++++++ drivers/usb/gadget/Makefile | 2 ++ drivers/usb/gadget/ether.c | 4 +++- drivers/usb/gadget/g_ffs.c | 2 +- drivers/usb/gadget/multi.c | 2 +- drivers/usb/gadget/rndis.c | 18 ++++++++++++++++++ drivers/usb/gadget/rndis.h | 1 + 7 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d5ae4dff3b90..5345b6895220 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -502,6 +502,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_RNDIS + tristate + config USB_F_SERIAL tristate @@ -599,6 +602,7 @@ config USB_ETH depends on NET select USB_LIBCOMPOSITE select USB_U_ETHER + select USB_U_RNDIS select CRC32 help This driver implements Ethernet style communication, in one of @@ -724,6 +728,7 @@ config USB_FUNCTIONFS_RNDIS bool "Include configuration with RNDIS (Ethernet)" depends on USB_FUNCTIONFS && NET select USB_U_ETHER + select USB_U_RNDIS help Include a configuration with RNDIS function (Ethernet) and the Filesystem. @@ -871,6 +876,7 @@ config USB_G_MULTI select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_U_ETHER + select USB_U_RNDIS select USB_F_ACM help The Multifunction Composite Gadget provides Ethernet (RNDIS diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b6c2bf7a3c2d..7a0463ef3684 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -46,6 +46,8 @@ obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o usb_f_obex-y := f_obex.o obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o obj-$(CONFIG_USB_U_ETHER) += u_ether.o +u_rndis-y := rndis.o +obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o # # USB gadget drivers diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 75418c7050fb..6bff24f193a2 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -91,6 +91,8 @@ static inline bool has_rndis(void) #endif } +#include + /*-------------------------------------------------------------------------*/ /* @@ -104,7 +106,7 @@ static inline bool has_rndis(void) #include "f_subset.c" #ifdef USB_ETH_RNDIS #include "f_rndis.c" -#include "rndis.c" +#include "rndis.h" #endif #include "f_eem.c" diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 45f26be640de..fbfdb53a2db5 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -32,7 +32,7 @@ # include "f_subset.c" # ifdef USB_ETH_RNDIS # include "f_rndis.c" -# include "rndis.c" +# include "rndis.h" # endif # include "u_ether.h" diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index cdb8dbf34c8d..ce21e9f8203e 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -47,7 +47,7 @@ MODULE_LICENSE("GPL"); #include "f_subset.c" #ifdef USB_ETH_RNDIS # include "f_rndis.c" -# include "rndis.c" +# include "rndis.h" #endif #include "u_ether.h" diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 1e4cfb05f70b..8c5e95762e59 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -761,6 +761,7 @@ int rndis_signal_connect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } +EXPORT_SYMBOL(rndis_signal_connect); int rndis_signal_disconnect(int configNr) { @@ -769,6 +770,7 @@ int rndis_signal_disconnect(int configNr) return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } +EXPORT_SYMBOL(rndis_signal_disconnect); void rndis_uninit(int configNr) { @@ -783,11 +785,13 @@ void rndis_uninit(int configNr) while ((buf = rndis_get_next_response(configNr, &length))) rndis_free_response(configNr, buf); } +EXPORT_SYMBOL(rndis_uninit); void rndis_set_host_mac(int configNr, const u8 *addr) { rndis_per_dev_params[configNr].host_mac = addr; } +EXPORT_SYMBOL(rndis_set_host_mac); /* * Message Parser @@ -870,6 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf) return -ENOTSUPP; } +EXPORT_SYMBOL(rndis_msg_parser); int rndis_register(void (*resp_avail)(void *v), void *v) { @@ -891,6 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v) return -ENODEV; } +EXPORT_SYMBOL(rndis_register); void rndis_deregister(int configNr) { @@ -899,6 +905,7 @@ void rndis_deregister(int configNr) if (configNr >= RNDIS_MAX_CONFIGS) return; rndis_per_dev_params[configNr].used = 0; } +EXPORT_SYMBOL(rndis_deregister); int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) { @@ -912,6 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) return 0; } +EXPORT_SYMBOL(rndis_set_param_dev); int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) { @@ -924,6 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) return 0; } +EXPORT_SYMBOL(rndis_set_param_vendor); int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) { @@ -935,6 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) return 0; } +EXPORT_SYMBOL(rndis_set_param_medium); void rndis_add_hdr(struct sk_buff *skb) { @@ -949,6 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb) header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); } +EXPORT_SYMBOL(rndis_add_hdr); void rndis_free_response(int configNr, u8 *buf) { @@ -965,6 +976,7 @@ void rndis_free_response(int configNr, u8 *buf) } } } +EXPORT_SYMBOL(rndis_free_response); u8 *rndis_get_next_response(int configNr, u32 *length) { @@ -986,6 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length) return NULL; } +EXPORT_SYMBOL(rndis_get_next_response); static rndis_resp_t *rndis_add_response(int configNr, u32 length) { @@ -1029,6 +1042,7 @@ int rndis_rm_hdr(struct gether *port, skb_queue_tail(list, skb); return 0; } +EXPORT_SYMBOL(rndis_rm_hdr); #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -1160,6 +1174,7 @@ int rndis_init(void) return 0; } +EXPORT_SYMBOL(rndis_init); void rndis_exit(void) { @@ -1173,3 +1188,6 @@ void rndis_exit(void) } #endif } +EXPORT_SYMBOL(rndis_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 0647f2f34e89..6e796152a7b2 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -16,6 +16,7 @@ #define _LINUX_RNDIS_H #include +#include "u_ether.h" #include "ndis.h" #define RNDIS_MAXIMUM_FRAME_SIZE 1518 -- cgit v1.2.3 From fee562a6450b7806f1fbbe1469a67b5395b5c10a Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 23 May 2013 10:32:03 +0200 Subject: usb: gadget: f_ecm: convert to new function interface with backward compatibility Converting ecm to the new function interface requires converting the USB ecm's function code and its users. This patch converts the f_ecm.c to the new function interface. The file is now compiled into a separate usb_f_ecm.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/cdc2.c | 1 + drivers/usb/gadget/ether.c | 1 + drivers/usb/gadget/f_ecm.c | 149 ++++++++++++++++++++++++++++++++++++++++---- drivers/usb/gadget/g_ffs.c | 1 + drivers/usb/gadget/multi.c | 1 + drivers/usb/gadget/nokia.c | 3 +- drivers/usb/gadget/u_ecm.h | 27 ++++++++ 9 files changed, 174 insertions(+), 14 deletions(-) create mode 100644 drivers/usb/gadget/u_ecm.h (limited to 'drivers/usb/gadget/ether.c') 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 config USB_F_NCM tristate +config USB_F_ECM + tristate + choice tristate "USB Gadget Drivers" 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 obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o usb_f_ncm-y := f_ncm.o obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o +usb_f_ecm-y := f_ecm.o +obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o # # 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(); * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USBF_ECM_INCLUDED #include "f_ecm.c" /*-------------------------------------------------------------------------*/ 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) * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USBF_ECM_INCLUDED #include "f_ecm.c" #include "f_subset.c" #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 @@ #include #include +#include #include #include #include "u_ether.h" +#include "u_ecm.h" /* @@ -687,6 +689,40 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) int status; struct usb_ep *ep; +#ifndef USBF_ECM_INCLUDED + struct f_ecm_opts *ecm_opts; + + if (!can_support_ecm(cdev->gadget)) + return -EINVAL; + + ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); + + /* + * in drivers/usb/gadget/configfs.c:configfs_composite_bind() + * configurations are bound in sequence with list_for_each_entry, + * in each configuration its functions are bound in sequence + * with list_for_each_entry, so we assume no race condition + * with regard to ecm_opts->bound access + */ + if (!ecm_opts->bound) { + gether_set_gadget(ecm_opts->net, cdev->gadget); + status = gether_register_netdev(ecm_opts->net); + if (status) + return status; + ecm_opts->bound = true; + } +#endif + if (ecm_string_defs[0].id == 0) { + status = usb_string_ids_tab(c->cdev, ecm_string_defs); + if (status) + return status; + + ecm_control_intf.iInterface = ecm_string_defs[0].id; + ecm_data_intf.iInterface = ecm_string_defs[2].id; + ecm_desc.iMACAddress = ecm_string_defs[1].id; + ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; + } + /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) @@ -796,8 +832,10 @@ fail: return status; } +#ifdef USBF_ECM_INCLUDED + static void -ecm_unbind(struct usb_configuration *c, struct usb_function *f) +ecm_old_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ecm *ecm = func_to_ecm(f); @@ -834,17 +872,6 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], if (!can_support_ecm(c->cdev->gadget) || !ethaddr) return -EINVAL; - if (ecm_string_defs[0].id == 0) { - status = usb_string_ids_tab(c->cdev, ecm_string_defs); - if (status) - return status; - - ecm_control_intf.iInterface = ecm_string_defs[0].id; - ecm_data_intf.iInterface = ecm_string_defs[2].id; - ecm_desc.iMACAddress = ecm_string_defs[1].id; - ecm_iad_descriptor.iFunction = ecm_string_defs[3].id; - } - /* allocate and initialize one new instance */ ecm = kzalloc(sizeof *ecm, GFP_KERNEL); if (!ecm) @@ -861,7 +888,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], ecm->port.func.strings = ecm_strings; /* descriptors are per-instance copies */ ecm->port.func.bind = ecm_bind; - ecm->port.func.unbind = ecm_unbind; + ecm->port.func.unbind = ecm_old_unbind; ecm->port.func.set_alt = ecm_set_alt; ecm->port.func.get_alt = ecm_get_alt; ecm->port.func.setup = ecm_setup; @@ -872,3 +899,99 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], kfree(ecm); return status; } + +#else + +static void ecm_free_inst(struct usb_function_instance *f) +{ + struct f_ecm_opts *opts; + + opts = container_of(f, struct f_ecm_opts, func_inst); + if (opts->bound) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); + kfree(opts); +} + +static struct usb_function_instance *ecm_alloc_inst(void) +{ + struct f_ecm_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = ecm_free_inst; + opts->net = gether_setup_default(); + if (IS_ERR(opts->net)) + return ERR_PTR(PTR_ERR(opts->net)); + + return &opts->func_inst; +} + +static void ecm_free(struct usb_function *f) +{ + struct f_ecm *ecm; + + ecm = func_to_ecm(f); + kfree(ecm); +} + +static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + + DBG(c->cdev, "ecm unbind\n"); + + ecm_string_defs[0].id = 0; + usb_free_all_descriptors(f); + + kfree(ecm->notify_req->buf); + usb_ep_free_request(ecm->notify, ecm->notify_req); +} + +struct usb_function *ecm_alloc(struct usb_function_instance *fi) +{ + struct f_ecm *ecm; + struct f_ecm_opts *opts; + int status; + + /* allocate and initialize one new instance */ + ecm = kzalloc(sizeof(*ecm), GFP_KERNEL); + if (!ecm) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_ecm_opts, func_inst); + + /* export host's Ethernet address in CDC format */ + status = gether_get_host_addr_cdc(opts->net, ecm->ethaddr, + sizeof(ecm->ethaddr)); + if (status < 12) { + kfree(ecm); + return ERR_PTR(-EINVAL); + } + ecm_string_defs[1].s = ecm->ethaddr; + + ecm->port.ioport = netdev_priv(opts->net); + ecm->port.cdc_filter = DEFAULT_FILTER; + + ecm->port.func.name = "cdc_ethernet"; + ecm->port.func.strings = ecm_strings; + /* descriptors are per-instance copies */ + ecm->port.func.bind = ecm_bind; + ecm->port.func.unbind = ecm_unbind; + ecm->port.func.set_alt = ecm_set_alt; + ecm->port.func.get_alt = ecm_get_alt; + ecm->port.func.setup = ecm_setup; + ecm->port.func.disable = ecm_disable; + ecm->port.func.free_func = ecm_free; + + return &ecm->port.func; +} + +DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell"); + +#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 @@ # define USB_ETH_RNDIS y # endif +#define USBF_ECM_INCLUDED # include "f_ecm.c" # include "f_subset.c" # 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"); */ #include "f_mass_storage.c" +#define USBF_ECM_INCLUDED #include "f_ecm.c" #include "f_subset.c" #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 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#define USBF_OBEX_INCLUDED +#define USBF_ECM_INCLUDED #include "f_ecm.c" +#define USBF_OBEX_INCLUDED #include "f_obex.c" #include "f_phonet.c" #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 @@ +/* + * u_ecm.h + * + * Utility definitions for the ecm function + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_ECM_H +#define U_ECM_H + +#include + +struct f_ecm_opts { + struct usb_function_instance func_inst; + struct net_device *net; + bool bound; +}; + +#endif /* U_ECM_H */ -- cgit v1.2.3 From 9c62ce83e4258bacc459faf57bf2ed83cce6be08 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:46 +0200 Subject: usb: gadget: ether: convert to new interface of f_ecm moving to new interface so we can remove the older one. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/ether.c | 73 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 13 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d6c4e601d711..a34d3da00b28 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -622,6 +622,7 @@ config USB_ETH select USB_LIBCOMPOSITE select USB_U_ETHER select USB_U_RNDIS + select USB_F_ECM select CRC32 help This driver implements Ethernet style communication, in one of diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 862ef656e8a1..f4d46d7cfe37 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -102,8 +102,7 @@ static inline bool has_rndis(void) * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#define USBF_ECM_INCLUDED -#include "f_ecm.c" +#include "u_ecm.h" #include "f_subset.c" #ifdef USB_ETH_RNDIS #include "f_rndis.c" @@ -212,6 +211,10 @@ static struct usb_gadget_strings *dev_strings[] = { static u8 host_mac[ETH_ALEN]; static struct eth_dev *the_dev; + +static struct usb_function_instance *fi_ecm; +static struct usb_function *f_ecm; + /*-------------------------------------------------------------------------*/ /* @@ -253,6 +256,8 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); */ static int __init eth_do_config(struct usb_configuration *c) { + int status = 0; + /* FIXME alloc iConfiguration string, set it in c->strings */ if (gadget_is_otg(c->cdev->gadget)) { @@ -262,10 +267,19 @@ static int __init eth_do_config(struct usb_configuration *c) if (use_eem) return eem_bind_config(c, the_dev); - else if (can_support_ecm(c->cdev->gadget)) - return ecm_bind_config(c, host_mac, the_dev); - else + else if (can_support_ecm(c->cdev->gadget)) { + f_ecm = usb_get_function(fi_ecm); + if (IS_ERR(f_ecm)) + return PTR_ERR(f_ecm); + + status = usb_add_function(c, f_ecm); + if (status < 0) + usb_put_function(f_ecm); + + return status; + } else return geth_bind_config(c, host_mac, the_dev); + } static struct usb_configuration eth_config_driver = { @@ -280,13 +294,16 @@ static struct usb_configuration eth_config_driver = { static int __init eth_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct f_ecm_opts *ecm_opts = NULL; int status; - /* set up network link layer */ - the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, - qmult); - if (IS_ERR(the_dev)) - return PTR_ERR(the_dev); + if (use_eem || !can_support_ecm(gadget)) { + /* set up network link layer */ + the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, + host_mac, qmult); + if (IS_ERR(the_dev)) + return PTR_ERR(the_dev); + } /* set up main config label and device descriptor */ if (use_eem) { @@ -294,8 +311,23 @@ static int __init eth_bind(struct usb_composite_dev *cdev) eth_config_driver.label = "CDC Ethernet (EEM)"; device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM); device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM); - } else if (can_support_ecm(cdev->gadget)) { + } else if (can_support_ecm(gadget)) { /* ECM */ + + fi_ecm = usb_get_function_instance("ecm"); + if (IS_ERR(fi_ecm)) + return PTR_ERR(fi_ecm); + + ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); + + gether_set_qmult(ecm_opts->net, qmult); + if (!gether_set_host_addr(ecm_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); + + the_dev = netdev_priv(ecm_opts->net); + eth_config_driver.label = "CDC Ethernet (ECM)"; } else { /* CDC Subset */ @@ -309,6 +341,15 @@ static int __init eth_bind(struct usb_composite_dev *cdev) if (has_rndis()) { /* RNDIS plus ECM-or-Subset */ + if (!use_eem && can_support_ecm(gadget)) { + gether_set_gadget(ecm_opts->net, cdev->gadget); + status = gether_register_netdev(ecm_opts->net); + if (status) + goto fail; + ecm_opts->bound = true; + gether_get_host_addr_u8(ecm_opts->net, host_mac); + } + device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM); device_desc.bNumConfigurations = 2; @@ -343,13 +384,19 @@ static int __init eth_bind(struct usb_composite_dev *cdev) return 0; fail: - gether_cleanup(the_dev); + if (use_eem || !can_support_ecm(gadget)) + gether_cleanup(the_dev); + else + usb_put_function_instance(fi_ecm); return status; } static int __exit eth_unbind(struct usb_composite_dev *cdev) { - gether_cleanup(the_dev); + if (use_eem || !can_support_ecm(cdev->gadget)) + gether_cleanup(the_dev); + else + usb_put_function_instance(fi_ecm); return 0; } -- cgit v1.2.3 From b29002a157940752dfed2c488b2011f63f007d71 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:47 +0200 Subject: usb: gadget: f_eem: convert to new function interface with backward compatibility Converting eem to the new function interface requires converting the USB eem's function code and its users. This patch converts the f_eem.c to the new function interface. The file is now compiled into a separate usb_f_eem.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/ether.c | 2 + drivers/usb/gadget/f_eem.c | 174 +++++++++++++++++++++++++++++++++++--------- drivers/usb/gadget/u_eem.h | 27 +++++++ 5 files changed, 172 insertions(+), 36 deletions(-) create mode 100644 drivers/usb/gadget/u_eem.h (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a34d3da00b28..a9d3a7f676b7 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -520,6 +520,9 @@ config USB_F_ECM config USB_F_PHONET tristate +config USB_F_EEM + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index db8ce05bbc2c..7069f53e140d 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -54,6 +54,8 @@ usb_f_ecm-y := f_ecm.o obj-$(CONFIG_USB_F_ECM) += usb_f_ecm.o usb_f_phonet-y := f_phonet.o obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o +usb_f_eem-y := f_eem.o +obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o # # USB gadget drivers diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f4d46d7cfe37..397609da5909 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -108,6 +108,8 @@ static inline bool has_rndis(void) #include "f_rndis.c" #include "rndis.h" #endif + +#define USB_FEEM_INCLUDED #include "f_eem.c" /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index f4e0bbef602a..471acc824115 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -12,12 +12,14 @@ */ #include +#include #include #include #include #include #include "u_ether.h" +#include "u_eem.h" #define EEM_HLEN 2 @@ -40,7 +42,7 @@ static inline struct f_eem *func_to_eem(struct usb_function *f) /* interface descriptor: */ -static struct usb_interface_descriptor eem_intf __initdata = { +static struct usb_interface_descriptor eem_intf = { .bLength = sizeof eem_intf, .bDescriptorType = USB_DT_INTERFACE, @@ -54,7 +56,7 @@ static struct usb_interface_descriptor eem_intf __initdata = { /* full speed support: */ -static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = { +static struct usb_endpoint_descriptor eem_fs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -62,7 +64,7 @@ static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = { +static struct usb_endpoint_descriptor eem_fs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -70,7 +72,7 @@ static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *eem_fs_function[] __initdata = { +static struct usb_descriptor_header *eem_fs_function[] = { /* CDC EEM control descriptors */ (struct usb_descriptor_header *) &eem_intf, (struct usb_descriptor_header *) &eem_fs_in_desc, @@ -80,7 +82,7 @@ static struct usb_descriptor_header *eem_fs_function[] __initdata = { /* high speed support: */ -static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = { +static struct usb_endpoint_descriptor eem_hs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -89,7 +91,7 @@ static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = { +static struct usb_endpoint_descriptor eem_hs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -98,7 +100,7 @@ static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_descriptor_header *eem_hs_function[] __initdata = { +static struct usb_descriptor_header *eem_hs_function[] = { /* CDC EEM control descriptors */ (struct usb_descriptor_header *) &eem_intf, (struct usb_descriptor_header *) &eem_hs_in_desc, @@ -108,7 +110,7 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = { /* super speed support: */ -static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = { +static struct usb_endpoint_descriptor eem_ss_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -117,7 +119,7 @@ static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = { .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = { +static struct usb_endpoint_descriptor eem_ss_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -126,7 +128,7 @@ static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = { .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = { +static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc = { .bLength = sizeof eem_ss_bulk_comp_desc, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, @@ -135,7 +137,7 @@ static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = { /* .bmAttributes = 0, */ }; -static struct usb_descriptor_header *eem_ss_function[] __initdata = { +static struct usb_descriptor_header *eem_ss_function[] = { /* CDC EEM control descriptors */ (struct usb_descriptor_header *) &eem_intf, (struct usb_descriptor_header *) &eem_ss_in_desc, @@ -242,14 +244,44 @@ static void eem_disable(struct usb_function *f) /* EEM function driver setup/binding */ -static int __init -eem_bind(struct usb_configuration *c, struct usb_function *f) +static int eem_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_eem *eem = func_to_eem(f); int status; struct usb_ep *ep; +#ifndef USB_FEEM_INCLUDED + struct f_eem_opts *eem_opts; + + eem_opts = container_of(f->fi, struct f_eem_opts, func_inst); + /* + * in drivers/usb/gadget/configfs.c:configfs_composite_bind() + * configurations are bound in sequence with list_for_each_entry, + * in each configuration its functions are bound in sequence + * with list_for_each_entry, so we assume no race condition + * with regard to eem_opts->bound access + */ + if (!eem_opts->bound) { + gether_set_gadget(eem_opts->net, cdev->gadget); + status = gether_register_netdev(eem_opts->net); + if (status) + return status; + eem_opts->bound = true; + } +#endif + + /* maybe allocate device-global string IDs */ + if (eem_string_defs[0].id == 0) { + + /* control interface label */ + status = usb_string_id(c->cdev); + if (status < 0) + return status; + eem_string_defs[0].id = status; + eem_intf.iInterface = status; + } + /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) @@ -307,17 +339,6 @@ fail: return status; } -static void -eem_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_eem *eem = func_to_eem(f); - - DBG(c->cdev, "eem unbind\n"); - - usb_free_all_descriptors(f); - kfree(eem); -} - static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) { struct sk_buff *skb = (struct sk_buff *)req->context; @@ -518,6 +539,18 @@ error: return status; } +#ifdef USB_FEEM_INCLUDED + +static void eem_old_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_eem *eem = func_to_eem(f); + + DBG(c->cdev, "eem unbind\n"); + + usb_free_all_descriptors(f); + kfree(eem); +} + /** * eem_bind_config - add CDC Ethernet (EEM) network link to a configuration * @c: the configuration to support the network link @@ -533,17 +566,6 @@ int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev) struct f_eem *eem; int status; - /* maybe allocate device-global string IDs */ - if (eem_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - eem_string_defs[0].id = status; - eem_intf.iInterface = status; - } - /* allocate and initialize one new instance */ eem = kzalloc(sizeof *eem, GFP_KERNEL); if (!eem) @@ -556,7 +578,7 @@ int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev) eem->port.func.strings = eem_strings; /* descriptors are per-instance copies */ eem->port.func.bind = eem_bind; - eem->port.func.unbind = eem_unbind; + eem->port.func.unbind = eem_old_unbind; eem->port.func.set_alt = eem_set_alt; eem->port.func.setup = eem_setup; eem->port.func.disable = eem_disable; @@ -570,3 +592,83 @@ int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev) return status; } +#else + +static void eem_free_inst(struct usb_function_instance *f) +{ + struct f_eem_opts *opts; + + opts = container_of(f, struct f_eem_opts, func_inst); + if (opts->bound) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); + kfree(opts); +} + +static struct usb_function_instance *eem_alloc_inst(void) +{ + struct f_eem_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + opts->func_inst.free_func_inst = eem_free_inst; + opts->net = gether_setup_default(); + if (IS_ERR(opts->net)) + return ERR_CAST(opts->net); + + return &opts->func_inst; +} + +static void eem_free(struct usb_function *f) +{ + struct f_eem *eem; + + eem = func_to_eem(f); + kfree(eem); +} + +static void eem_unbind(struct usb_configuration *c, struct usb_function *f) +{ + DBG(c->cdev, "eem unbind\n"); + + usb_free_all_descriptors(f); +} + +struct usb_function *eem_alloc(struct usb_function_instance *fi) +{ + struct f_eem *eem; + struct f_eem_opts *opts; + + /* allocate and initialize one new instance */ + eem = kzalloc(sizeof(*eem), GFP_KERNEL); + if (!eem) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_eem_opts, func_inst); + + eem->port.ioport = netdev_priv(opts->net); + eem->port.cdc_filter = DEFAULT_FILTER; + + eem->port.func.name = "cdc_eem"; + eem->port.func.strings = eem_strings; + /* descriptors are per-instance copies */ + eem->port.func.bind = eem_bind; + eem->port.func.unbind = eem_unbind; + eem->port.func.set_alt = eem_set_alt; + eem->port.func.setup = eem_setup; + eem->port.func.disable = eem_disable; + eem->port.func.free_func = eem_free; + eem->port.wrap = eem_wrap; + eem->port.unwrap = eem_unwrap; + eem->port.header_len = EEM_HLEN; + + return &eem->port.func; +} + +DECLARE_USB_FUNCTION_INIT(eem, eem_alloc_inst, eem_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell"); + +#endif diff --git a/drivers/usb/gadget/u_eem.h b/drivers/usb/gadget/u_eem.h new file mode 100644 index 000000000000..8f432f2a5e57 --- /dev/null +++ b/drivers/usb/gadget/u_eem.h @@ -0,0 +1,27 @@ +/* + * u_eem.h + * + * Utility definitions for the eem function + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_EEM_H +#define U_EEM_H + +#include + +struct f_eem_opts { + struct usb_function_instance func_inst; + struct net_device *net; + bool bound; +}; + +#endif /* U_EEM_H */ -- cgit v1.2.3 From 94b5573e97729f0e1496d23b69cbe2c6b24ec0c3 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:48 +0200 Subject: usb: gadget: ether: convert to new interface of f_eem use new interface so old one can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/ether.c | 54 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 9 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a9d3a7f676b7..159393d58912 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -681,6 +681,7 @@ config USB_ETH_EEM bool "Ethernet Emulation Model (EEM) support" depends on USB_ETH select USB_LIBCOMPOSITE + select USB_F_EEM default n help CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 397609da5909..2078e6c227a1 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -109,8 +109,7 @@ static inline bool has_rndis(void) #include "rndis.h" #endif -#define USB_FEEM_INCLUDED -#include "f_eem.c" +#include "u_eem.h" /*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); @@ -217,6 +216,9 @@ static struct eth_dev *the_dev; static struct usb_function_instance *fi_ecm; static struct usb_function *f_ecm; +static struct usb_function_instance *fi_eem; +static struct usb_function *f_eem; + /*-------------------------------------------------------------------------*/ /* @@ -267,9 +269,17 @@ static int __init eth_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - if (use_eem) - return eem_bind_config(c, the_dev); - else if (can_support_ecm(c->cdev->gadget)) { + if (use_eem) { + f_eem = usb_get_function(fi_eem); + if (IS_ERR(f_eem)) + return PTR_ERR(f_eem); + + status = usb_add_function(c, f_eem); + if (status < 0) + usb_put_function(f_eem); + + return status; + } else if (can_support_ecm(c->cdev->gadget)) { f_ecm = usb_get_function(fi_ecm); if (IS_ERR(f_ecm)) return PTR_ERR(f_ecm); @@ -296,10 +306,11 @@ static struct usb_configuration eth_config_driver = { static int __init eth_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct f_eem_opts *eem_opts = NULL; struct f_ecm_opts *ecm_opts = NULL; int status; - if (use_eem || !can_support_ecm(gadget)) { + if (!use_eem && !can_support_ecm(gadget)) { /* set up network link layer */ the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, qmult); @@ -310,6 +321,20 @@ static int __init eth_bind(struct usb_composite_dev *cdev) /* set up main config label and device descriptor */ if (use_eem) { /* EEM */ + fi_eem = usb_get_function_instance("eem"); + if (IS_ERR(fi_eem)) + return PTR_ERR(fi_eem); + + eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst); + + gether_set_qmult(eem_opts->net, qmult); + if (!gether_set_host_addr(eem_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(eem_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); + + the_dev = netdev_priv(eem_opts->net); + eth_config_driver.label = "CDC Ethernet (EEM)"; device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM); device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM); @@ -343,7 +368,14 @@ static int __init eth_bind(struct usb_composite_dev *cdev) if (has_rndis()) { /* RNDIS plus ECM-or-Subset */ - if (!use_eem && can_support_ecm(gadget)) { + if (use_eem) { + gether_set_gadget(eem_opts->net, cdev->gadget); + status = gether_register_netdev(eem_opts->net); + if (status) + goto fail; + eem_opts->bound = true; + gether_get_host_addr_u8(eem_opts->net, host_mac); + } else if (can_support_ecm(gadget)) { gether_set_gadget(ecm_opts->net, cdev->gadget); status = gether_register_netdev(ecm_opts->net); if (status) @@ -386,8 +418,10 @@ static int __init eth_bind(struct usb_composite_dev *cdev) return 0; fail: - if (use_eem || !can_support_ecm(gadget)) + if (!use_eem && !can_support_ecm(gadget)) gether_cleanup(the_dev); + else if (use_eem) + usb_put_function_instance(fi_eem); else usb_put_function_instance(fi_ecm); return status; @@ -395,8 +429,10 @@ fail: static int __exit eth_unbind(struct usb_composite_dev *cdev) { - if (use_eem || !can_support_ecm(cdev->gadget)) + if (!use_eem && !can_support_ecm(cdev->gadget)) gether_cleanup(the_dev); + else if (use_eem) + usb_put_function_instance(fi_eem); else usb_put_function_instance(fi_ecm); return 0; -- cgit v1.2.3 From 8cedba7c73af1369599b1111639cfeb66fe13aaa Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:53 +0200 Subject: usb: gadget: f_subset: convert to new function interface with backward compatibility Converting ecm subset to the new function interface requires converting the USB subset's function code and its users. This patch converts the f_subset.c to the new function interface. The file is now compiled into a separate usb_f_subset.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/ether.c | 1 + drivers/usb/gadget/f_subset.c | 136 +++++++++++++++++++++++++++++++++++++----- drivers/usb/gadget/g_ffs.c | 1 + drivers/usb/gadget/u_gether.h | 27 +++++++++ 6 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 drivers/usb/gadget/u_gether.h (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d5b0ffe26118..803aa93f3aa5 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -523,6 +523,9 @@ config USB_F_PHONET config USB_F_EEM tristate +config USB_F_SUBSET + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 7069f53e140d..1bfad55b9678 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -56,6 +56,8 @@ usb_f_phonet-y := f_phonet.o obj-$(CONFIG_USB_F_PHONET) += usb_f_phonet.o usb_f_eem-y := f_eem.o obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o +usb_f_ecm_subset-y := f_subset.o +obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o # # USB gadget drivers diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 2078e6c227a1..31739662ad00 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -103,6 +103,7 @@ static inline bool has_rndis(void) * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ #include "u_ecm.h" +#define USB_FSUBSET_INCLUDED #include "f_subset.c" #ifdef USB_ETH_RNDIS #include "f_rndis.c" diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 7be04b342494..5ae0bf612428 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -12,11 +12,12 @@ #include #include +#include #include #include #include "u_ether.h" - +#include "u_gether.h" /* * This function packages a simple "CDC Subset" Ethernet port with no real @@ -298,6 +299,35 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) int status; struct usb_ep *ep; +#ifndef USB_FSUBSET_INCLUDED + struct f_gether_opts *gether_opts; + + gether_opts = container_of(f->fi, struct f_gether_opts, func_inst); + + /* + * in drivers/usb/gadget/configfs.c:configfs_composite_bind() + * configurations are bound in sequence with list_for_each_entry, + * in each configuration its functions are bound in sequence + * with list_for_each_entry, so we assume no race condition + * with regard to gether_opts->bound access + */ + if (!gether_opts->bound) { + gether_set_gadget(gether_opts->net, cdev->gadget); + status = gether_register_netdev(gether_opts->net); + if (status) + return status; + gether_opts->bound = true; + } +#endif + /* maybe allocate device-global string IDs */ + if (geth_string_defs[0].id == 0) { + status = usb_string_ids_tab(c->cdev, geth_string_defs); + if (status < 0) + return status; + subset_data_intf.iInterface = geth_string_defs[0].id; + ether_desc.iMACAddress = geth_string_defs[1].id; + } + /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) @@ -360,8 +390,10 @@ fail: return status; } +#ifdef USB_FSUBSET_INCLUDED + static void -geth_unbind(struct usb_configuration *c, struct usb_function *f) +geth_old_unbind(struct usb_configuration *c, struct usb_function *f) { geth_string_defs[0].id = 0; usb_free_all_descriptors(f); @@ -387,18 +419,6 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], struct f_gether *geth; int status; - if (!ethaddr) - return -EINVAL; - - /* maybe allocate device-global string IDs */ - if (geth_string_defs[0].id == 0) { - status = usb_string_ids_tab(c->cdev, geth_string_defs); - if (status < 0) - return status; - subset_data_intf.iInterface = geth_string_defs[0].id; - ether_desc.iMACAddress = geth_string_defs[1].id; - } - /* allocate and initialize one new instance */ geth = kzalloc(sizeof *geth, GFP_KERNEL); if (!geth) @@ -414,7 +434,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], geth->port.func.name = "cdc_subset"; geth->port.func.strings = geth_strings; geth->port.func.bind = geth_bind; - geth->port.func.unbind = geth_unbind; + geth->port.func.unbind = geth_old_unbind; geth->port.func.set_alt = geth_set_alt; geth->port.func.disable = geth_disable; @@ -423,3 +443,89 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], kfree(geth); return status; } + +#else + +static void geth_free_inst(struct usb_function_instance *f) +{ + struct f_gether_opts *opts; + + opts = container_of(f, struct f_gether_opts, func_inst); + if (opts->bound) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); + kfree(opts); +} + +static struct usb_function_instance *geth_alloc_inst(void) +{ + struct f_gether_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = geth_free_inst; + opts->net = gether_setup_default(); + if (IS_ERR(opts->net)) + return ERR_CAST(opts->net); + + return &opts->func_inst; +} + +static void geth_free(struct usb_function *f) +{ + struct f_gether *eth; + + eth = func_to_geth(f); + kfree(eth); +} + +static void geth_unbind(struct usb_configuration *c, struct usb_function *f) +{ + geth_string_defs[0].id = 0; + usb_free_all_descriptors(f); +} + +static struct usb_function *geth_alloc(struct usb_function_instance *fi) +{ + struct f_gether *geth; + struct f_gether_opts *opts; + int status; + + /* allocate and initialize one new instance */ + geth = kzalloc(sizeof(*geth), GFP_KERNEL); + if (!geth) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_gether_opts, func_inst); + + /* export host's Ethernet address in CDC format */ + status = gether_get_host_addr_cdc(opts->net, geth->ethaddr, + sizeof(geth->ethaddr)); + if (status < 12) { + kfree(geth); + return ERR_PTR(-EINVAL); + } + geth_string_defs[1].s = geth->ethaddr; + + geth->port.ioport = netdev_priv(opts->net); + geth->port.cdc_filter = DEFAULT_FILTER; + + geth->port.func.name = "cdc_subset"; + geth->port.func.strings = geth_strings; + geth->port.func.bind = geth_bind; + geth->port.func.unbind = geth_unbind; + geth->port.func.set_alt = geth_set_alt; + geth->port.func.disable = geth_disable; + geth->port.func.free_func = geth_free; + + return &geth->port.func; +} + +DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell"); + +#endif diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index d38a073efd5d..3d290e5106af 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -30,6 +30,7 @@ #define USBF_ECM_INCLUDED # include "f_ecm.c" +#define USB_FSUBSET_INCLUDED # include "f_subset.c" # ifdef USB_ETH_RNDIS # include "f_rndis.c" diff --git a/drivers/usb/gadget/u_gether.h b/drivers/usb/gadget/u_gether.h new file mode 100644 index 000000000000..3a4a2bf61cdc --- /dev/null +++ b/drivers/usb/gadget/u_gether.h @@ -0,0 +1,27 @@ +/* + * u_gether.h + * + * Utility definitions for the subset function + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_GETHER_H +#define U_GETHER_H + +#include + +struct f_gether_opts { + struct usb_function_instance func_inst; + struct net_device *net; + bool bound; +}; + +#endif /* U_GETHER_H */ -- cgit v1.2.3 From 8af5232d6f48896b151898ccb2e9e155481bb785 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:54 +0200 Subject: usb: gadget: ether: convert to new interface of f_subset teach ethernet code about the new interface of f_subset so the old one can eventually be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/ether.c | 104 +++++++++++++++++++++++++-------------------- 2 files changed, 58 insertions(+), 47 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 803aa93f3aa5..0a444f39109f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -644,6 +644,7 @@ config USB_ETH select USB_U_ETHER select USB_U_RNDIS select USB_F_ECM + select USB_F_SUBSET select CRC32 help This driver implements Ethernet style communication, in one of diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 31739662ad00..9e96d5583e4c 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -14,6 +14,7 @@ /* #define VERBOSE_DEBUG */ #include +#include #if defined USB_ETH_RNDIS # undef USB_ETH_RNDIS @@ -103,8 +104,7 @@ static inline bool has_rndis(void) * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ #include "u_ecm.h" -#define USB_FSUBSET_INCLUDED -#include "f_subset.c" +#include "u_gether.h" #ifdef USB_ETH_RNDIS #include "f_rndis.c" #include "rndis.h" @@ -220,6 +220,9 @@ static struct usb_function *f_ecm; static struct usb_function_instance *fi_eem; static struct usb_function *f_eem; +static struct usb_function_instance *fi_geth; +static struct usb_function *f_geth; + /*-------------------------------------------------------------------------*/ /* @@ -290,8 +293,17 @@ static int __init eth_do_config(struct usb_configuration *c) usb_put_function(f_ecm); return status; - } else - return geth_bind_config(c, host_mac, the_dev); + } else { + f_geth = usb_get_function(fi_geth); + if (IS_ERR(f_geth)) + return PTR_ERR(f_geth); + + status = usb_add_function(c, f_geth); + if (status < 0) + usb_put_function(f_geth); + + return status; + } } @@ -309,16 +321,10 @@ static int __init eth_bind(struct usb_composite_dev *cdev) struct usb_gadget *gadget = cdev->gadget; struct f_eem_opts *eem_opts = NULL; struct f_ecm_opts *ecm_opts = NULL; + struct f_gether_opts *geth_opts = NULL; + struct net_device *net; int status; - if (!use_eem && !can_support_ecm(gadget)) { - /* set up network link layer */ - the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, - host_mac, qmult); - if (IS_ERR(the_dev)) - return PTR_ERR(the_dev); - } - /* set up main config label and device descriptor */ if (use_eem) { /* EEM */ @@ -328,13 +334,8 @@ static int __init eth_bind(struct usb_composite_dev *cdev) eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst); - gether_set_qmult(eem_opts->net, qmult); - if (!gether_set_host_addr(eem_opts->net, host_addr)) - pr_info("using host ethernet address: %s", host_addr); - if (!gether_set_dev_addr(eem_opts->net, dev_addr)) - pr_info("using self ethernet address: %s", dev_addr); - - the_dev = netdev_priv(eem_opts->net); + net = eem_opts->net; + the_dev = netdev_priv(net); eth_config_driver.label = "CDC Ethernet (EEM)"; device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM); @@ -348,17 +349,23 @@ static int __init eth_bind(struct usb_composite_dev *cdev) ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); - gether_set_qmult(ecm_opts->net, qmult); - if (!gether_set_host_addr(ecm_opts->net, host_addr)) - pr_info("using host ethernet address: %s", host_addr); - if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) - pr_info("using self ethernet address: %s", dev_addr); - - the_dev = netdev_priv(ecm_opts->net); + net = ecm_opts->net; + the_dev = netdev_priv(net); eth_config_driver.label = "CDC Ethernet (ECM)"; } else { /* CDC Subset */ + + fi_geth = usb_get_function_instance("geth"); + if (IS_ERR(fi_geth)) + return PTR_ERR(fi_geth); + + geth_opts = container_of(fi_geth, struct f_gether_opts, + func_inst); + + net = geth_opts->net; + the_dev = netdev_priv(net); + eth_config_driver.label = "CDC Subset/SAFE"; device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM); @@ -367,23 +374,26 @@ static int __init eth_bind(struct usb_composite_dev *cdev) device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; } + gether_set_qmult(net, qmult); + if (!gether_set_host_addr(net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); + if (has_rndis()) { /* RNDIS plus ECM-or-Subset */ - if (use_eem) { - gether_set_gadget(eem_opts->net, cdev->gadget); - status = gether_register_netdev(eem_opts->net); - if (status) - goto fail; + gether_set_gadget(net, cdev->gadget); + status = gether_register_netdev(net); + if (status) + goto fail; + gether_get_host_addr_u8(net, host_mac); + + if (use_eem) eem_opts->bound = true; - gether_get_host_addr_u8(eem_opts->net, host_mac); - } else if (can_support_ecm(gadget)) { - gether_set_gadget(ecm_opts->net, cdev->gadget); - status = gether_register_netdev(ecm_opts->net); - if (status) - goto fail; + else if (can_support_ecm(gadget)) ecm_opts->bound = true; - gether_get_host_addr_u8(ecm_opts->net, host_mac); - } + else + geth_opts->bound = true; device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM); @@ -419,23 +429,23 @@ static int __init eth_bind(struct usb_composite_dev *cdev) return 0; fail: - if (!use_eem && !can_support_ecm(gadget)) - gether_cleanup(the_dev); - else if (use_eem) + if (use_eem) usb_put_function_instance(fi_eem); - else + else if (can_support_ecm(gadget)) usb_put_function_instance(fi_ecm); + else + usb_put_function_instance(fi_geth); return status; } static int __exit eth_unbind(struct usb_composite_dev *cdev) { - if (!use_eem && !can_support_ecm(cdev->gadget)) - gether_cleanup(the_dev); - else if (use_eem) + if (use_eem) usb_put_function_instance(fi_eem); - else + else if (can_support_ecm(cdev->gadget)) usb_put_function_instance(fi_ecm); + else + usb_put_function_instance(fi_geth); return 0; } -- cgit v1.2.3 From f466c6353819326873fa48a02c6f2d7c903240d6 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:57 +0200 Subject: usb: gadget: f_rndis: convert to new function interface with backward compatibility Converting rndis to the new function interface requires converting the USB rndis' function code and its users. This patch converts the f_rndis.c to the new function interface. The file is now compiled into a separate usb_f_rndis.ko module. The old function interface is provided by means of a preprocessor conditional directives. After all users are converted, the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/ether.c | 1 + drivers/usb/gadget/f_rndis.c | 203 +++++++++++++++++++++++++++++++++++++------ drivers/usb/gadget/g_ffs.c | 1 + drivers/usb/gadget/multi.c | 1 + drivers/usb/gadget/u_rndis.h | 32 +++++++ 7 files changed, 215 insertions(+), 28 deletions(-) create mode 100644 drivers/usb/gadget/u_rndis.h (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3a72b9dbf7f0..22c86089d647 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -526,6 +526,9 @@ config USB_F_EEM config USB_F_SUBSET tristate +config USB_F_RNDIS + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 1bfad55b9678..b41776065f27 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -58,6 +58,8 @@ usb_f_eem-y := f_eem.o obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o usb_f_ecm_subset-y := f_subset.o obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o +usb_f_rndis-y := f_rndis.o +obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o # # USB gadget drivers diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9e96d5583e4c..4d7290a48fe7 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -106,6 +106,7 @@ static inline bool has_rndis(void) #include "u_ecm.h" #include "u_gether.h" #ifdef USB_ETH_RNDIS +#define USB_FRNDIS_INCLUDED #include "f_rndis.c" #include "rndis.h" #endif diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 36e8c44d8e5e..437198b6d8fa 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -17,15 +17,16 @@ #include #include +#include #include #include #include #include "u_ether.h" +#include "u_rndis.h" #include "rndis.h" - /* * This function is an RNDIS Ethernet port -- a Microsoft protocol that's * been promoted instead of the standard CDC Ethernet. The published RNDIS @@ -655,6 +656,13 @@ static void rndis_close(struct gether *geth) /*-------------------------------------------------------------------------*/ +/* Some controllers can't support RNDIS ... */ +static inline bool can_support_rndis(struct usb_configuration *c) +{ + /* everything else is *presumably* fine */ + return true; +} + /* ethernet function driver setup/binding */ static int @@ -665,6 +673,45 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) int status; struct usb_ep *ep; +#ifndef USB_FRNDIS_INCLUDED + struct f_rndis_opts *rndis_opts; + + if (!can_support_rndis(c)) + return -EINVAL; + + rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); + + /* + * in drivers/usb/gadget/configfs.c:configfs_composite_bind() + * configurations are bound in sequence with list_for_each_entry, + * in each configuration its functions are bound in sequence + * with list_for_each_entry, so we assume no race condition + * with regard to rndis_opts->bound access + */ + if (!rndis_opts->bound) { + gether_set_gadget(rndis_opts->net, cdev->gadget); + status = gether_register_netdev(rndis_opts->net); + if (status) + return status; + rndis_opts->bound = true; + } +#endif + + if (rndis_string_defs[0].id == 0) { + /* ... and setup RNDIS itself */ + status = rndis_init(); + if (status < 0) + return status; + + status = usb_string_ids_tab(c->cdev, rndis_string_defs); + if (status) + return status; + + rndis_control_intf.iInterface = rndis_string_defs[0].id; + rndis_data_intf.iInterface = rndis_string_defs[1].id; + rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; + } + /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) @@ -741,10 +788,12 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->port.open = rndis_open; rndis->port.close = rndis_close; +#ifdef USB_FRNDIS_INCLUDED status = rndis_register(rndis_response_available, rndis); if (status < 0) goto fail; rndis->config = status; +#endif rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); @@ -787,8 +836,10 @@ fail: return status; } +#ifdef USB_FRNDIS_INCLUDED + static void -rndis_unbind(struct usb_configuration *c, struct usb_function *f) +rndis_old_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); @@ -804,13 +855,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) kfree(rndis); } -/* Some controllers can't support RNDIS ... */ -static inline bool can_support_rndis(struct usb_configuration *c) -{ - /* everything else is *presumably* fine */ - return true; -} - int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], u32 vendorID, const char *manufacturer, struct eth_dev *dev) @@ -818,24 +862,6 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], struct f_rndis *rndis; int status; - if (!can_support_rndis(c) || !ethaddr) - return -EINVAL; - - if (rndis_string_defs[0].id == 0) { - /* ... and setup RNDIS itself */ - status = rndis_init(); - if (status < 0) - return status; - - status = usb_string_ids_tab(c->cdev, rndis_string_defs); - if (status) - return status; - - rndis_control_intf.iInterface = rndis_string_defs[0].id; - rndis_data_intf.iInterface = rndis_string_defs[1].id; - rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; - } - /* allocate and initialize one new instance */ status = -ENOMEM; rndis = kzalloc(sizeof *rndis, GFP_KERNEL); @@ -859,7 +885,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], rndis->port.func.strings = rndis_strings; /* descriptors are per-instance copies */ rndis->port.func.bind = rndis_bind; - rndis->port.func.unbind = rndis_unbind; + rndis->port.func.unbind = rndis_old_unbind; rndis->port.func.set_alt = rndis_set_alt; rndis->port.func.setup = rndis_setup; rndis->port.func.disable = rndis_disable; @@ -872,3 +898,124 @@ fail: } return status; } + +#else + +void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) +{ + struct f_rndis_opts *opts; + + opts = container_of(f, struct f_rndis_opts, func_inst); + if (opts->bound) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); + opts->borrowed_net = opts->bound = true; + opts->net = net; +} +EXPORT_SYMBOL(rndis_borrow_net); + +static void rndis_free_inst(struct usb_function_instance *f) +{ + struct f_rndis_opts *opts; + + opts = container_of(f, struct f_rndis_opts, func_inst); + if (!opts->borrowed_net) { + if (opts->bound) + gether_cleanup(netdev_priv(opts->net)); + else + free_netdev(opts->net); + } + kfree(opts); +} + +static struct usb_function_instance *rndis_alloc_inst(void) +{ + struct f_rndis_opts *opts; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = rndis_free_inst; + opts->net = gether_setup_default(); + if (IS_ERR(opts->net)) + return ERR_CAST(opts->net); + + return &opts->func_inst; +} + +static void rndis_free(struct usb_function *f) +{ + struct f_rndis *rndis; + + rndis = func_to_rndis(f); + rndis_deregister(rndis->config); + kfree(rndis); +} + +static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_rndis *rndis = func_to_rndis(f); + + rndis_exit(); + rndis_string_defs[0].id = 0; + usb_free_all_descriptors(f); + + kfree(rndis->notify_req->buf); + usb_ep_free_request(rndis->notify, rndis->notify_req); +} + +static struct usb_function *rndis_alloc(struct usb_function_instance *fi) +{ + struct f_rndis *rndis; + struct f_rndis_opts *opts; + int status; + + /* allocate and initialize one new instance */ + rndis = kzalloc(sizeof(*rndis), GFP_KERNEL); + if (!rndis) { + rndis_exit(); + return ERR_PTR(-ENOMEM); + } + + opts = container_of(fi, struct f_rndis_opts, func_inst); + + 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); + /* RNDIS activates when the host changes this filter */ + rndis->port.cdc_filter = 0; + + /* RNDIS has special (and complex) framing */ + rndis->port.header_len = sizeof(struct rndis_packet_msg_type); + rndis->port.wrap = rndis_add_header; + rndis->port.unwrap = rndis_rm_hdr; + + rndis->port.func.name = "rndis"; + rndis->port.func.strings = rndis_strings; + /* descriptors are per-instance copies */ + rndis->port.func.bind = rndis_bind; + rndis->port.func.unbind = rndis_unbind; + rndis->port.func.set_alt = rndis_set_alt; + rndis->port.func.setup = rndis_setup; + rndis->port.func.disable = rndis_disable; + rndis->port.func.free_func = rndis_free; + + status = rndis_register(rndis_response_available, rndis); + if (status < 0) { + kfree(rndis); + return ERR_PTR(status); + } + rndis->config = status; + + return &rndis->port.func; +} + +DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Brownell"); + +#endif diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 3d290e5106af..5327c82472ed 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -33,6 +33,7 @@ #define USB_FSUBSET_INCLUDED # include "f_subset.c" # ifdef USB_ETH_RNDIS +# define USB_FRNDIS_INCLUDED # include "f_rndis.c" # include "rndis.h" # endif diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 656c99983f62..032b96a51ce4 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -46,6 +46,7 @@ MODULE_LICENSE("GPL"); #define USBF_ECM_INCLUDED #include "f_ecm.c" #ifdef USB_ETH_RNDIS +# define USB_FRNDIS_INCLUDED # include "f_rndis.c" # include "rndis.h" #endif diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h new file mode 100644 index 000000000000..d274df56ce75 --- /dev/null +++ b/drivers/usb/gadget/u_rndis.h @@ -0,0 +1,32 @@ +/* + * u_rndis.h + * + * Utility definitions for the subset function + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_RNDIS_H +#define U_RNDIS_H + +#include + +struct f_rndis_opts { + struct usb_function_instance func_inst; + u32 vendor_id; + const char *manufacturer; + struct net_device *net; + bool bound; + bool borrowed_net; +}; + +void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net); + +#endif /* U_RNDIS_H */ -- cgit v1.2.3 From 9bd4a10e1bf881af0b0a7c117c7092b558447047 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 28 May 2013 09:15:58 +0200 Subject: usb: gadget: ether: convert to new interface of f_rndis use new interface so old one can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + drivers/usb/gadget/ether.c | 56 +++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 23 deletions(-) (limited to 'drivers/usb/gadget/ether.c') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 22c86089d647..19373a300ec4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -694,6 +694,7 @@ config USB_ETH_RNDIS bool "RNDIS support" depends on USB_ETH select USB_LIBCOMPOSITE + select USB_F_RNDIS default y help Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 4d7290a48fe7..f48712ffe261 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -94,23 +94,14 @@ static inline bool has_rndis(void) #include -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ #include "u_ecm.h" #include "u_gether.h" #ifdef USB_ETH_RNDIS -#define USB_FRNDIS_INCLUDED -#include "f_rndis.c" +#include "u_rndis.h" #include "rndis.h" +#else +#define rndis_borrow_net(...) do {} while (0) #endif - #include "u_eem.h" /*-------------------------------------------------------------------------*/ @@ -212,9 +203,6 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; -static u8 host_mac[ETH_ALEN]; -static struct eth_dev *the_dev; - static struct usb_function_instance *fi_ecm; static struct usb_function *f_ecm; @@ -224,6 +212,9 @@ static struct usb_function *f_eem; static struct usb_function_instance *fi_geth; static struct usb_function *f_geth; +static struct usb_function_instance *fi_rndis; +static struct usb_function *f_rndis; + /*-------------------------------------------------------------------------*/ /* @@ -233,6 +224,8 @@ static struct usb_function *f_geth; */ static int __init rndis_do_config(struct usb_configuration *c) { + int status; + /* FIXME alloc iConfiguration string, set it in c->strings */ if (gadget_is_otg(c->cdev->gadget)) { @@ -240,7 +233,15 @@ static int __init rndis_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return rndis_bind_config(c, host_mac, the_dev); + f_rndis = usb_get_function(fi_rndis); + if (IS_ERR(f_rndis)) + return PTR_ERR(f_rndis); + + status = usb_add_function(c, f_rndis); + if (status < 0) + usb_put_function(f_rndis); + + return status; } static struct usb_configuration rndis_config_driver = { @@ -336,7 +337,6 @@ static int __init eth_bind(struct usb_composite_dev *cdev) eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst); net = eem_opts->net; - the_dev = netdev_priv(net); eth_config_driver.label = "CDC Ethernet (EEM)"; device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM); @@ -351,7 +351,6 @@ static int __init eth_bind(struct usb_composite_dev *cdev) ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); net = ecm_opts->net; - the_dev = netdev_priv(net); eth_config_driver.label = "CDC Ethernet (ECM)"; } else { @@ -365,7 +364,6 @@ static int __init eth_bind(struct usb_composite_dev *cdev) func_inst); net = geth_opts->net; - the_dev = netdev_priv(net); eth_config_driver.label = "CDC Subset/SAFE"; @@ -387,7 +385,6 @@ static int __init eth_bind(struct usb_composite_dev *cdev) status = gether_register_netdev(net); if (status) goto fail; - gether_get_host_addr_u8(net, host_mac); if (use_eem) eem_opts->bound = true; @@ -396,6 +393,14 @@ static int __init eth_bind(struct usb_composite_dev *cdev) else geth_opts->bound = true; + fi_rndis = usb_get_function_instance("rndis"); + if (IS_ERR(fi_rndis)) { + status = PTR_ERR(fi_rndis); + goto fail; + } + + rndis_borrow_net(fi_rndis, net); + device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM); device_desc.bNumConfigurations = 2; @@ -407,7 +412,7 @@ static int __init eth_bind(struct usb_composite_dev *cdev) status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) - goto fail; + goto fail1; device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; @@ -416,12 +421,12 @@ static int __init eth_bind(struct usb_composite_dev *cdev) status = usb_add_config(cdev, &rndis_config_driver, rndis_do_config); if (status < 0) - goto fail; + goto fail1; } status = usb_add_config(cdev, ð_config_driver, eth_do_config); if (status < 0) - goto fail; + goto fail1; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -429,6 +434,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev) return 0; +fail1: + if (has_rndis()) + usb_put_function_instance(fi_rndis); fail: if (use_eem) usb_put_function_instance(fi_eem); @@ -441,6 +449,8 @@ fail: static int __exit eth_unbind(struct usb_composite_dev *cdev) { + if (has_rndis()) + usb_put_function_instance(fi_rndis); if (use_eem) usb_put_function_instance(fi_eem); else if (can_support_ecm(cdev->gadget)) -- cgit v1.2.3