Joshua Wise wrote:

        Is there a tutorial out there or a list of what I
need to do to get a really teeny driver up and going? g_zero seems to be
rather large for what it does...

No tutorial, at least not now -- beyond the overview in the 2.6 kerneldoc (Documentation/DocBook/gadget.pdf). You'll need to understand chunks of the USB spec too. Provide the usb_gadget_driver methods, and work up from there.

Actually I think g_zero is quite small for a driver that handles
several different kinds of hardware, supports two different
configurations, and passes the usb-if tests at both high and
full speeds ... more than you may be thinking!  :)

Try trimming things out of zero.c ... easier to prune out
things you don't need (like second config) than to come up
with a really minimal driver (like the one below) and then
morph it back into something that's useful and portable.

- Dave


#include <linux/config.h> #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/uts.h> #include <linux/version.h> #include <linux/device.h> #include <linux/moduleparam.h>

#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>

#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>


/* This driver is OVERSIMPLIFIED and completely unrealistic, * because it doesn't support: * * - anything except enumeration to a nop configuration * - hardware other than the pxa2xx udc * - error checking/handling; fault logging; diagnostics; ... * - endpoints other then ep0 * - string descriptors * - non-spotty usb-if conformance * - ... any useful functionality * * DO NOT BASE REAL DRIVERS ON THIS CODE. */

#define USB_BUFSIZ 256

struct simple_dev {
        struct usb_request      *req;
};


/* these descriptors embed pxa-specific knowledge */ static const struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE,

        .bcdUSB =               __constant_cpu_to_le16 (0x0200),
        .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
        .bMaxPacketSize0 =      16,

        .bNumConfigurations =   1,
};

static const struct usb_config_descriptor
the_config = {
        .bLength =              sizeof the_config,
        .bDescriptorType =      USB_DT_CONFIG,

        .bNumInterfaces =       1,
        .bConfigurationValue =  1,
        .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
        .bMaxPower =            (100 + 1) / 2,
};

static const struct usb_interface_descriptor
the_intf = {
        .bLength =              sizeof the_intf,
        .bDescriptorType =      USB_DT_INTERFACE,

        .bNumEndpoints =        2,
        .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
};


static int config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { const unsigned config_len = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE;

        /* config */
        memcpy (buf, &the_config, USB_DT_CONFIG_SIZE);
        buf [1] = type;
        ((struct usb_config_descriptor *) buf)->wTotalLength
                = __constant_cpu_to_le16 (config_len);
        buf += USB_DT_CONFIG_SIZE;

        /* one interface */
        memcpy (buf, &the_intf, USB_DT_INTERFACE_SIZE);
        buf += USB_DT_INTERFACE_SIZE;

/* no endpoints */

        return config_len;
}


static void simple_setup_complete (struct usb_ep *ep, struct usb_request *req) { }

static int
simple_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
        struct simple_dev               *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;

/* this takes shortcuts and embeds pxa-specific knowledge */

switch (ctrl->bRequest) {

        case USB_REQ_GET_DESCRIPTOR:
                switch (ctrl->wValue >> 8) {

                case USB_DT_DEVICE:
                        value = min (ctrl->wLength, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
                case USB_DT_CONFIG:
                        value = config_buf (gadget->speed, req->buf,
                                        ctrl->wValue >> 8,
                                        ctrl->wValue & 0xff);
                        if (value >= 0)
                                value = min (ctrl->wLength, (u16) value);
                        break;
                }
                break;

        /* our set_{config,interface} is a NOP;
         * pxa hw handles get_config and get_interface
         */
        case USB_REQ_SET_CONFIGURATION:
        case USB_REQ_SET_INTERFACE:
                value = 0;
                break;
        }

        if (value >= 0) {
                req->length = value;
                (void) usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
        }
        return value;
}

static void
simple_disconnect (struct usb_gadget *gadget)
{
}

static void
simple_unbind (struct usb_gadget *gadget)
{
        struct simple_dev       *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;

        if (req) {
                if (req->buf)
                        usb_ep_free_buffer (gadget->ep0, req->buf,
                                                req->dma, req->length);
                usb_ep_free_request (gadget->ep0, req);
        }
        kfree (dev);
        set_gadget_data (gadget, 0);
}

static int
simple_bind (struct usb_gadget *gadget)
{
        struct simple_dev               *dev;

        dev = kmalloc (sizeof *dev, SLAB_KERNEL);
        if (!dev)
                return -ENOMEM;
        memset (dev, 0, sizeof *dev);
        set_gadget_data (gadget, dev);

        dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
        if (!dev->req)
                goto enomem;
        dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
                                &dev->req->dma, GFP_KERNEL);
        if (!dev->req->buf)
                goto enomem;
        dev->req->complete = simple_setup_complete;
        gadget->ep0->driver_data = dev;

return 0;

enomem:
        simple_unbind (gadget);
        return -ENOMEM;
}

static struct usb_gadget_driver simple_driver = {
        .speed          = USB_SPEED_FULL,
        .function       = "oversimplified example",
        .bind           = simple_bind,
        .unbind         = simple_unbind,

        .setup          = simple_setup,
        .disconnect     = simple_disconnect,

        .driver         = {
                .name           = "simple",
        },
};

static int __init init (void)
{
        return usb_gadget_register_driver (&simple_driver);
}
module_init (init);

static void __exit cleanup (void)
{
        usb_gadget_unregister_driver (&simple_driver);
}
module_exit (cleanup);





-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to