[RFC] [PATCH 2/5]: Composite Devices Support
Felipe Balbi <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <1170431110.23028.38.camel@balbi> |
[PATCH] Base work for composite gadget support. Signed-off-by: Felipe Balbi <[email protected]> Signed-off-by: Ragner Magalhaes <[email protected]> --- Index: 2.6-dev/drivers/usb/gadget/Kconfig =================================================================== --- 2.6-dev.orig/drivers/usb/gadget/Kconfig 2007-01-29 11:40:21.000000000 -0400 +++ 2.6-dev/drivers/usb/gadget/Kconfig 2007-01-29 11:42:00.000000000 -0400 @@ -282,6 +282,15 @@ # this first set of drivers all depend on bulk-capable hardware. +config USB_COMPOSITE + tristate "Composite Gadget Support" + depends on USB_GADGET + help + A composite gadget is a device with more than one + interface. + + This module adds support for this kind of device. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" depends on EXPERIMENTAL Index: 2.6-dev/drivers/usb/gadget/Makefile =================================================================== --- 2.6-dev.orig/drivers/usb/gadget/Makefile 2007-01-29 11:40:21.000000000 -0400 +++ 2.6-dev/drivers/usb/gadget/Makefile 2007-01-29 11:42:18.000000000 -0400 @@ -19,6 +19,8 @@ gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o +g_composite-objs := composite_functions.o composite.o \ + usbstring.o config.o epautoconf.o ifeq ($(CONFIG_USB_ETH_RNDIS),y) g_ether-objs += rndis.o @@ -30,4 +32,4 @@ obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o - +obj-$(CONFIG_USB_COMPOSITE) += g_composite.o Index: 2.6-dev/drivers/usb/gadget/composite.c =================================================================== --- 2.6-dev.orig/drivers/usb/gadget/composite.c 2007-01-29 11:39:35.000000000 -0400 +++ 2.6-dev/drivers/usb/gadget/composite.c 2007-01-29 11:42:29.000000000 -0400 @@ -1,6 +1,3 @@ -#define DEBUG 1 -// #define VERBOSE - #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -22,9 +19,12 @@ #include <asm/unaligned.h> #include <linux/usb_ch9.h> +#include <linux/usb/cdc.h> #include <linux/usb_gadget.h> #include <linux/usb/composite.h> +#define DEBUG 1 +#define VERBOSE 1 #define xprintk(d,level,fmt,args...) \ dev_printk(level , &(d)->gadget->dev , fmt , ## args) @@ -51,10 +51,22 @@ #define INFO(dev,fmt,args...) \ xprintk(dev , KERN_INFO , fmt , ## args) +/* Defines */ +#define DRIVER_DESC "Composite Device" +#define DRIVER_VERSION "v1.0-alfa" +#define DRIVER_NAME "composite" + +static const char driver_desc [] = DRIVER_DESC; +static const char shortname [] = DRIVER_NAME; + /*-------------------------------------------------------------------------*/ +#define NUM_CONFIGS 1 +#define COMPOSITE_CONFIG_VALUE 3 /* composite config */ + /* big enough to hold our biggest descriptor */ -#define USB_BUFSIZ 512 +#define USB_BUFSIZ 256 + static struct usb_composite_driver *composite; @@ -78,6 +90,7 @@ } /*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ /* To simplify, we expect to have only ONE real configuration, working the * same no matter what speed it connects with. A given function may expose @@ -85,7 +98,7 @@ * class and endpoint descriptors (as usual). */ -#define CONFIG_NUMBER 1 +#define COMPOSITE_CONFIG_NUMBER 1 static int config_buf(struct usb_composite_dev *cdev, void *buf, u8 type) @@ -103,11 +116,12 @@ } else hs = 0; + /* write a config descriptor */ *c = cdev->config; c->bLength = USB_DT_CONFIG_SIZE; c->bDescriptorType = type; - c->bConfigurationValue = CONFIG_NUMBER; + c->bConfigurationValue = COMPOSITE_CONFIG_NUMBER; /* REVISIT some configurations might need other descriptors, * independent of the interfaces they implement ... notably @@ -139,13 +153,14 @@ ) { struct usb_function *f; int result; - DBG(cdev, "reset config\n"); req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_SET_CONFIGURATION; + req->wValue = COMPOSITE_CONFIG_VALUE; list_for_each_entry (f, &composite->functions, function) { + cdev->current_func = f; result = f->setup(cdev, req); if (result < 0) DBG(cdev, "reset function %s --> %d\n", @@ -157,7 +172,7 @@ static int composite_set_config(struct usb_composite_dev *cdev, unsigned number) { - int result = 0, tmp; + int result = 0; struct usb_gadget *gadget = cdev->gadget; struct usb_ctrlrequest req; @@ -176,18 +191,19 @@ case 0: usb_gadget_vbus_draw(gadget, is_otg(gadget) ? 8 : 100); break; - case CONFIG_NUMBER: + case COMPOSITE_CONFIG_NUMBER: req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE; req.bRequest = USB_REQ_SET_INTERFACE; - +/* ragner comments for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; req.wIndex = cpu_to_le16(tmp); + cdev->current_func = f; result = f->setup(cdev, &req); if (result < 0) { DBG(cdev, "interface %d/%s alt 0--> %d \n", @@ -196,12 +212,13 @@ return result; } } - +*/ cdev->config.bConfigurationValue = number; usb_gadget_vbus_draw(gadget, 2 * cdev->config.bMaxPower); break; } + INFO(cdev, "%s speed config #%d\n", ({ char *speed; switch (gadget->speed) { @@ -217,39 +234,37 @@ /*-------------------------------------------------------------------------*/ static void -composite_collect_langs(const struct usb_gadget_strings **sp, __le16 *buf) +composite_collect_langs(struct usb_gadget_strings *sp, __le16 *buf) { const struct usb_gadget_strings *s; u16 language; __le16 *tmp; - while (*sp) { - s = *sp; + if(sp) { + s = sp; language = cpu_to_le16(s->language); for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { if (*tmp == language) - goto repeat; + return; } *tmp++ = language; -repeat: - sp++; } } static int composite_check_string( - const struct usb_gadget_strings **sp, + struct usb_gadget_strings *sp, void *buf, u16 language, int id ) { - const struct usb_gadget_strings *s; + struct usb_gadget_strings *s; int value; - while (*sp) { - s = *sp++; + if(sp) { + s = sp; if (s->language != language) - continue; + return -EINVAL; value = usb_gadget_get_string(s, id, buf); if (value > 0) return value; @@ -265,9 +280,9 @@ /* 0 == report all available language codes */ if (id == 0) { struct usb_string_descriptor *s = buf; - const struct usb_gadget_strings **sp; + struct usb_gadget_strings *sp; - memset(s, 0, 256); + memset(s, 0, USB_BUFSIZ); s->bDescriptorType = USB_DT_STRING; sp = composite->strings; @@ -332,20 +347,26 @@ u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); + struct usb_function *f; + int result; req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: + VDBG(cdev, "Get descriptor control req=%d \n", w_value >> 8); if (ctrl->bRequestType != USB_DIR_IN) goto unknown; switch (w_value >> 8) { case USB_DT_DEVICE: + VDBG(cdev, "Get descriptor device\n"); value = min(w_length, (u16) sizeof cdev->dev); memcpy(req->buf, &cdev->dev, value); break; +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + VDBG(cdev, "Get descriptor qualifier\n"); if (!is_dualspeed(gadget)) break; value = min(w_length, (u16) sizeof cdev->qual); @@ -353,11 +374,13 @@ break; case USB_DT_OTHER_SPEED_CONFIG: + VDBG(cdev, "Get descriptor speed config\n"); if (!is_dualspeed(gadget)) break; // FALLTHROUGH - +#endif case USB_DT_CONFIG: + VDBG(cdev, "Get descriptor config\n"); /* one config ... so it must always be index 0 */ if (w_value & 0xff) break; @@ -367,6 +390,7 @@ value = min(w_length, (u16) value); break; case USB_DT_STRING: + VDBG(cdev, "Get descriptor string lang=%x id=%d\n", w_index, w_value & 0xff); value = composite_lookup_string(req->buf, w_index, w_value & 0xff); if (value >= 0) @@ -377,6 +401,7 @@ /* currently one config, two speeds */ case USB_REQ_SET_CONFIGURATION: + VDBG(cdev, "Set configuration control req=%d\n", w_value); if (ctrl->bRequestType != 0) goto unknown; if (gadget->a_hnp_support) @@ -390,6 +415,7 @@ spin_unlock(&cdev->lock); break; case USB_REQ_GET_CONFIGURATION: + VDBG(cdev, "Get configuration control req\n"); if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = cdev->config.bConfigurationValue; @@ -398,6 +424,7 @@ /* function drivers must handle get/set altsetting */ case USB_REQ_SET_INTERFACE: + VDBG(cdev, "Set interface control req=%d\n", w_index); if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; if (!cdev->config.bConfigurationValue @@ -405,10 +432,13 @@ || !cdev->interface[w_index]) break; spin_lock(&cdev->lock); - value = cdev->interface[w_index]->setup(cdev, ctrl); + cdev->current_func = cdev->interface[w_index]; + value = cdev->current_func->setup(cdev, ctrl); spin_unlock(&cdev->lock); + goto done; break; case USB_REQ_GET_INTERFACE: + VDBG(cdev, "Get interface control req=%d\n", w_index); if (ctrl->bRequestType !=(USB_DIR_IN| USB_RECIP_INTERFACE)) goto unknown; if (!cdev->config.bConfigurationValue @@ -417,13 +447,28 @@ break; spin_lock(&cdev->lock); /* function must set cdev->req->buf[0] */ - value = cdev->interface[w_index]->setup(cdev, ctrl); + cdev->current_func = cdev->interface[w_index]; + value = cdev->current_func->setup(cdev, ctrl); spin_unlock(&cdev->lock); value = min(w_length, (u16) 1); + goto done; break; default: + VDBG(cdev, "Default control req=%d\n", ctrl->bRequest); + /* FIXME - POG/GAMBI: For unknown CLASS_TYPE */ + list_for_each_entry (f, &cdev->driver->functions, function) { + cdev->current_func = f; + result = f->setup(cdev, ctrl); + if (result >= 0) { + DBG(cdev, "Default control req ok\n"); + value = result; + }else { + DBG(cdev, "Default control req not\n"); + } + } + goto done; unknown: - VDBG(dev, + VDBG(cdev, "unknown control req%02x.%02x v%04x i%04x l%d \n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); @@ -440,6 +485,7 @@ composite_setup_complete(gadget->ep0, req); } } + done: /* device either stalls (value < 0) or reports success */ return value; @@ -451,7 +497,6 @@ struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; struct usb_ctrlrequest req; - DBG(cdev, "disconnect\n"); memset(&req, 0, sizeof req); @@ -472,9 +517,10 @@ DBG(cdev, "unbind\n"); list_for_each_entry (f, &cdev->driver->functions, function) { + cdev->current_func = f; if (f->unbind) f->unbind(cdev); - if (f == cdev->current_bind) + if (f == cdev->current_func) break; } if (composite->unbind) @@ -487,14 +533,14 @@ set_gadget_data(gadget, NULL); } -static int __init +static int//__init composite_bind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; struct usb_function *f; int status = -ENOMEM; - cdev = kzalloc(sizeof *cdev, SLAB_KERNEL); + cdev = kzalloc(sizeof *cdev, GFP_KERNEL); if (!cdev) return status; @@ -519,6 +565,10 @@ usb_gadget_set_selfpowered(gadget); + /* before composite->bind() */ + cdev->next_string_id = 0; + cdev->next_interface_id = 0; + /* mostly to assign strings for whole device, like serial number, * but potentially also to update power state and consumption etc */ @@ -541,7 +591,7 @@ */ usb_ep_autoconfig_reset(gadget); list_for_each_entry (f, &cdev->driver->functions, function) { - cdev->current_bind = f; + cdev->current_func = f; status = f->bind(cdev); if (status < 0) goto fail; @@ -552,7 +602,7 @@ goto fail; } } - cdev->current_bind = NULL; + cdev->current_func = NULL; cdev->config.bNumInterfaces = cdev->next_interface_id; /* REVISIT eventually we want e.g. RNDIS and non-RNDIS configs, @@ -582,22 +632,120 @@ return status; } +/* FIXME + * Set the string id for each string in the current + * func referenced by current_func + */ int usb_composite_string_id(struct usb_composite_dev *cdev) { - if (cdev->current_bind && cdev->next_string_id < 255) - return cdev->next_string_id++; - return -ENODEV; + struct usb_function *f = cdev->current_func; + struct usb_string *src = f->strings->strings; + + if (!cdev->current_func && cdev->next_string_id >= 255) { + return -ENODEV; + } + + for (; src && src->s ; src++) { + (src)->id = cdev->next_string_id; + cdev->next_string_id ++; + } + + return 0; } +/* Set the interface id for each interface in the current + * func referenced by current_func + */ int usb_composite_interface_id(struct usb_composite_dev *cdev) { - if (cdev->next_interface_id < MAX_COMPOSITE_INTERFACES - && cdev->current_bind) { - cdev->interface[cdev->next_interface_id] = cdev->current_bind; - return cdev->next_interface_id++; - } - return -ENODEV; + struct usb_function *f = cdev->current_func; + struct usb_descriptor_header **src; + struct usb_interface_descriptor *interf_desc; + struct usb_cdc_header_desc *cdc_desc; + struct usb_cdc_union_desc *union_desc; + + int hs; + + if (!cdev->current_func && cdev->next_interface_id >= MAX_COMPOSITE_INTERFACES ) { + printk(KERN_INFO "Max composite interfaces ...\n" ); + return -ENODEV; + } + + if (is_dualspeed(cdev->gadget)) { + hs = (cdev->gadget->speed == USB_SPEED_HIGH); + //if (type == USB_DT_OTHER_SPEED_CONFIG) + // hs = !hs; + } else + hs = 0; + + f->interface_shift = cdev->next_interface_id; + + src = hs ? f->hs_descriptors : f->descriptors; + for (; 0 != *src; src++) { + if( (*src)->bDescriptorType == USB_DT_INTERFACE ) { + /* FIXME */ + interf_desc = (struct usb_interface_descriptor *) (*src); + interf_desc->bInterfaceNumber += f->interface_shift; + if( (cdev->next_interface_id - interf_desc->bInterfaceNumber) < 0 ) { + printk(KERN_INFO "Invalid interface number ...!\n" ); + return -EINVAL; + } + if( cdev->next_interface_id >= MAX_COMPOSITE_INTERFACES ) { + printk(KERN_INFO "Max composite interfaces ...\n" ); + return -EINVAL; + } + cdev->interface[cdev->next_interface_id] = f; + cdev->next_interface_id = interf_desc->bInterfaceNumber + 1; + } else if( (*src)->bDescriptorType == USB_DT_CS_INTERFACE ) { + /* FIXME */ + cdc_desc = (struct usb_cdc_header_desc *) (*src); + if( cdc_desc->bDescriptorSubType == USB_CDC_UNION_TYPE ) { + union_desc = (struct usb_cdc_union_desc *) (*src); + union_desc->bMasterInterface0 += f->interface_shift; + union_desc->bSlaveInterface0 += f->interface_shift; + } + } + } + + return 0; +} +/* FIXME +int composite_reset_interface_id(struct usb_composite_dev *cdev) +{ + struct usb_function *f = cdev->current_func; + struct usb_descriptor_header **src; + struct usb_interface_descriptor *interf_desc; + struct usb_cdc_header_desc *cdc_desc; + struct usb_cdc_union_desc *union_desc; + + int hs; + + if (is_dualspeed(cdev->gadget)) { + hs = (cdev->gadget->speed == USB_SPEED_HIGH); + //if (type == USB_DT_OTHER_SPEED_CONFIG) + // hs = !hs; + } else + hs = 0; + + src = hs ? f->hs_descriptors : f->descriptors; + + for (; 0 != *src; src++) { + if( (*src)->bDescriptorType == USB_DT_INTERFACE ) { + interf_desc = (struct usb_interface_descriptor *) (*src); + interf_desc->bInterfaceNumber -= f->interface_shift; + } else if( (*src)->bDescriptorType == USB_DT_CS_INTERFACE ) { + cdc_desc = (struct usb_cdc_header_desc *) (*src); + if( cdc_desc->bDescriptorSubType == USB_CDC_UNION_TYPE ) { + union_desc = (struct usb_cdc_union_desc *) (*src); + union_desc->bMasterInterface0 -= f->interface_shift; + union_desc->bSlaveInterface0 -= f->interface_shift; + } + } + } + + return 0; } +*/ /*-------------------------------------------------------------------------*/ @@ -610,7 +758,8 @@ DBG(cdev, "suspend\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry (f, &cdev->driver->functions, function) { - if (!f->suspend) + cdev->current_func = f; + if (!f->suspend) continue; f->suspend(cdev); } @@ -625,6 +774,7 @@ DBG(cdev, "resume\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry (f, &cdev->driver->functions, function) { + cdev->current_func = f; if (!f->resume) continue; f->resume(cdev); @@ -648,10 +798,11 @@ .driver = { .owner = THIS_MODULE, + .name = (char *) shortname, }, }; -int usb_composite_register(struct usb_composite_driver *d) +int /*__init*/ usb_composite_register(struct usb_composite_driver *d) { struct usb_function *f; @@ -677,3 +828,7 @@ return usb_gadget_register_driver(&composite_driver); } +void __exit usb_composite_unregister(struct usb_composite_driver *d) +{ + usb_gadget_unregister_driver(&composite_driver); +} Index: 2.6-dev/drivers/usb/gadget/composite_functions.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2.6-dev/drivers/usb/gadget/composite_functions.c 2007-01-29 11:42:50.000000000 -0400 @@ -0,0 +1,265 @@ +/* + * g_omap_composite.c -- USB OMAP Layer for Composite Device Support + * + * Copyright 2006 (C) Instituto Nokia de Tecnologia - INdT + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of the License of (at you option) any later version. + * + */ + +/* MODULE INCLUDES */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> +#include <linux/timer.h> +#include <linux/utsname.h> +#include <linux/usb_ch9.h> +#include <linux/usb_gadget.h> +#include <linux/usb/composite.h> + +#include <asm/byteorder.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/semaphore.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +#include "gadget_chips.h" + +/* Defines */ +#define DRIVER_DESC "Composite Driver" +#define DRIVER_VERSION "v1.0-alfa" +#define DRIVER_NAME "composite" + +static const char driver_desc [] = DRIVER_DESC; +static const char shortname [] = DRIVER_NAME; + +/* descriptors that are built on-demand */ +static char manufacturer [50]; +static char product_desc [40] = DRIVER_DESC; +static char serial_number [20] = {"INdT0"}; + +/*-------------------------------------------------------------------------*/ + +#define NUM_CONFIGS 1 + +#define VENDOR_ID 0x0525 /* NetChip */ +#define PRODUCT_ID 0Xa4a6 /* Linux-USB Serial */ +//#define VENDOR_ID 0x1a0a /* OTG test device IDs */ +//#define PRODUCT_ID 0xbadd +#define COMPOSITE_CONFIG_NUMBER 1 // ether ok + +/* USB String IDs */ +#define COMPOSITE_MANUFACTURER_ID 1 +#define COMPOSITE_PRODUCT_ID 2 +#define COMPOSITE_SERIALNUMBER_ID 3 +#define COMPOSITE_CONFIG_SRT_ID 4 + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Felipe Balbi, Ragner Magalhaes"); +MODULE_LICENSE("GPL"); + +/* USB Strings, UTF8 */ + + +static struct usb_string composite_strings[] = { + { COMPOSITE_MANUFACTURER_ID, manufacturer }, + { COMPOSITE_PRODUCT_ID, product_desc}, + { COMPOSITE_SERIALNUMBER_ID, serial_number }, + { COMPOSITE_CONFIG_SRT_ID, "Composite Alfa" }, + { } /* end */ +}; +static struct usb_gadget_strings composite_stringtable = { + .language = 0x0409, /* en-US */ + .strings = composite_strings, +}; +static struct usb_device_descriptor composite_device_desc = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = USB_CLASS_PER_INTERFACE, + .bDeviceProtocol = 0, + .idVendor = __constant_cpu_to_le16(VENDOR_ID), + .idProduct = __constant_cpu_to_le16(PRODUCT_ID), + .iManufacturer = COMPOSITE_MANUFACTURER_ID, + .iProduct = COMPOSITE_PRODUCT_ID, + .iSerialNumber = COMPOSITE_SERIALNUMBER_ID, + .bNumConfigurations = NUM_CONFIGS, +}; +static struct usb_config_descriptor composite_config_desc = { + .bLength = USB_DT_CONFIG_SIZE, + .bDescriptorType = USB_DT_CONFIG, + /* wTotalLenght computed dynamically */ + .bNumInterfaces = MAX_COMPOSITE_INTERFACES, + .bConfigurationValue = COMPOSITE_CONFIG_NUMBER, + .iConfiguration = COMPOSITE_CONFIG_SRT_ID, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, +}; +static struct usb_qualifier_descriptor composite_qualifier_desc = { + .bLength = sizeof composite_qualifier_desc, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bNumConfigurations = NUM_CONFIGS, +}; + +struct usb_composite_dev *cdev; + +/* Functions */ + +/* module */ +static int __init composite_init(void); +static void __exit composite_exit(void); + +/* usb_function register function */ +int usb_function_register(struct usb_function *); + +static int composite_func_bind(struct usb_composite_dev *composite_dev) +{ + cdev = composite_dev; + // Last id + 1 + cdev->next_string_id = COMPOSITE_CONFIG_SRT_ID + 1; + + cdev->config = composite_config_desc; + cdev->qual = composite_qualifier_desc; + + snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", + init_utsname()->sysname, init_utsname()->release, + driver_desc); + + return 0; +} + + +/* Composite Driver Struct */ + +static struct usb_composite_driver composite_drv = { + .dev = &composite_device_desc, + .strings = &composite_stringtable, + .bind = composite_func_bind, +// .unbind = composite_unbind, +// .setup = composite_setup, + .functions = LIST_HEAD_INIT(composite_drv.functions), +}; +/* FIXME +static int reset_functions() { + int status = 0; + struct usb_function *f; + cdev->next_interface_id = 0; + list_for_each_entry (f, &cdev->driver->functions, function) { + cdev->current_func = f; + composite_reset_interface_id(cdev); + status = usb_composite_interface_id(cdev); + if( status < 0 ) + goto fail; + } + cdev->config.bNumInterfaces = cdev->next_interface_id; + return 0; + fail: + return status; +} +*/ + +/* usb_function_register + * + * Get from usb function drivers their struct usb_function + * and assembles all of them into one struct usb_composite_driver + */ + + +/* FIXME: Code this function properly */ +int usb_function_register(struct usb_function *g_func) +{ + struct usb_composite_driver *d = &composite_drv; + int status = 0; + + if (!g_func->name) + g_func->name = "Composite Gadget"; + + cdev->current_func = g_func; + printk(KERN_INFO "Set interface.\n"); + + // Set interface id + status = usb_composite_interface_id(cdev); + if(status) + goto fail; + /* FIXME + printk(KERN_INFO "Set string.\n"); + status = usb_composite_string_id(cdev); + if(status) + goto fail; + */ + status = g_func->bind(cdev); + cdev->config.bNumInterfaces = cdev->next_interface_id; + if( status < 0 ) + goto fail; + + list_add_tail(&g_func->function, &d->functions); + printk(KERN_INFO "USB Function registered.\n"); + return 0; +fail: + return status; +} +EXPORT_SYMBOL(usb_function_register); + +void usb_function_unregister(struct usb_function *g_func) +{ + //struct usb_composite_driver *d = &composite_drv; + +/* FIXME */ + cdev->current_func = g_func; + g_func->unbind(cdev); + list_del(&g_func->function);//, &d->functions); +/* FIXME + * How to do this??? + if( reset_functions() < 0 ) + printk(KERN_INFO "Reset functions error!!!.\n"); +*/ +} +EXPORT_SYMBOL(usb_function_unregister); + + +/* + * composite_init + * + * Register as a USB Composite driver + * + * This function calls composite_function_register() to assemble + * composite_drv properly. After that it calls usb_composite_register() + * to register this device as a composite device. + */ + +/* This function will register de composite driver */ +static int __init composite_init(void) +{ + int retval = 0; + + retval = usb_composite_register(&composite_drv); + + if (retval) + return -EINVAL; + else { + return 0; + } +} + +static void __exit composite_exit(void) +{ + usb_composite_unregister(&composite_drv); + printk(KERN_INFO "composite_exit: %s %s unloaded\n", DRIVER_DESC, DRIVER_VERSION); +} +module_init(composite_init); +module_exit(composite_exit); Index: 2.6-dev/include/linux/usb/composite.h =================================================================== --- 2.6-dev.orig/include/linux/usb/composite.h 2007-01-29 11:39:35.000000000 -0400 +++ 2.6-dev/include/linux/usb/composite.h 2007-01-29 11:43:16.000000000 -0400 @@ -40,9 +40,11 @@ */ struct usb_function { const char *name; - const struct usb_gadget_strings **strings; - const struct usb_descriptor_header **descriptors; - const struct usb_descriptor_header **hs_descriptors; + struct usb_gadget_strings *strings; + struct usb_descriptor_header **descriptors; + struct usb_descriptor_header **hs_descriptors; + void *driver_data; /* data private to the driver */ + u8 interface_shift; struct list_head function; @@ -77,7 +79,7 @@ struct usb_composite_driver { const char *name; const struct usb_device_descriptor *dev; - const struct usb_gadget_strings **strings; + struct usb_gadget_strings *strings; /* REVISIT want a general "add more descriptors for config N" * hook; OTG would fall out naturally @@ -95,6 +97,9 @@ extern int usb_composite_register(struct usb_composite_driver *); +extern void usb_composite_unregister(struct usb_composite_driver *); +extern int usb_function_register(struct usb_function *); +extern void usb_function_unregister(struct usb_function *); #define MAX_COMPOSITE_INTERFACES 8 /* max 16 */ @@ -121,7 +126,7 @@ /* INTERNALS -- not for function drivers */ u8 next_string_id; u8 next_interface_id; - struct usb_function *current_bind; + struct usb_function *current_func; struct usb_function *interface[MAX_COMPOSITE_INTERFACES]; struct usb_composite_driver *driver; @@ -131,7 +136,12 @@ /* IDs may be assigned ONLY during function driver bind() */ extern int usb_composite_string_id(struct usb_composite_dev *c); extern int usb_composite_interface_id(struct usb_composite_dev *c); +/* FIXME +extern int composite_reset_interface_id(struct usb_composite_dev *c); +*/ + +extern int is_composite(void); #endif /* __KERNEL__ */ #endif /* __LINUX_USB_COMPOSITE_H */ -- Best Regards, Felipe Balbi [email protected] Nokia Institute of Technology - INdT Kernel Developers Team +55 92 2126 1003 ------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier. Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel