This patch converts f_acm into a module which uses the new function interface. It also converts one of its users that is g_serial to make use of it. The other users of it (g_nokia for instance) are still using the old include file system and should not notice the change at all. So they can be converter later independently. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/gadget/Kconfig | 4 ++ drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/acm_ms.c | 2 +- drivers/usb/gadget/cdc2.c | 2 +- drivers/usb/gadget/f_acm.c | 110 +++++++++++++++++++++++++++++------------ drivers/usb/gadget/multi.c | 2 +- drivers/usb/gadget/nokia.c | 1 + drivers/usb/gadget/serial.c | 81 ++++++++++++++++++++++++------ drivers/usb/gadget/u_serial.h | 2 + 9 files changed, 156 insertions(+), 49 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 18d2114..4889dfb 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -500,6 +500,9 @@ config USB_LIBCOMPOSITE tristate depends on USB_GADGET +config USB_F_ACM + tristate + config USB_F_SS_LB tristate @@ -784,6 +787,7 @@ config USB_GADGET_TARGET config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" select USB_U_SERIAL + select USB_F_ACM select USB_LIBCOMPOSITE help The Serial Gadget talks to the Linux-USB generic serial driver. diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 3083583..bd941d0 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o # USB Functions +obj-$(CONFIG_USB_F_ACM) += f_acm.o f_ss_lb-y := f_loopback.o f_sourcesink.o obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o obj-$(CONFIG_USB_U_SERIAL) += u_serial.o diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 35cbe72..4c5f116 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -40,7 +40,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - +#define USB_FACM_INCLUDED #include "f_acm.c" #include "f_mass_storage.c" diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 379df67..fa7a26c 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -42,7 +42,7 @@ USB_GADGET_COMPOSITE_OPTIONS(); * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ - +#define USB_FACM_INCLUDED #include "f_acm.c" #include "f_ecm.c" #include "u_ether.c" diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index d4a7c19..3aba07dc 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -16,7 +16,9 @@ #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/device.h> +#include <linux/err.h> #include "u_serial.h" #include "gadget_chips.h" @@ -608,6 +610,22 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) int status; struct usb_ep *ep; + /* REVISIT might want instance-specific strings to help + * distinguish instances ... + */ + + /* maybe allocate device-global string IDs, and patch descriptors */ + if (acm_string_defs[0].id == 0) { + status = usb_string_ids_tab(c->cdev, acm_string_defs); + if (status < 0) + return status; + acm_control_interface_desc.iInterface = + acm_string_defs[ACM_CTRL_IDX].id; + acm_data_interface_desc.iInterface = + acm_string_defs[ACM_DATA_IDX].id; + acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; + } + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) @@ -707,10 +725,37 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f) acm_string_defs[0].id = 0; usb_free_all_descriptors(f); - gs_free_req(acm->notify, acm->notify_req); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); kfree(acm); } +static struct f_acm *acm_alloc_basic_func(void) +{ + struct f_acm *acm; + + acm = kzalloc(sizeof(*acm), GFP_KERNEL); + if (!acm) + return NULL; + + spin_lock_init(&acm->lock); + + acm->port.connect = acm_connect; + acm->port.disconnect = acm_disconnect; + acm->port.send_break = acm_send_break; + + acm->port.func.name = "acm"; + acm->port.func.strings = acm_strings; + /* descriptors are per-instance copies */ + acm->port.func.bind = acm_bind; + acm->port.func.set_alt = acm_set_alt; + acm->port.func.setup = acm_setup; + acm->port.func.disable = acm_disable; + + return acm; +} + +#ifdef USB_FACM_INCLUDED /** * acm_bind_config - add a CDC ACM function to a configuration * @c: the configuration to support the CDC ACM instance @@ -728,46 +773,49 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num) struct f_acm *acm; int status; - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ - - /* maybe allocate device-global string IDs, and patch descriptors */ - if (acm_string_defs[0].id == 0) { - status = usb_string_ids_tab(c->cdev, acm_string_defs); - if (status < 0) - return status; - acm_control_interface_desc.iInterface = - acm_string_defs[ACM_CTRL_IDX].id; - acm_data_interface_desc.iInterface = - acm_string_defs[ACM_DATA_IDX].id; - acm_iad_descriptor.iFunction = acm_string_defs[ACM_IAD_IDX].id; - } - /* allocate and initialize one new instance */ - acm = kzalloc(sizeof *acm, GFP_KERNEL); + acm = acm_alloc_basic_func(); if (!acm) return -ENOMEM; - spin_lock_init(&acm->lock); - acm->port_num = port_num; - acm->port.connect = acm_connect; - acm->port.disconnect = acm_disconnect; - acm->port.send_break = acm_send_break; - - acm->port.func.name = "acm"; - acm->port.func.strings = acm_strings; - /* descriptors are per-instance copies */ - acm->port.func.bind = acm_bind; acm->port.func.unbind = acm_unbind; - acm->port.func.set_alt = acm_set_alt; - acm->port.func.setup = acm_setup; - acm->port.func.disable = acm_disable; status = usb_add_function(c, &acm->port.func); if (status) kfree(acm); return status; } + +#else + +static void acm_free_func(struct usb_function *f) +{ + acm_unbind(NULL, f); +} + +void facm_configure(struct usb_function *f, unsigned port) +{ + struct f_acm *acm; + + acm = func_to_acm(f); + acm->port_num = port; +} +EXPORT_SYMBOL_GPL(facm_configure); + +static struct usb_function *acm_alloc_func(void) +{ + struct f_acm *acm; + + acm = acm_alloc_basic_func(); + if (!acm) + return ERR_PTR(-ENOMEM); + + acm->port.func.free_func = acm_free_func; + + return &acm->port.func; +} +DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_func); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 0066791..78b26ed 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -41,7 +41,7 @@ MODULE_LICENSE("GPL"); * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ #include "f_mass_storage.c" - +#define USB_FACM_INCLUDED #include "f_acm.c" #include "f_ecm.c" diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 60937d0..a000fb7 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -37,6 +37,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#define USB_FACM_INCLUDED #include "f_acm.c" #include "f_ecm.c" #include "f_obex.c" diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 4816f49..6aff77e 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -36,7 +36,6 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#include "f_acm.c" #include "f_obex.c" #include "f_serial.c" @@ -128,16 +127,6 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); /*-------------------------------------------------------------------------*/ -static int __init serial_bind_acm_config(struct usb_configuration *c) -{ - unsigned i; - int status = 0; - - for (i = 0; i < n_ports && status == 0; i++) - status = acm_bind_config(c, i); - return status; -} - static int __init serial_bind_obex_config(struct usb_configuration *c) { unsigned i; @@ -165,6 +154,54 @@ static struct usb_configuration serial_config_driver = { .bmAttributes = USB_CONFIG_ATT_SELFPOWER, }; +static struct usb_function **f_serial; + +static int serial_register_ports(struct usb_composite_dev *cdev, + struct usb_configuration *c, const char *f_name, + void (*set_port)(struct usb_function *f, unsigned port)) +{ + int i; + int ret; + + f_serial = kmalloc(sizeof(struct usb_function *) * n_ports, GFP_KERNEL); + if (!f_serial) + return -ENOMEM; + ret = usb_add_config_only(cdev, c); + if (ret) + goto free_out; + + for (i = 0; i < n_ports; i++) { + + f_serial[i] = usb_get_function(f_name); + if (IS_ERR(f_serial[i])) { + ret = PTR_ERR(f_serial[i]); + i--; + goto fail; + } + + set_port(f_serial[i], i); + + ret = usb_add_function(c, f_serial[i]); + if (ret) { + usb_put_function(f_serial[i]); + i--; + goto fail; + } + } + + return 0; +fail: + while (i >= 0) { + usb_remove_function(c, f_serial[i]); + usb_put_function(f_serial[i]); + i--; + } +free_out: + kfree(f_serial); + f_serial = NULL; + return ret; +} + static int __init gs_bind(struct usb_composite_dev *cdev) { int status; @@ -191,10 +228,11 @@ static int __init gs_bind(struct usb_composite_dev *cdev) } /* register our configuration */ - if (use_acm) - status = usb_add_config(cdev, &serial_config_driver, - serial_bind_acm_config); - else if (use_obex) + if (use_acm) { + status = serial_register_ports(cdev, &serial_config_driver, + "acm", facm_configure); + usb_ep_autoconfig_reset(cdev->gadget); + } else if (use_obex) status = usb_add_config(cdev, &serial_config_driver, serial_bind_obex_config); else @@ -213,12 +251,25 @@ static int __init gs_bind(struct usb_composite_dev *cdev) return status; } +static int gs_unbind(struct usb_composite_dev *cdev) +{ + int i; + + if (!f_serial) + return 0; + for (i = 0; i < n_ports; i++) + usb_put_function(f_serial[i]); + kfree(f_serial); + return 0; +} + static __refdata struct usb_composite_driver gserial_driver = { .name = "g_serial", .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_SUPER, .bind = gs_bind, + .unbind = gs_unbind, }; static int __init init(void) diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 9b0fe64..6fa36cf 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h @@ -62,4 +62,6 @@ int acm_bind_config(struct usb_configuration *c, u8 port_num); int gser_bind_config(struct usb_configuration *c, u8 port_num); int obex_bind_config(struct usb_configuration *c, u8 port_num); +void facm_configure(struct usb_function *f, unsigned port); + #endif /* __U_SERIAL_H */ -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html