From: Ragner Magalhaes <[EMAIL PROTECTED]>

Implements support for a gadget function with composite support
to work as a single function.

Signed-off-by: Ragner Magalhaes <[EMAIL PROTECTED]>
---

 drivers/usb/gadget/gadget.c |  283 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 283 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/gadget.c b/drivers/usb/gadget/gadget.c
new file mode 100644
index 0000000..9a4a0e0
--- /dev/null
+++ b/drivers/usb/gadget/gadget.c
@@ -0,0 +1,283 @@
+/*
+ * gadget.c -- USB gadget driver.
+ *
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ * Developed for INdT by Ragner Magalhaes
+ * Ragner Magalhaes <[EMAIL PROTECTED]>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * Implements support for one gadget device with a single function.
+ */
+
+#if 0
+#define DEBUG 1
+#define VERBOSE 1
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/composite.h>
+
+#include "gadget_chips.h"
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(d,level,fmt,args...) \
+       dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#define DBG(dev,fmt,args...) \
+       xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev,fmt,args...) \
+       do { } while(0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG   DBG
+#else
+#define VDBG(dev,fmt,args...) \
+       do { } while(0)
+#endif /* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+       xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ             256
+
+
+struct usb_function    *func;
+
+/*-------------------------------------------------------------------------*/
+
+/* An impossibly large value as file_storage */
+#define DELAYED_STATUS         (USB_BUFSIZ + 999)
+
+void usb_func_ep_reset (struct usb_gadget *g, struct usb_function *f)
+{
+       struct usb_ep   *ep;
+
+       list_for_each_entry (ep, &g->ep_list, ep_list) {
+               if (ep->driver_data == f->driver_data) {
+                       usb_ep_disable (ep);
+                       ep->driver_data = NULL;
+               }
+       }
+}
+
+static void
+free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+       if (req->buf)
+               kfree (req->buf);
+       usb_ep_free_request(ep, req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+gadget_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_gadget_dev           *dev = get_gadget_data(gadget);
+       struct usb_request              *req = dev->req;
+       int                             value = -EOPNOTSUPP;
+       u16                             w_index = le16_to_cpu(ctrl->wIndex);
+       u16                             w_value = le16_to_cpu(ctrl->wValue);
+       u16                             w_length = le16_to_cpu(ctrl->wLength);
+
+       req->zero = 0;
+       req->length = 0;
+       value = dev->func->setup (gadget, ctrl);
+
+       /* respond with data transfer before status phase? */
+       if (value >= 0 && value != DELAYED_STATUS) {
+               value = min((u16)value, w_length);
+               req->length = value;
+               req->zero = value < w_length;
+
+               value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+               if (value != 0 && value != -ESHUTDOWN) {
+                       WARN(dev, "error in submission: %s --> %d\n",
+                                       (ctrl->bRequestType & USB_DIR_IN ?
+                                        "ep0-in" : "ep0-out"), value);
+                       req->status = 0;
+               }
+       } else {
+               DBG(dev, "setup req%02x.%02x v%04x i%04x l%d --> %d\n",
+                               ctrl->bRequestType, ctrl->bRequest,
+                               w_value, w_index, w_length, value);
+               /* to eliminate compile warnings */
+               w_index = w_value = 0;
+       }
+
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+static void
+gadget_disconnect(struct usb_gadget *gadget)
+{
+       struct usb_gadget_dev           *dev = get_gadget_data(gadget);
+       unsigned long                   flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->func->disconnect(gadget);
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void /* __init_or_exit */
+gadget_unbind(struct usb_gadget *gadget)
+{
+       struct usb_gadget_dev           *dev = get_gadget_data(gadget);
+
+       /* we've already been disconnected ... no i/o is active */
+       if (dev->req) {
+               dev->req->length = USB_BUFSIZ;
+               free_ep_req(gadget->ep0, dev->req);
+               dev->req = NULL;
+       }
+       if (dev->func)
+               dev->func->unbind(gadget);
+
+       gadget->ep0->driver_data = dev;
+       usb_func_ep_reset (gadget, dev->func);
+       kfree(dev);
+       set_gadget_data(gadget, NULL);
+}
+
+static int __devinit
+gadget_bind(struct usb_gadget *gadget)
+{
+       struct usb_gadget_dev           *dev;
+       int                             status = -ENOMEM;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return status;
+
+       spin_lock_init(&dev->lock);
+       dev->gadget = gadget;
+       set_gadget_data(gadget, dev);
+
+       /* preallocate control response and buffer */
+       dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+       if (!dev->req)
+               goto fail;
+       dev->req->buf = kmalloc (USB_BUFSIZ, GFP_KERNEL);
+       if (!dev->req->buf)
+               goto fail;
+
+       dev->func = func;
+
+       usb_ep_autoconfig_reset(gadget);
+
+       if (!func->bind) {
+               status = -EINVAL;
+               goto fail;
+       }
+       status = func->bind (gadget);
+       if (status < 0)
+               goto fail;
+
+       return 0;
+fail:
+       gadget_unbind(gadget);
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+gadget_suspend(struct usb_gadget *gadget)
+{
+       struct usb_gadget_dev           *dev = get_gadget_data(gadget);
+
+       dev->func->suspend(gadget);
+}
+
+static void
+gadget_resume(struct usb_gadget *gadget)
+{
+       struct usb_gadget_dev           *dev = get_gadget_data (gadget);
+
+       dev->func->resume (gadget);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver gadget_drv = {
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       .speed          = USB_SPEED_HIGH,
+#else
+       .speed          = USB_SPEED_FULL,
+#endif
+
+       .bind           = gadget_bind,
+       .unbind         = __exit_p(gadget_unbind),
+
+       .setup          = gadget_setup,
+       .disconnect     = gadget_disconnect,
+
+       .suspend        = gadget_suspend,
+       .resume         = gadget_resume,
+
+       .driver = {
+               .owner  = THIS_MODULE,
+       },
+};
+
+/* register single function */
+int usb_func_register(struct usb_function *f)
+{
+       if (!f)
+               return -ENODEV;
+       else if (func)
+               return -EBUSY;
+
+       if (!f->name)
+               f->name = "gadget";
+       gadget_drv.function =  (char *) f->name;
+       gadget_drv.driver.name = f->name;
+
+       func = f;
+
+       return usb_gadget_register_driver (&gadget_drv);
+}
+
+void usb_func_unregister(struct usb_function *f)
+{
+       usb_gadget_unregister_driver (&gadget_drv);
+}
+

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to