linux/drivers/usb/gadget/hid.c
<<
>>
Prefs
   1/*
   2 * hid.c -- HID Composite driver
   3 *
   4 * Based on multi.c
   5 *
   6 * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14
  15#include <linux/kernel.h>
  16#include <linux/platform_device.h>
  17#include <linux/list.h>
  18
  19#define DRIVER_DESC             "HID Gadget"
  20#define DRIVER_VERSION          "2010/03/16"
  21
  22/*-------------------------------------------------------------------------*/
  23
  24#define HIDG_VENDOR_NUM         0x0525  /* XXX NetChip */
  25#define HIDG_PRODUCT_NUM        0xa4ac  /* Linux-USB HID gadget */
  26
  27/*-------------------------------------------------------------------------*/
  28
  29/*
  30 * kbuild is not very cooperative with respect to linking separately
  31 * compiled library objects into one module.  So for now we won't use
  32 * separate compilation ... ensuring init/exit sections work to shrink
  33 * the runtime footprint, and giving us at least some parts of what
  34 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  35 */
  36
  37#include "composite.c"
  38#include "usbstring.c"
  39#include "config.c"
  40#include "epautoconf.c"
  41
  42#include "f_hid.c"
  43
  44
  45struct hidg_func_node {
  46        struct list_head node;
  47        struct hidg_func_descriptor *func;
  48};
  49
  50static LIST_HEAD(hidg_func_list);
  51
  52/*-------------------------------------------------------------------------*/
  53
  54static struct usb_device_descriptor device_desc = {
  55        .bLength =              sizeof device_desc,
  56        .bDescriptorType =      USB_DT_DEVICE,
  57
  58        .bcdUSB =               cpu_to_le16(0x0200),
  59
  60        /* .bDeviceClass =              USB_CLASS_COMM, */
  61        /* .bDeviceSubClass =   0, */
  62        /* .bDeviceProtocol =   0, */
  63        .bDeviceClass =         USB_CLASS_PER_INTERFACE,
  64        .bDeviceSubClass =      0,
  65        .bDeviceProtocol =      0,
  66        /* .bMaxPacketSize0 = f(hardware) */
  67
  68        /* Vendor and product id can be overridden by module parameters.  */
  69        .idVendor =             cpu_to_le16(HIDG_VENDOR_NUM),
  70        .idProduct =            cpu_to_le16(HIDG_PRODUCT_NUM),
  71        /* .bcdDevice = f(hardware) */
  72        /* .iManufacturer = DYNAMIC */
  73        /* .iProduct = DYNAMIC */
  74        /* NO SERIAL NUMBER */
  75        .bNumConfigurations =   1,
  76};
  77
  78static struct usb_otg_descriptor otg_descriptor = {
  79        .bLength =              sizeof otg_descriptor,
  80        .bDescriptorType =      USB_DT_OTG,
  81
  82        /* REVISIT SRP-only hardware is possible, although
  83         * it would not be called "OTG" ...
  84         */
  85        .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
  86};
  87
  88static const struct usb_descriptor_header *otg_desc[] = {
  89        (struct usb_descriptor_header *) &otg_descriptor,
  90        NULL,
  91};
  92
  93
  94/* string IDs are assigned dynamically */
  95
  96#define STRING_MANUFACTURER_IDX         0
  97#define STRING_PRODUCT_IDX              1
  98
  99static char manufacturer[50];
 100
 101static struct usb_string strings_dev[] = {
 102        [STRING_MANUFACTURER_IDX].s = manufacturer,
 103        [STRING_PRODUCT_IDX].s = DRIVER_DESC,
 104        {  } /* end of list */
 105};
 106
 107static struct usb_gadget_strings stringtab_dev = {
 108        .language       = 0x0409,       /* en-us */
 109        .strings        = strings_dev,
 110};
 111
 112static struct usb_gadget_strings *dev_strings[] = {
 113        &stringtab_dev,
 114        NULL,
 115};
 116
 117
 118
 119/****************************** Configurations ******************************/
 120
 121static int __init do_config(struct usb_configuration *c)
 122{
 123        struct hidg_func_node *e;
 124        int func = 0, status = 0;
 125
 126        if (gadget_is_otg(c->cdev->gadget)) {
 127                c->descriptors = otg_desc;
 128                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 129        }
 130
 131        list_for_each_entry(e, &hidg_func_list, node) {
 132                status = hidg_bind_config(c, e->func, func++);
 133                if (status)
 134                        break;
 135        }
 136
 137        return status;
 138}
 139
 140static struct usb_configuration config_driver = {
 141        .label                  = "HID Gadget",
 142        .bConfigurationValue    = 1,
 143        /* .iConfiguration = DYNAMIC */
 144        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 145};
 146
 147/****************************** Gadget Bind ******************************/
 148
 149static int __init hid_bind(struct usb_composite_dev *cdev)
 150{
 151        struct usb_gadget *gadget = cdev->gadget;
 152        struct list_head *tmp;
 153        int status, gcnum, funcs = 0;
 154
 155        list_for_each(tmp, &hidg_func_list)
 156                funcs++;
 157
 158        if (!funcs)
 159                return -ENODEV;
 160
 161        /* set up HID */
 162        status = ghid_setup(cdev->gadget, funcs);
 163        if (status < 0)
 164                return status;
 165
 166        gcnum = usb_gadget_controller_number(gadget);
 167        if (gcnum >= 0)
 168                device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
 169        else
 170                device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
 171
 172
 173        /* Allocate string descriptor numbers ... note that string
 174         * contents can be overridden by the composite_dev glue.
 175         */
 176
 177        /* device descriptor strings: manufacturer, product */
 178        snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
 179                init_utsname()->sysname, init_utsname()->release,
 180                gadget->name);
 181        status = usb_string_id(cdev);
 182        if (status < 0)
 183                return status;
 184        strings_dev[STRING_MANUFACTURER_IDX].id = status;
 185        device_desc.iManufacturer = status;
 186
 187        status = usb_string_id(cdev);
 188        if (status < 0)
 189                return status;
 190        strings_dev[STRING_PRODUCT_IDX].id = status;
 191        device_desc.iProduct = status;
 192
 193        /* register our configuration */
 194        status = usb_add_config(cdev, &config_driver, do_config);
 195        if (status < 0)
 196                return status;
 197
 198        dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 199
 200        return 0;
 201}
 202
 203static int __exit hid_unbind(struct usb_composite_dev *cdev)
 204{
 205        ghid_cleanup();
 206        return 0;
 207}
 208
 209static int __init hidg_plat_driver_probe(struct platform_device *pdev)
 210{
 211        struct hidg_func_descriptor *func = pdev->dev.platform_data;
 212        struct hidg_func_node *entry;
 213
 214        if (!func) {
 215                dev_err(&pdev->dev, "Platform data missing\n");
 216                return -ENODEV;
 217        }
 218
 219        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 220        if (!entry)
 221                return -ENOMEM;
 222
 223        entry->func = func;
 224        list_add_tail(&entry->node, &hidg_func_list);
 225
 226        return 0;
 227}
 228
 229static int __devexit hidg_plat_driver_remove(struct platform_device *pdev)
 230{
 231        struct hidg_func_node *e, *n;
 232
 233        list_for_each_entry_safe(e, n, &hidg_func_list, node) {
 234                list_del(&e->node);
 235                kfree(e);
 236        }
 237
 238        return 0;
 239}
 240
 241
 242/****************************** Some noise ******************************/
 243
 244
 245static struct usb_composite_driver hidg_driver = {
 246        .name           = "g_hid",
 247        .dev            = &device_desc,
 248        .strings        = dev_strings,
 249        .max_speed      = USB_SPEED_HIGH,
 250        .unbind         = __exit_p(hid_unbind),
 251};
 252
 253static struct platform_driver hidg_plat_driver = {
 254        .remove         = __devexit_p(hidg_plat_driver_remove),
 255        .driver         = {
 256                .owner  = THIS_MODULE,
 257                .name   = "hidg",
 258        },
 259};
 260
 261
 262MODULE_DESCRIPTION(DRIVER_DESC);
 263MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
 264MODULE_LICENSE("GPL");
 265
 266static int __init hidg_init(void)
 267{
 268        int status;
 269
 270        status = platform_driver_probe(&hidg_plat_driver,
 271                                hidg_plat_driver_probe);
 272        if (status < 0)
 273                return status;
 274
 275        status = usb_composite_probe(&hidg_driver, hid_bind);
 276        if (status < 0)
 277                platform_driver_unregister(&hidg_plat_driver);
 278
 279        return status;
 280}
 281module_init(hidg_init);
 282
 283static void __exit hidg_cleanup(void)
 284{
 285        platform_driver_unregister(&hidg_plat_driver);
 286        usb_composite_unregister(&hidg_driver);
 287}
 288module_exit(hidg_cleanup);
 289
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.