linux/drivers/usb/gadget/acm_ms.c
<<
>>
Prefs
   1/*
   2 * acm_ms.c -- Composite driver, with ACM and mass storage support
   3 *
   4 * Copyright (C) 2008 David Brownell
   5 * Copyright (C) 2008 Nokia Corporation
   6 * Author: David Brownell
   7 * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
   8 *
   9 * Heavily based on multi.c and cdc2.c
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19
  20#include "u_serial.h"
  21
  22#define DRIVER_DESC             "Composite Gadget (ACM + MS)"
  23#define DRIVER_VERSION          "2011/10/10"
  24
  25/*-------------------------------------------------------------------------*/
  26
  27/*
  28 * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  29 * Instead:  allocate your own, using normal USB-IF procedures.
  30 */
  31#define ACM_MS_VENDOR_NUM       0x1d6b  /* Linux Foundation */
  32#define ACM_MS_PRODUCT_NUM      0x0106  /* Composite Gadget: ACM + MS*/
  33
  34/*-------------------------------------------------------------------------*/
  35
  36/*
  37 * Kbuild is not very cooperative with respect to linking separately
  38 * compiled library objects into one module.  So for now we won't use
  39 * separate compilation ... ensuring init/exit sections work to shrink
  40 * the runtime footprint, and giving us at least some parts of what
  41 * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
  42 */
  43#include "f_mass_storage.c"
  44
  45/*-------------------------------------------------------------------------*/
  46USB_GADGET_COMPOSITE_OPTIONS();
  47
  48static struct usb_device_descriptor device_desc = {
  49        .bLength =              sizeof device_desc,
  50        .bDescriptorType =      USB_DT_DEVICE,
  51
  52        .bcdUSB =               cpu_to_le16(0x0200),
  53
  54        .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
  55        .bDeviceSubClass =      2,
  56        .bDeviceProtocol =      1,
  57
  58        /* .bMaxPacketSize0 = f(hardware) */
  59
  60        /* Vendor and product id can be overridden by module parameters.  */
  61        .idVendor =             cpu_to_le16(ACM_MS_VENDOR_NUM),
  62        .idProduct =            cpu_to_le16(ACM_MS_PRODUCT_NUM),
  63        /* .bcdDevice = f(hardware) */
  64        /* .iManufacturer = DYNAMIC */
  65        /* .iProduct = DYNAMIC */
  66        /* NO SERIAL NUMBER */
  67        /*.bNumConfigurations = DYNAMIC*/
  68};
  69
  70static struct usb_otg_descriptor otg_descriptor = {
  71        .bLength =              sizeof otg_descriptor,
  72        .bDescriptorType =      USB_DT_OTG,
  73
  74        /*
  75         * REVISIT SRP-only hardware is possible, although
  76         * it would not be called "OTG" ...
  77         */
  78        .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
  79};
  80
  81static const struct usb_descriptor_header *otg_desc[] = {
  82        (struct usb_descriptor_header *) &otg_descriptor,
  83        NULL,
  84};
  85
  86/* string IDs are assigned dynamically */
  87static struct usb_string strings_dev[] = {
  88        [USB_GADGET_MANUFACTURER_IDX].s = "",
  89        [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
  90        [USB_GADGET_SERIAL_IDX].s = "",
  91        {  } /* end of list */
  92};
  93
  94static struct usb_gadget_strings stringtab_dev = {
  95        .language       = 0x0409,       /* en-us */
  96        .strings        = strings_dev,
  97};
  98
  99static struct usb_gadget_strings *dev_strings[] = {
 100        &stringtab_dev,
 101        NULL,
 102};
 103
 104/****************************** Configurations ******************************/
 105
 106static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
 107FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
 108
 109static struct fsg_common fsg_common;
 110
 111/*-------------------------------------------------------------------------*/
 112static struct usb_function *f_acm;
 113static struct usb_function_instance *f_acm_inst;
 114/*
 115 * We _always_ have both ACM and mass storage functions.
 116 */
 117static int __init acm_ms_do_config(struct usb_configuration *c)
 118{
 119        int     status;
 120
 121        if (gadget_is_otg(c->cdev->gadget)) {
 122                c->descriptors = otg_desc;
 123                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 124        }
 125
 126        f_acm_inst = usb_get_function_instance("acm");
 127        if (IS_ERR(f_acm_inst))
 128                return PTR_ERR(f_acm_inst);
 129
 130        f_acm = usb_get_function(f_acm_inst);
 131        if (IS_ERR(f_acm)) {
 132                status = PTR_ERR(f_acm);
 133                goto err_func;
 134        }
 135
 136        status = usb_add_function(c, f_acm);
 137        if (status < 0)
 138                goto err_conf;
 139
 140        status = fsg_bind_config(c->cdev, c, &fsg_common);
 141        if (status < 0)
 142                goto err_fsg;
 143
 144        return 0;
 145err_fsg:
 146        usb_remove_function(c, f_acm);
 147err_conf:
 148        usb_put_function(f_acm);
 149err_func:
 150        usb_put_function_instance(f_acm_inst);
 151        return status;
 152}
 153
 154static struct usb_configuration acm_ms_config_driver = {
 155        .label                  = DRIVER_DESC,
 156        .bConfigurationValue    = 1,
 157        /* .iConfiguration = DYNAMIC */
 158        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 159};
 160
 161/*-------------------------------------------------------------------------*/
 162
 163static int __init acm_ms_bind(struct usb_composite_dev *cdev)
 164{
 165        struct usb_gadget       *gadget = cdev->gadget;
 166        int                     status;
 167        void                    *retp;
 168
 169        /* set up mass storage function */
 170        retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
 171        if (IS_ERR(retp)) {
 172                status = PTR_ERR(retp);
 173                return PTR_ERR(retp);
 174        }
 175
 176        /*
 177         * Allocate string descriptor numbers ... note that string
 178         * contents can be overridden by the composite_dev glue.
 179         */
 180        status = usb_string_ids_tab(cdev, strings_dev);
 181        if (status < 0)
 182                goto fail1;
 183        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
 184        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 185
 186        /* register our configuration */
 187        status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
 188        if (status < 0)
 189                goto fail1;
 190
 191        usb_composite_overwrite_options(cdev, &coverwrite);
 192        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
 193                        DRIVER_DESC);
 194        fsg_common_put(&fsg_common);
 195        return 0;
 196
 197        /* error recovery */
 198fail1:
 199        fsg_common_put(&fsg_common);
 200        return status;
 201}
 202
 203static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
 204{
 205        usb_put_function(f_acm);
 206        usb_put_function_instance(f_acm_inst);
 207        return 0;
 208}
 209
 210static __refdata struct usb_composite_driver acm_ms_driver = {
 211        .name           = "g_acm_ms",
 212        .dev            = &device_desc,
 213        .max_speed      = USB_SPEED_SUPER,
 214        .strings        = dev_strings,
 215        .bind           = acm_ms_bind,
 216        .unbind         = __exit_p(acm_ms_unbind),
 217};
 218
 219MODULE_DESCRIPTION(DRIVER_DESC);
 220MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
 221MODULE_LICENSE("GPL v2");
 222
 223static int __init init(void)
 224{
 225        return usb_composite_probe(&acm_ms_driver);
 226}
 227module_init(init);
 228
 229static void __exit cleanup(void)
 230{
 231        usb_composite_unregister(&acm_ms_driver);
 232}
 233module_exit(cleanup);
 234