[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.