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