linux/drivers/usb/gadget/legacy/serial.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * serial.c -- USB gadget serial driver
   4 *
   5 * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
   6 * Copyright (C) 2008 by David Brownell
   7 * Copyright (C) 2008 by Nokia Corporation
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/module.h>
  13#include <linux/tty.h>
  14#include <linux/tty_flip.h>
  15
  16#include "u_serial.h"
  17
  18
  19/* Defines */
  20
  21#define GS_VERSION_STR                  "v2.4"
  22#define GS_VERSION_NUM                  0x2400
  23
  24#define GS_LONG_NAME                    "Gadget Serial"
  25#define GS_VERSION_NAME                 GS_LONG_NAME " " GS_VERSION_STR
  26
  27/*-------------------------------------------------------------------------*/
  28USB_GADGET_COMPOSITE_OPTIONS();
  29
  30/* Thanks to NetChip Technologies for donating this product ID.
  31*
  32* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  33* Instead:  allocate your own, using normal USB-IF procedures.
  34*/
  35#define GS_VENDOR_ID                    0x0525  /* NetChip */
  36#define GS_PRODUCT_ID                   0xa4a6  /* Linux-USB Serial Gadget */
  37#define GS_CDC_PRODUCT_ID               0xa4a7  /* ... as CDC-ACM */
  38#define GS_CDC_OBEX_PRODUCT_ID          0xa4a9  /* ... as CDC-OBEX */
  39
  40/* string IDs are assigned dynamically */
  41
  42#define STRING_DESCRIPTION_IDX          USB_GADGET_FIRST_AVAIL_IDX
  43
  44static struct usb_string strings_dev[] = {
  45        [USB_GADGET_MANUFACTURER_IDX].s = "",
  46        [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
  47        [USB_GADGET_SERIAL_IDX].s = "",
  48        [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
  49        {  } /* end of list */
  50};
  51
  52static struct usb_gadget_strings stringtab_dev = {
  53        .language       = 0x0409,       /* en-us */
  54        .strings        = strings_dev,
  55};
  56
  57static struct usb_gadget_strings *dev_strings[] = {
  58        &stringtab_dev,
  59        NULL,
  60};
  61
  62static struct usb_device_descriptor device_desc = {
  63        .bLength =              USB_DT_DEVICE_SIZE,
  64        .bDescriptorType =      USB_DT_DEVICE,
  65        /* .bcdUSB = DYNAMIC */
  66        /* .bDeviceClass = f(use_acm) */
  67        .bDeviceSubClass =      0,
  68        .bDeviceProtocol =      0,
  69        /* .bMaxPacketSize0 = f(hardware) */
  70        .idVendor =             cpu_to_le16(GS_VENDOR_ID),
  71        /* .idProduct = f(use_acm) */
  72        .bcdDevice = cpu_to_le16(GS_VERSION_NUM),
  73        /* .iManufacturer = DYNAMIC */
  74        /* .iProduct = DYNAMIC */
  75        .bNumConfigurations =   1,
  76};
  77
  78static const struct usb_descriptor_header *otg_desc[2];
  79
  80/*-------------------------------------------------------------------------*/
  81
  82/* Module */
  83MODULE_DESCRIPTION(GS_VERSION_NAME);
  84MODULE_AUTHOR("Al Borchers");
  85MODULE_AUTHOR("David Brownell");
  86MODULE_LICENSE("GPL");
  87
  88static bool use_acm = true;
  89module_param(use_acm, bool, 0);
  90MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
  91
  92static bool use_obex = false;
  93module_param(use_obex, bool, 0);
  94MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
  95
  96static unsigned n_ports = 1;
  97module_param(n_ports, uint, 0);
  98MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
  99
 100static bool enable = true;
 101
 102static int switch_gserial_enable(bool do_enable);
 103
 104static int enable_set(const char *s, const struct kernel_param *kp)
 105{
 106        bool do_enable;
 107        int ret;
 108
 109        if (!s) /* called for no-arg enable == default */
 110                return 0;
 111
 112        ret = strtobool(s, &do_enable);
 113        if (ret || enable == do_enable)
 114                return ret;
 115
 116        ret = switch_gserial_enable(do_enable);
 117        if (!ret)
 118                enable = do_enable;
 119
 120        return ret;
 121}
 122
 123static const struct kernel_param_ops enable_ops = {
 124        .set = enable_set,
 125        .get = param_get_bool,
 126};
 127
 128module_param_cb(enable, &enable_ops, &enable, 0644);
 129
 130/*-------------------------------------------------------------------------*/
 131
 132static struct usb_configuration serial_config_driver = {
 133        /* .label = f(use_acm) */
 134        /* .bConfigurationValue = f(use_acm) */
 135        /* .iConfiguration = DYNAMIC */
 136        .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
 137};
 138
 139static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS];
 140static struct usb_function *f_serial[MAX_U_SERIAL_PORTS];
 141
 142static int serial_register_ports(struct usb_composite_dev *cdev,
 143                struct usb_configuration *c, const char *f_name)
 144{
 145        int i;
 146        int ret;
 147
 148        ret = usb_add_config_only(cdev, c);
 149        if (ret)
 150                goto out;
 151
 152        for (i = 0; i < n_ports; i++) {
 153
 154                fi_serial[i] = usb_get_function_instance(f_name);
 155                if (IS_ERR(fi_serial[i])) {
 156                        ret = PTR_ERR(fi_serial[i]);
 157                        goto fail;
 158                }
 159
 160                f_serial[i] = usb_get_function(fi_serial[i]);
 161                if (IS_ERR(f_serial[i])) {
 162                        ret = PTR_ERR(f_serial[i]);
 163                        goto err_get_func;
 164                }
 165
 166                ret = usb_add_function(c, f_serial[i]);
 167                if (ret)
 168                        goto err_add_func;
 169        }
 170
 171        return 0;
 172
 173err_add_func:
 174        usb_put_function(f_serial[i]);
 175err_get_func:
 176        usb_put_function_instance(fi_serial[i]);
 177
 178fail:
 179        i--;
 180        while (i >= 0) {
 181                usb_remove_function(c, f_serial[i]);
 182                usb_put_function(f_serial[i]);
 183                usb_put_function_instance(fi_serial[i]);
 184                i--;
 185        }
 186out:
 187        return ret;
 188}
 189
 190static int gs_bind(struct usb_composite_dev *cdev)
 191{
 192        int                     status;
 193
 194        /* Allocate string descriptor numbers ... note that string
 195         * contents can be overridden by the composite_dev glue.
 196         */
 197
 198        status = usb_string_ids_tab(cdev, strings_dev);
 199        if (status < 0)
 200                goto fail;
 201        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
 202        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 203        status = strings_dev[STRING_DESCRIPTION_IDX].id;
 204        serial_config_driver.iConfiguration = status;
 205
 206        if (gadget_is_otg(cdev->gadget)) {
 207                if (!otg_desc[0]) {
 208                        struct usb_descriptor_header *usb_desc;
 209
 210                        usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
 211                        if (!usb_desc) {
 212                                status = -ENOMEM;
 213                                goto fail;
 214                        }
 215                        usb_otg_descriptor_init(cdev->gadget, usb_desc);
 216                        otg_desc[0] = usb_desc;
 217                        otg_desc[1] = NULL;
 218                }
 219                serial_config_driver.descriptors = otg_desc;
 220                serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 221        }
 222
 223        /* register our configuration */
 224        if (use_acm) {
 225                status  = serial_register_ports(cdev, &serial_config_driver,
 226                                "acm");
 227                usb_ep_autoconfig_reset(cdev->gadget);
 228        } else if (use_obex)
 229                status = serial_register_ports(cdev, &serial_config_driver,
 230                                "obex");
 231        else {
 232                status = serial_register_ports(cdev, &serial_config_driver,
 233                                "gser");
 234        }
 235        if (status < 0)
 236                goto fail1;
 237
 238        usb_composite_overwrite_options(cdev, &coverwrite);
 239        INFO(cdev, "%s\n", GS_VERSION_NAME);
 240
 241        return 0;
 242fail1:
 243        kfree(otg_desc[0]);
 244        otg_desc[0] = NULL;
 245fail:
 246        return status;
 247}
 248
 249static int gs_unbind(struct usb_composite_dev *cdev)
 250{
 251        int i;
 252
 253        for (i = 0; i < n_ports; i++) {
 254                usb_put_function(f_serial[i]);
 255                usb_put_function_instance(fi_serial[i]);
 256        }
 257
 258        kfree(otg_desc[0]);
 259        otg_desc[0] = NULL;
 260
 261        return 0;
 262}
 263
 264static struct usb_composite_driver gserial_driver = {
 265        .name           = "g_serial",
 266        .dev            = &device_desc,
 267        .strings        = dev_strings,
 268        .max_speed      = USB_SPEED_SUPER,
 269        .bind           = gs_bind,
 270        .unbind         = gs_unbind,
 271};
 272
 273static int switch_gserial_enable(bool do_enable)
 274{
 275        if (!serial_config_driver.label)
 276                /* init() was not called, yet */
 277                return 0;
 278
 279        if (do_enable)
 280                return usb_composite_probe(&gserial_driver);
 281
 282        usb_composite_unregister(&gserial_driver);
 283        return 0;
 284}
 285
 286static int __init init(void)
 287{
 288        /* We *could* export two configs; that'd be much cleaner...
 289         * but neither of these product IDs was defined that way.
 290         */
 291        if (use_acm) {
 292                serial_config_driver.label = "CDC ACM config";
 293                serial_config_driver.bConfigurationValue = 2;
 294                device_desc.bDeviceClass = USB_CLASS_COMM;
 295                device_desc.idProduct =
 296                                cpu_to_le16(GS_CDC_PRODUCT_ID);
 297        } else if (use_obex) {
 298                serial_config_driver.label = "CDC OBEX config";
 299                serial_config_driver.bConfigurationValue = 3;
 300                device_desc.bDeviceClass = USB_CLASS_COMM;
 301                device_desc.idProduct =
 302                        cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
 303        } else {
 304                serial_config_driver.label = "Generic Serial config";
 305                serial_config_driver.bConfigurationValue = 1;
 306                device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 307                device_desc.idProduct =
 308                                cpu_to_le16(GS_PRODUCT_ID);
 309        }
 310        strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
 311
 312        if (!enable)
 313                return 0;
 314
 315        return usb_composite_probe(&gserial_driver);
 316}
 317module_init(init);
 318
 319static void __exit cleanup(void)
 320{
 321        if (enable)
 322                usb_composite_unregister(&gserial_driver);
 323}
 324module_exit(cleanup);
 325