linux/drivers/usb/gadget/legacy/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#include "f_mass_storage.h"
  35
  36/*-------------------------------------------------------------------------*/
  37USB_GADGET_COMPOSITE_OPTIONS();
  38
  39static struct usb_device_descriptor device_desc = {
  40        .bLength =              sizeof device_desc,
  41        .bDescriptorType =      USB_DT_DEVICE,
  42
  43        /* .bcdUSB = DYNAMIC */
  44
  45        .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
  46        .bDeviceSubClass =      2,
  47        .bDeviceProtocol =      1,
  48
  49        /* .bMaxPacketSize0 = f(hardware) */
  50
  51        /* Vendor and product id can be overridden by module parameters.  */
  52        .idVendor =             cpu_to_le16(ACM_MS_VENDOR_NUM),
  53        .idProduct =            cpu_to_le16(ACM_MS_PRODUCT_NUM),
  54        /* .bcdDevice = f(hardware) */
  55        /* .iManufacturer = DYNAMIC */
  56        /* .iProduct = DYNAMIC */
  57        /* NO SERIAL NUMBER */
  58        /*.bNumConfigurations = DYNAMIC*/
  59};
  60
  61static const struct usb_descriptor_header *otg_desc[2];
  62
  63/* string IDs are assigned dynamically */
  64static struct usb_string strings_dev[] = {
  65        [USB_GADGET_MANUFACTURER_IDX].s = "",
  66        [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
  67        [USB_GADGET_SERIAL_IDX].s = "",
  68        {  } /* end of list */
  69};
  70
  71static struct usb_gadget_strings stringtab_dev = {
  72        .language       = 0x0409,       /* en-us */
  73        .strings        = strings_dev,
  74};
  75
  76static struct usb_gadget_strings *dev_strings[] = {
  77        &stringtab_dev,
  78        NULL,
  79};
  80
  81/****************************** Configurations ******************************/
  82
  83static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
  84#ifdef CONFIG_USB_GADGET_DEBUG_FILES
  85
  86static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
  87
  88#else
  89
  90/*
  91 * Number of buffers we will use.
  92 * 2 is usually enough for good buffering pipeline
  93 */
  94#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
  95
  96#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
  97
  98FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
  99
 100/*-------------------------------------------------------------------------*/
 101static struct usb_function *f_acm;
 102static struct usb_function_instance *f_acm_inst;
 103
 104static struct usb_function_instance *fi_msg;
 105static struct usb_function *f_msg;
 106
 107/*
 108 * We _always_ have both ACM and mass storage functions.
 109 */
 110static int acm_ms_do_config(struct usb_configuration *c)
 111{
 112        struct fsg_opts *opts;
 113        int     status;
 114
 115        if (gadget_is_otg(c->cdev->gadget)) {
 116                c->descriptors = otg_desc;
 117                c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 118        }
 119
 120        opts = fsg_opts_from_func_inst(fi_msg);
 121
 122        f_acm = usb_get_function(f_acm_inst);
 123        if (IS_ERR(f_acm))
 124                return PTR_ERR(f_acm);
 125
 126        f_msg = usb_get_function(fi_msg);
 127        if (IS_ERR(f_msg)) {
 128                status = PTR_ERR(f_msg);
 129                goto put_acm;
 130        }
 131
 132        status = usb_add_function(c, f_acm);
 133        if (status < 0)
 134                goto put_msg;
 135
 136        status = usb_add_function(c, f_msg);
 137        if (status)
 138                goto remove_acm;
 139
 140        return 0;
 141remove_acm:
 142        usb_remove_function(c, f_acm);
 143put_msg:
 144        usb_put_function(f_msg);
 145put_acm:
 146        usb_put_function(f_acm);
 147        return status;
 148}
 149
 150static struct usb_configuration acm_ms_config_driver = {
 151        .label                  = DRIVER_DESC,
 152        .bConfigurationValue    = 1,
 153        /* .iConfiguration = DYNAMIC */
 154        .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
 155};
 156
 157/*-------------------------------------------------------------------------*/
 158
 159static int acm_ms_bind(struct usb_composite_dev *cdev)
 160{
 161        struct usb_gadget       *gadget = cdev->gadget;
 162        struct fsg_opts         *opts;
 163        struct fsg_config       config;
 164        int                     status;
 165
 166        f_acm_inst = usb_get_function_instance("acm");
 167        if (IS_ERR(f_acm_inst))
 168                return PTR_ERR(f_acm_inst);
 169
 170        fi_msg = usb_get_function_instance("mass_storage");
 171        if (IS_ERR(fi_msg)) {
 172                status = PTR_ERR(fi_msg);
 173                goto fail_get_msg;
 174        }
 175
 176        /* set up mass storage function */
 177        fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
 178        opts = fsg_opts_from_func_inst(fi_msg);
 179
 180        opts->no_configfs = true;
 181        status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
 182        if (status)
 183                goto fail;
 184
 185        status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
 186        if (status)
 187                goto fail_set_cdev;
 188
 189        fsg_common_set_sysfs(opts->common, true);
 190        status = fsg_common_create_luns(opts->common, &config);
 191        if (status)
 192                goto fail_set_cdev;
 193
 194        fsg_common_set_inquiry_string(opts->common, config.vendor_name,
 195                                      config.product_name);
 196        /*
 197         * Allocate string descriptor numbers ... note that string
 198         * contents can be overridden by the composite_dev glue.
 199         */
 200        status = usb_string_ids_tab(cdev, strings_dev);
 201        if (status < 0)
 202                goto fail_string_ids;
 203        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
 204        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 205
 206        if (gadget_is_otg(gadget) && !otg_desc[0]) {
 207                struct usb_descriptor_header *usb_desc;
 208
 209                usb_desc = usb_otg_descriptor_alloc(gadget);
 210                if (!usb_desc)
 211                        goto fail_string_ids;
 212                usb_otg_descriptor_init(gadget, usb_desc);
 213                otg_desc[0] = usb_desc;
 214                otg_desc[1] = NULL;
 215        }
 216
 217        /* register our configuration */
 218        status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
 219        if (status < 0)
 220                goto fail_otg_desc;
 221
 222        usb_composite_overwrite_options(cdev, &coverwrite);
 223        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
 224                        DRIVER_DESC);
 225        return 0;
 226
 227        /* error recovery */
 228fail_otg_desc:
 229        kfree(otg_desc[0]);
 230        otg_desc[0] = NULL;
 231fail_string_ids:
 232        fsg_common_remove_luns(opts->common);
 233fail_set_cdev:
 234        fsg_common_free_buffers(opts->common);
 235fail:
 236        usb_put_function_instance(fi_msg);
 237fail_get_msg:
 238        usb_put_function_instance(f_acm_inst);
 239        return status;
 240}
 241
 242static int acm_ms_unbind(struct usb_composite_dev *cdev)
 243{
 244        usb_put_function(f_msg);
 245        usb_put_function_instance(fi_msg);
 246        usb_put_function(f_acm);
 247        usb_put_function_instance(f_acm_inst);
 248        kfree(otg_desc[0]);
 249        otg_desc[0] = NULL;
 250
 251        return 0;
 252}
 253
 254static struct usb_composite_driver acm_ms_driver = {
 255        .name           = "g_acm_ms",
 256        .dev            = &device_desc,
 257        .max_speed      = USB_SPEED_SUPER,
 258        .strings        = dev_strings,
 259        .bind           = acm_ms_bind,
 260        .unbind         = acm_ms_unbind,
 261};
 262
 263module_usb_composite_driver(acm_ms_driver);
 264
 265MODULE_DESCRIPTION(DRIVER_DESC);
 266MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
 267MODULE_LICENSE("GPL v2");
 268