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/*-------------------------------------------------------------------------*/ 44USB_GADGET_COMPOSITE_OPTIONS(); 45 46USB_ETHERNET_MODULE_PARAMETERS(); 47 48static 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 72static const struct usb_descriptor_header *otg_desc[2]; 73 74/* string IDs are assigned dynamically */ 75static struct usb_string strings_dev[] = { 76 [USB_GADGET_MANUFACTURER_IDX].s = "", 77 [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, 78 [USB_GADGET_SERIAL_IDX].s = "", 79 { } /* end of list */ 80}; 81 82static struct usb_gadget_strings stringtab_dev = { 83 .language = 0x0409, /* en-us */ 84 .strings = strings_dev, 85}; 86 87static struct usb_gadget_strings *dev_strings[] = { 88 &stringtab_dev, 89 NULL, 90}; 91 92static struct usb_function_instance *f_ncm_inst; 93static struct usb_function *f_ncm; 94 95/*-------------------------------------------------------------------------*/ 96 97static int ncm_do_config(struct usb_configuration *c) 98{ 99 int status; 100 101 /* FIXME alloc iConfiguration string, set it in c->strings */ 102 103 if (gadget_is_otg(c->cdev->gadget)) { 104 c->descriptors = otg_desc; 105 c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; 106 } 107 108 f_ncm = usb_get_function(f_ncm_inst); 109 if (IS_ERR(f_ncm)) { 110 status = PTR_ERR(f_ncm); 111 return status; 112 } 113 114 status = usb_add_function(c, f_ncm); 115 if (status < 0) { 116 usb_put_function(f_ncm); 117 return status; 118 } 119 120 return 0; 121} 122 123static struct usb_configuration ncm_config_driver = { 124 /* .label = f(hardware) */ 125 .label = "CDC Ethernet (NCM)", 126 .bConfigurationValue = 1, 127 /* .iConfiguration = DYNAMIC */ 128 .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 129}; 130 131/*-------------------------------------------------------------------------*/ 132 133static int gncm_bind(struct usb_composite_dev *cdev) 134{ 135 struct usb_gadget *gadget = cdev->gadget; 136 struct f_ncm_opts *ncm_opts; 137 int status; 138 139 f_ncm_inst = usb_get_function_instance("ncm"); 140 if (IS_ERR(f_ncm_inst)) 141 return PTR_ERR(f_ncm_inst); 142 143 ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst); 144 145 gether_set_qmult(ncm_opts->net, qmult); 146 if (!gether_set_host_addr(ncm_opts->net, host_addr)) 147 pr_info("using host ethernet address: %s", host_addr); 148 if (!gether_set_dev_addr(ncm_opts->net, dev_addr)) 149 pr_info("using self ethernet address: %s", dev_addr); 150 151 /* Allocate string descriptor numbers ... note that string 152 * contents can be overridden by the composite_dev glue. 153 */ 154 155 status = usb_string_ids_tab(cdev, strings_dev); 156 if (status < 0) 157 goto fail; 158 device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; 159 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 160 161 if (gadget_is_otg(gadget) && !otg_desc[0]) { 162 struct usb_descriptor_header *usb_desc; 163 164 usb_desc = usb_otg_descriptor_alloc(gadget); 165 if (!usb_desc) 166 goto fail; 167 usb_otg_descriptor_init(gadget, usb_desc); 168 otg_desc[0] = usb_desc; 169 otg_desc[1] = NULL; 170 } 171 172 status = usb_add_config(cdev, &ncm_config_driver, 173 ncm_do_config); 174 if (status < 0) 175 goto fail1; 176 177 usb_composite_overwrite_options(cdev, &coverwrite); 178 dev_info(&gadget->dev, "%s\n", DRIVER_DESC); 179 180 return 0; 181 182fail1: 183 kfree(otg_desc[0]); 184 otg_desc[0] = NULL; 185fail: 186 usb_put_function_instance(f_ncm_inst); 187 return status; 188} 189 190static int gncm_unbind(struct usb_composite_dev *cdev) 191{ 192 if (!IS_ERR_OR_NULL(f_ncm)) 193 usb_put_function(f_ncm); 194 if (!IS_ERR_OR_NULL(f_ncm_inst)) 195 usb_put_function_instance(f_ncm_inst); 196 kfree(otg_desc[0]); 197 otg_desc[0] = NULL; 198 199 return 0; 200} 201 202static struct usb_composite_driver ncm_driver = { 203 .name = "g_ncm", 204 .dev = &device_desc, 205 .strings = dev_strings, 206 .max_speed = USB_SPEED_HIGH, 207 .bind = gncm_bind, 208 .unbind = gncm_unbind, 209}; 210 211module_usb_composite_driver(ncm_driver); 212 213MODULE_DESCRIPTION(DRIVER_DESC); 214MODULE_AUTHOR("Yauheni Kaliuta"); 215MODULE_LICENSE("GPL"); 216