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