1/* 2 * nokia.c -- Nokia Composite Gadget Driver 3 * 4 * Copyright (C) 2008-2010 Nokia Corporation 5 * Contact: Felipe Balbi <felipe.balbi@nokia.com> 6 * 7 * This gadget driver borrows from serial.c which is: 8 * 9 * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) 10 * Copyright (C) 2008 by David Brownell 11 * Copyright (C) 2008 by Nokia Corporation 12 * 13 * This software is distributed under the terms of the GNU General 14 * Public License ("GPL") as published by the Free Software Foundation, 15 * version 2 of that License. 16 */ 17 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/device.h> 21 22#include "u_serial.h" 23#include "u_ether.h" 24#include "u_phonet.h" 25#include "u_ecm.h" 26#include "gadget_chips.h" 27 28/* Defines */ 29 30#define NOKIA_VERSION_NUM 0x0211 31#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" 32 33USB_GADGET_COMPOSITE_OPTIONS(); 34 35USB_ETHERNET_MODULE_PARAMETERS(); 36 37#define NOKIA_VENDOR_ID 0x0421 /* Nokia */ 38#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ 39 40/* string IDs are assigned dynamically */ 41 42#define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX 43 44static char manufacturer_nokia[] = "Nokia"; 45static const char product_nokia[] = NOKIA_LONG_NAME; 46static const char description_nokia[] = "PC-Suite Configuration"; 47 48static struct usb_string strings_dev[] = { 49 [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia, 50 [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME, 51 [USB_GADGET_SERIAL_IDX].s = "", 52 [STRING_DESCRIPTION_IDX].s = description_nokia, 53 { } /* end of list */ 54}; 55 56static struct usb_gadget_strings stringtab_dev = { 57 .language = 0x0409, /* en-us */ 58 .strings = strings_dev, 59}; 60 61static struct usb_gadget_strings *dev_strings[] = { 62 &stringtab_dev, 63 NULL, 64}; 65 66static struct usb_device_descriptor device_desc = { 67 .bLength = USB_DT_DEVICE_SIZE, 68 .bDescriptorType = USB_DT_DEVICE, 69 .bcdUSB = __constant_cpu_to_le16(0x0200), 70 .bDeviceClass = USB_CLASS_COMM, 71 .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), 72 .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), 73 .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM), 74 /* .iManufacturer = DYNAMIC */ 75 /* .iProduct = DYNAMIC */ 76 .bNumConfigurations = 1, 77}; 78 79/*-------------------------------------------------------------------------*/ 80 81/* Module */ 82MODULE_DESCRIPTION("Nokia composite gadget driver for N900"); 83MODULE_AUTHOR("Felipe Balbi"); 84MODULE_LICENSE("GPL"); 85 86/*-------------------------------------------------------------------------*/ 87static struct usb_function *f_acm_cfg1; 88static struct usb_function *f_acm_cfg2; 89static struct usb_function *f_ecm_cfg1; 90static struct usb_function *f_ecm_cfg2; 91static struct usb_function *f_obex1_cfg1; 92static struct usb_function *f_obex2_cfg1; 93static struct usb_function *f_obex1_cfg2; 94static struct usb_function *f_obex2_cfg2; 95static struct usb_function *f_phonet_cfg1; 96static struct usb_function *f_phonet_cfg2; 97 98 99static struct usb_configuration nokia_config_500ma_driver = { 100 .label = "Bus Powered", 101 .bConfigurationValue = 1, 102 /* .iConfiguration = DYNAMIC */ 103 .bmAttributes = USB_CONFIG_ATT_ONE, 104 .MaxPower = 500, 105}; 106 107static struct usb_configuration nokia_config_100ma_driver = { 108 .label = "Self Powered", 109 .bConfigurationValue = 2, 110 /* .iConfiguration = DYNAMIC */ 111 .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 112 .MaxPower = 100, 113}; 114 115static struct usb_function_instance *fi_acm; 116static struct usb_function_instance *fi_ecm; 117static struct usb_function_instance *fi_obex1; 118static struct usb_function_instance *fi_obex2; 119static struct usb_function_instance *fi_phonet; 120 121static int nokia_bind_config(struct usb_configuration *c) 122{ 123 struct usb_function *f_acm; 124 struct usb_function *f_phonet = NULL; 125 struct usb_function *f_obex1 = NULL; 126 struct usb_function *f_ecm; 127 struct usb_function *f_obex2 = NULL; 128 int status = 0; 129 int obex1_stat = -1; 130 int obex2_stat = -1; 131 int phonet_stat = -1; 132 133 if (!IS_ERR(fi_phonet)) { 134 f_phonet = usb_get_function(fi_phonet); 135 if (IS_ERR(f_phonet)) 136 pr_debug("could not get phonet function\n"); 137 } 138 139 if (!IS_ERR(fi_obex1)) { 140 f_obex1 = usb_get_function(fi_obex1); 141 if (IS_ERR(f_obex1)) 142 pr_debug("could not get obex function 0\n"); 143 } 144 145 if (!IS_ERR(fi_obex2)) { 146 f_obex2 = usb_get_function(fi_obex2); 147 if (IS_ERR(f_obex2)) 148 pr_debug("could not get obex function 1\n"); 149 } 150 151 f_acm = usb_get_function(fi_acm); 152 if (IS_ERR(f_acm)) { 153 status = PTR_ERR(f_acm); 154 goto err_get_acm; 155 } 156 157 f_ecm = usb_get_function(fi_ecm); 158 if (IS_ERR(f_ecm)) { 159 status = PTR_ERR(f_ecm); 160 goto err_get_ecm; 161 } 162 163 if (!IS_ERR_OR_NULL(f_phonet)) { 164 phonet_stat = usb_add_function(c, f_phonet); 165 if (phonet_stat) 166 pr_debug("could not add phonet function\n"); 167 } 168 169 if (!IS_ERR_OR_NULL(f_obex1)) { 170 obex1_stat = usb_add_function(c, f_obex1); 171 if (obex1_stat) 172 pr_debug("could not add obex function 0\n"); 173 } 174 175 if (!IS_ERR_OR_NULL(f_obex2)) { 176 obex2_stat = usb_add_function(c, f_obex2); 177 if (obex2_stat) 178 pr_debug("could not add obex function 1\n"); 179 } 180 181 status = usb_add_function(c, f_acm); 182 if (status) 183 goto err_conf; 184 185 status = usb_add_function(c, f_ecm); 186 if (status) { 187 pr_debug("could not bind ecm config %d\n", status); 188 goto err_ecm; 189 } 190 if (c == &nokia_config_500ma_driver) { 191 f_acm_cfg1 = f_acm; 192 f_ecm_cfg1 = f_ecm; 193 f_phonet_cfg1 = f_phonet; 194 f_obex1_cfg1 = f_obex1; 195 f_obex2_cfg1 = f_obex2; 196 } else { 197 f_acm_cfg2 = f_acm; 198 f_ecm_cfg2 = f_ecm; 199 f_phonet_cfg2 = f_phonet; 200 f_obex1_cfg2 = f_obex1; 201 f_obex2_cfg2 = f_obex2; 202 } 203 204 return status; 205err_ecm: 206 usb_remove_function(c, f_acm); 207err_conf: 208 if (!obex2_stat) 209 usb_remove_function(c, f_obex2); 210 if (!obex1_stat) 211 usb_remove_function(c, f_obex1); 212 if (!phonet_stat) 213 usb_remove_function(c, f_phonet); 214 usb_put_function(f_ecm); 215err_get_ecm: 216 usb_put_function(f_acm); 217err_get_acm: 218 if (!IS_ERR_OR_NULL(f_obex2)) 219 usb_put_function(f_obex2); 220 if (!IS_ERR_OR_NULL(f_obex1)) 221 usb_put_function(f_obex1); 222 if (!IS_ERR_OR_NULL(f_phonet)) 223 usb_put_function(f_phonet); 224 return status; 225} 226 227static int nokia_bind(struct usb_composite_dev *cdev) 228{ 229 struct usb_gadget *gadget = cdev->gadget; 230 int status; 231 232 status = usb_string_ids_tab(cdev, strings_dev); 233 if (status < 0) 234 goto err_usb; 235 device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; 236 device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; 237 status = strings_dev[STRING_DESCRIPTION_IDX].id; 238 nokia_config_500ma_driver.iConfiguration = status; 239 nokia_config_100ma_driver.iConfiguration = status; 240 241 if (!gadget_supports_altsettings(gadget)) { 242 status = -ENODEV; 243 goto err_usb; 244 } 245 246 fi_phonet = usb_get_function_instance("phonet"); 247 if (IS_ERR(fi_phonet)) 248 pr_debug("could not find phonet function\n"); 249 250 fi_obex1 = usb_get_function_instance("obex"); 251 if (IS_ERR(fi_obex1)) 252 pr_debug("could not find obex function 1\n"); 253 254 fi_obex2 = usb_get_function_instance("obex"); 255 if (IS_ERR(fi_obex2)) 256 pr_debug("could not find obex function 2\n"); 257 258 fi_acm = usb_get_function_instance("acm"); 259 if (IS_ERR(fi_acm)) { 260 status = PTR_ERR(fi_acm); 261 goto err_obex2_inst; 262 } 263 264 fi_ecm = usb_get_function_instance("ecm"); 265 if (IS_ERR(fi_ecm)) { 266 status = PTR_ERR(fi_ecm); 267 goto err_acm_inst; 268 } 269 270 /* finally register the configuration */ 271 status = usb_add_config(cdev, &nokia_config_500ma_driver, 272 nokia_bind_config); 273 if (status < 0) 274 goto err_ecm_inst; 275 276 status = usb_add_config(cdev, &nokia_config_100ma_driver, 277 nokia_bind_config); 278 if (status < 0) 279 goto err_put_cfg1; 280 281 usb_composite_overwrite_options(cdev, &coverwrite); 282 dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); 283 284 return 0; 285 286err_put_cfg1: 287 usb_put_function(f_acm_cfg1); 288 if (!IS_ERR_OR_NULL(f_obex1_cfg1)) 289 usb_put_function(f_obex1_cfg1); 290 if (!IS_ERR_OR_NULL(f_obex2_cfg1)) 291 usb_put_function(f_obex2_cfg1); 292 if (!IS_ERR_OR_NULL(f_phonet_cfg1)) 293 usb_put_function(f_phonet_cfg1); 294 usb_put_function(f_ecm_cfg1); 295err_ecm_inst: 296 usb_put_function_instance(fi_ecm); 297err_acm_inst: 298 usb_put_function_instance(fi_acm); 299err_obex2_inst: 300 if (!IS_ERR(fi_obex2)) 301 usb_put_function_instance(fi_obex2); 302 if (!IS_ERR(fi_obex1)) 303 usb_put_function_instance(fi_obex1); 304 if (!IS_ERR(fi_phonet)) 305 usb_put_function_instance(fi_phonet); 306err_usb: 307 return status; 308} 309 310static int nokia_unbind(struct usb_composite_dev *cdev) 311{ 312 if (!IS_ERR_OR_NULL(f_obex1_cfg2)) 313 usb_put_function(f_obex1_cfg2); 314 if (!IS_ERR_OR_NULL(f_obex2_cfg2)) 315 usb_put_function(f_obex2_cfg2); 316 if (!IS_ERR_OR_NULL(f_obex1_cfg1)) 317 usb_put_function(f_obex1_cfg1); 318 if (!IS_ERR_OR_NULL(f_obex2_cfg1)) 319 usb_put_function(f_obex2_cfg1); 320 if (!IS_ERR_OR_NULL(f_phonet_cfg1)) 321 usb_put_function(f_phonet_cfg1); 322 if (!IS_ERR_OR_NULL(f_phonet_cfg2)) 323 usb_put_function(f_phonet_cfg2); 324 usb_put_function(f_acm_cfg1); 325 usb_put_function(f_acm_cfg2); 326 usb_put_function(f_ecm_cfg1); 327 usb_put_function(f_ecm_cfg2); 328 329 usb_put_function_instance(fi_ecm); 330 if (!IS_ERR(fi_obex2)) 331 usb_put_function_instance(fi_obex2); 332 if (!IS_ERR(fi_obex1)) 333 usb_put_function_instance(fi_obex1); 334 if (!IS_ERR(fi_phonet)) 335 usb_put_function_instance(fi_phonet); 336 usb_put_function_instance(fi_acm); 337 338 return 0; 339} 340 341static struct usb_composite_driver nokia_driver = { 342 .name = "g_nokia", 343 .dev = &device_desc, 344 .strings = dev_strings, 345 .max_speed = USB_SPEED_HIGH, 346 .bind = nokia_bind, 347 .unbind = nokia_unbind, 348}; 349 350module_usb_composite_driver(nokia_driver); 351