1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * ncm.c -- NCM gadget driver 4 * 5 * Copyright (C) 2010 Nokia Corporation 6 * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com> 7 * 8 * The driver borrows from ether.c which is: 9 * 10 * Copyright (C) 2003-2005,2008 David Brownell 11 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger 12 * Copyright (C) 2008 Nokia Corporation 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 */ 19 20 /* #define DEBUG */ 21 /* #define VERBOSE_DEBUG */ 22 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/usb/composite.h> 26 27 #include "u_ether.h" 28 #include "u_ncm.h" 29 30 #define DRIVER_DESC "NCM Gadget" 31 32 /*-------------------------------------------------------------------------*/ 33 34 /* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! 35 * Instead: allocate your own, using normal USB-IF procedures. 36 */ 37 38 /* Thanks to NetChip Technologies for donating this product ID. 39 * It's for devices with only CDC Ethernet configurations. 40 */ 41 #define CDC_VENDOR_NUM 0x0525 /* NetChip */ 42 #define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ 43 44 /*-------------------------------------------------------------------------*/ 45 USB_GADGET_COMPOSITE_OPTIONS(); 46 47 USB_ETHERNET_MODULE_PARAMETERS(); 48 49 static struct usb_device_descriptor device_desc = { 50 .bLength = sizeof device_desc, 51 .bDescriptorType = USB_DT_DEVICE, 52 53 /* .bcdUSB = DYNAMIC */ 54 55 .bDeviceClass = USB_CLASS_COMM, 56 .bDeviceSubClass = 0, 57 .bDeviceProtocol = 0, 58 /* .bMaxPacketSize0 = f(hardware) */ 59 60 /* Vendor and product id defaults change according to what configs 61 * we support. (As does bNumConfigurations.) These values can 62 * also be overridden by module parameters. 63 */ 64 .idVendor = cpu_to_le16 (CDC_VENDOR_NUM), 65 .idProduct = cpu_to_le16 (CDC_PRODUCT_NUM), 66 /* .bcdDevice = f(hardware) */ 67 /* .iManufacturer = DYNAMIC */ 68 /* .iProduct = DYNAMIC */ 69 /* NO SERIAL NUMBER */ 70 .bNumConfigurations = 1, 71 }; 72 73 static const struct usb_descriptor_header *otg_desc[2]; 74 75 /* string IDs are assigned dynamically */ 76 static struct usb_string strings_dev[] = { 77 [USB_GADGET_MANUFACTURER_IDX].s = "", 78 [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, 79 [USB_GADGET_SERIAL_IDX].s = "", 80 { } /* end of list */ 81 }; 82 83 static struct usb_gadget_strings stringtab_dev = { 84 .language = 0x0409, /* en-us */ 85 .strings = strings_dev, 86 }; 87 88 static struct usb_gadget_strings *dev_strings[] = { 89 &stringtab_dev, 90 NULL, 91 }; 92 93 static struct usb_function_instance *f_ncm_inst; 94 static struct usb_function *f_ncm; 95 96 /*-------------------------------------------------------------------------*/ 97 98 static int ncm_do_config(struct usb_configuration *c) 99 { 100 int status; 101 102 /* FIXME alloc iConfiguration string, set it in c->strings */ 103 104 if (gadget_is_otg(c->cdev->gadget)) { 105 c->descriptors = otg_desc; 106 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 107 } 108 109 f_ncm = usb_get_function(f_ncm_inst); 110 if (IS_ERR(f_ncm)) { 111 status = PTR_ERR(f_ncm); 112 return status; 113 } 114 115 status = usb_add_function(c, f_ncm); 116 if (status < 0) { 117 usb_put_function(f_ncm); 118 return status; 119 } 120 121 return 0; 122 } 123 124 static struct usb_configuration ncm_config_driver = { 125 /* .label = f(hardware) */ 126 .label = "CDC Ethernet (NCM)", 127 .bConfigurationValue = 1, 128 /* .iConfiguration = DYNAMIC */ 129 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 130 }; 131 132 /*-------------------------------------------------------------------------*/ 133 134 static int gncm_bind(struct usb_composite_dev *cdev) 135 { 136 struct usb_gadget *gadget = cdev->gadget; 137 struct f_ncm_opts *ncm_opts; 138 int status; 139 140 f_ncm_inst = usb_get_function_instance("ncm"); 141 if (IS_ERR(f_ncm_inst)) 142 return PTR_ERR(f_ncm_inst); 143 144 ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); 145 146 gether_set_qmult(ncm_opts->net, qmult); 147 if (!gether_set_host_addr(ncm_opts->net, host_addr)) 148 pr_info("using host ethernet address: %s", host_addr); 149 if (!gether_set_dev_addr(ncm_opts->net, dev_addr)) 150 pr_info("using self ethernet address: %s", dev_addr); 151 152 /* Allocate string descriptor numbers ... note that string 153 * contents can be overridden by the composite_dev glue. 154 */ 155 156 status = usb_string_ids_tab(cdev, strings_dev); 157 if (status < 0) 158 goto fail; 159 device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; 160 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 161 162 if (gadget_is_otg(gadget) && !otg_desc[0]) { 163 struct usb_descriptor_header *usb_desc; 164 165 usb_desc = usb_otg_descriptor_alloc(gadget); 166 if (!usb_desc) 167 goto fail; 168 usb_otg_descriptor_init(gadget, usb_desc); 169 otg_desc[0] = usb_desc; 170 otg_desc[1] = NULL; 171 } 172 173 status = usb_add_config(cdev, &ncm_config_driver, 174 ncm_do_config); 175 if (status < 0) 176 goto fail1; 177 178 usb_composite_overwrite_options(cdev, &coverwrite); 179 dev_info(&gadget->dev, "%s\n", DRIVER_DESC); 180 181 return 0; 182 183 fail1: 184 kfree(otg_desc[0]); 185 otg_desc[0] = NULL; 186 fail: 187 usb_put_function_instance(f_ncm_inst); 188 return status; 189 } 190 191 static int gncm_unbind(struct usb_composite_dev *cdev) 192 { 193 if (!IS_ERR_OR_NULL(f_ncm)) 194 usb_put_function(f_ncm); 195 if (!IS_ERR_OR_NULL(f_ncm_inst)) 196 usb_put_function_instance(f_ncm_inst); 197 kfree(otg_desc[0]); 198 otg_desc[0] = NULL; 199 200 return 0; 201 } 202 203 static struct usb_composite_driver ncm_driver = { 204 .name = "g_ncm", 205 .dev = &device_desc, 206 .strings = dev_strings, 207 .max_speed = USB_SPEED_HIGH, 208 .bind = gncm_bind, 209 .unbind = gncm_unbind, 210 }; 211 212 module_usb_composite_driver(ncm_driver); 213 214 MODULE_DESCRIPTION(DRIVER_DESC); 215 MODULE_AUTHOR("Yauheni Kaliuta"); 216 MODULE_LICENSE("GPL"); 217