1 /* 2 * Copyright 2010, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jérôme Duval, korli@users.berlios.de 7 */ 8 9 /* 10 Devices and messages reference: usb-modeswitch-data-20100826 11 */ 12 13 #include <ByteOrder.h> 14 #include <Drivers.h> 15 #include <KernelExport.h> 16 #include <lock.h> 17 #include <USB3.h> 18 19 #include <malloc.h> 20 #include <stdio.h> 21 #include <string.h> 22 23 #define DRIVER_NAME "usb_modeswitch" 24 25 #define TRACE_USB_MODESWITCH 1 26 #ifdef TRACE_USB_MODESWITCH 27 #define TRACE(x...) dprintf(DRIVER_NAME": "x) 28 #else 29 #define TRACE(x...) /* nothing */ 30 #endif 31 #define TRACE_ALWAYS(x...) dprintf(DRIVER_NAME": "x) 32 #define ENTER() TRACE("%s", __FUNCTION__) 33 34 35 enum msgType { 36 MSG_NONE = 0, 37 MSG_HUAWEI_1, 38 MSG_HUAWEI_2, 39 MSG_HUAWEI_3, 40 MSG_NOKIA_1, 41 MSG_OLIVETTI_1, 42 MSG_OLIVETTI_2, 43 MSG_OPTION_1, 44 MSG_ATHEROS_1, 45 }; 46 47 48 unsigned char kDevicesMsg[][31] = { 49 { /* MSG_HUAWEI_1 */ 50 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 52 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 54 }, 55 { /* MSG_HUAWEI_2 */ 56 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 57 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x0a, 0x11, 58 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 60 }, 61 { /* MSG_HUAWEI_3 */ 62 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 63 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 66 }, 67 { /* MSG_NOKIA_1 */ 68 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b, 70 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 72 }, 73 { /* MSG_OLIVETTI_1 */ 74 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b, 76 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 78 }, 79 { /* MSG_OLIVETTI_2 */ 80 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 81 0xc0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x06, 82 0xf5, 0x04, 0x02, 0x52, 0x70, 0x00, 0x00, 0x00, 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 84 }, 85 { /* MSG_OPTION_1 */ 86 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, 87 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x10, 88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 90 }, 91 { /* MSG_ATHEROS_1 */ 92 0x55, 0x53, 0x42, 0x43, 0x29, 0x00, 0x00, 0x00, 93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1b, 94 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 96 } 97 98 }; 99 100 101 #define HUAWEI_VENDOR 0x12d1 102 #define NOKIA_VENDOR 0x0421 103 #define NOVATEL_VENDOR 0x1410 104 #define ZYDAS_VENDOR 0x0ace 105 #define ZTE_VENDOR 0x19d2 106 #define OLIVETTI_VENDOR 0x0b3c 107 #define OPTION_VENDOR 0x0af0 108 #define ATHEROS_VENDOR 0x0cf3 109 110 111 static const struct { 112 usb_support_descriptor desc; 113 msgType type; 114 } kDevices[] = { 115 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1446}, MSG_HUAWEI_1}, 116 {{ 0, 0, 0, HUAWEI_VENDOR, 0x14ad}, MSG_HUAWEI_1}, 117 {{ 0, 0, 0, HUAWEI_VENDOR, 0x14c1}, MSG_HUAWEI_1}, 118 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1520}, MSG_HUAWEI_1}, 119 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1521}, MSG_HUAWEI_1}, 120 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1523}, MSG_HUAWEI_1}, 121 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1557}, MSG_HUAWEI_1}, 122 {{ 0, 0, 0, HUAWEI_VENDOR, 0x1031}, MSG_HUAWEI_2}, 123 {{ 0, 0, 0, HUAWEI_VENDOR, 0x101e}, MSG_HUAWEI_3}, 124 {{ 0, 0, 0, NOKIA_VENDOR, 0x060c}, MSG_NOKIA_1}, 125 {{ 0, 0, 0, NOKIA_VENDOR, 0x0610}, MSG_NOKIA_1}, 126 {{ 0, 0, 0, NOVATEL_VENDOR, 0x5010}, MSG_NOKIA_1}, 127 {{ 0, 0, 0, NOVATEL_VENDOR, 0x5020}, MSG_NOKIA_1}, 128 {{ 0, 0, 0, NOVATEL_VENDOR, 0x5030}, MSG_NOKIA_1}, 129 {{ 0, 0, 0, NOVATEL_VENDOR, 0x5031}, MSG_NOKIA_1}, 130 {{ 0, 0, 0, NOVATEL_VENDOR, 0x5041}, MSG_NOKIA_1}, 131 {{ 0, 0, 0, ZYDAS_VENDOR, 0x2011}, MSG_NOKIA_1}, 132 {{ 0, 0, 0, ZYDAS_VENDOR, 0x20ff}, MSG_NOKIA_1}, 133 {{ 0, 0, 0, ZTE_VENDOR, 0x0026}, MSG_NOKIA_1}, 134 {{ 0, 0, 0, ZTE_VENDOR, 0x0083}, MSG_NOKIA_1}, 135 {{ 0, 0, 0, ZTE_VENDOR, 0x0101}, MSG_NOKIA_1}, 136 {{ 0, 0, 0, ZTE_VENDOR, 0x0115}, MSG_NOKIA_1}, 137 {{ 0, 0, 0, ZTE_VENDOR, 0x1001}, MSG_NOKIA_1}, 138 {{ 0, 0, 0, ZTE_VENDOR, 0x1007}, MSG_NOKIA_1}, 139 {{ 0, 0, 0, ZTE_VENDOR, 0x1009}, MSG_NOKIA_1}, 140 {{ 0, 0, 0, ZTE_VENDOR, 0x1013}, MSG_NOKIA_1}, 141 {{ 0, 0, 0, OLIVETTI_VENDOR, 0xc700}, MSG_OLIVETTI_1}, 142 {{ 0, 0, 0, OLIVETTI_VENDOR, 0xf000}, MSG_OLIVETTI_2}, 143 {{ 0, 0, 0, OPTION_VENDOR, 0x6711}, MSG_OPTION_1}, 144 {{ 0, 0, 0, OPTION_VENDOR, 0x6731}, MSG_OPTION_1}, 145 {{ 0, 0, 0, OPTION_VENDOR, 0x6751}, MSG_OPTION_1}, 146 {{ 0, 0, 0, OPTION_VENDOR, 0x6771}, MSG_OPTION_1}, 147 {{ 0, 0, 0, OPTION_VENDOR, 0x6791}, MSG_OPTION_1}, 148 {{ 0, 0, 0, OPTION_VENDOR, 0x6811}, MSG_OPTION_1}, 149 {{ 0, 0, 0, OPTION_VENDOR, 0x6911}, MSG_OPTION_1}, 150 {{ 0, 0, 0, OPTION_VENDOR, 0x6951}, MSG_OPTION_1}, 151 {{ 0, 0, 0, OPTION_VENDOR, 0x6971}, MSG_OPTION_1}, 152 {{ 0, 0, 0, OPTION_VENDOR, 0x7011}, MSG_OPTION_1}, 153 {{ 0, 0, 0, OPTION_VENDOR, 0x7031}, MSG_OPTION_1}, 154 {{ 0, 0, 0, OPTION_VENDOR, 0x7051}, MSG_OPTION_1}, 155 {{ 0, 0, 0, OPTION_VENDOR, 0x7111}, MSG_OPTION_1}, 156 {{ 0, 0, 0, OPTION_VENDOR, 0x7211}, MSG_OPTION_1}, 157 {{ 0, 0, 0, OPTION_VENDOR, 0x7251}, MSG_OPTION_1}, 158 {{ 0, 0, 0, OPTION_VENDOR, 0x7271}, MSG_OPTION_1}, 159 {{ 0, 0, 0, OPTION_VENDOR, 0x7301}, MSG_OPTION_1}, 160 {{ 0, 0, 0, OPTION_VENDOR, 0x7311}, MSG_OPTION_1}, 161 {{ 0, 0, 0, OPTION_VENDOR, 0x7361}, MSG_OPTION_1}, 162 {{ 0, 0, 0, OPTION_VENDOR, 0x7381}, MSG_OPTION_1}, 163 {{ 0, 0, 0, OPTION_VENDOR, 0x7401}, MSG_OPTION_1}, 164 {{ 0, 0, 0, OPTION_VENDOR, 0x7501}, MSG_OPTION_1}, 165 {{ 0, 0, 0, OPTION_VENDOR, 0x7601}, MSG_OPTION_1}, 166 {{ 0, 0, 0, OPTION_VENDOR, 0x7701}, MSG_OPTION_1}, 167 {{ 0, 0, 0, OPTION_VENDOR, 0x7801}, MSG_OPTION_1}, 168 {{ 0, 0, 0, OPTION_VENDOR, 0x7901}, MSG_OPTION_1}, 169 {{ 0, 0, 0, OPTION_VENDOR, 0x8200}, MSG_OPTION_1}, 170 {{ 0, 0, 0, OPTION_VENDOR, 0x8201}, MSG_OPTION_1}, 171 {{ 0, 0, 0, OPTION_VENDOR, 0x8300}, MSG_OPTION_1}, 172 {{ 0, 0, 0, OPTION_VENDOR, 0x8302}, MSG_OPTION_1}, 173 {{ 0, 0, 0, OPTION_VENDOR, 0x8304}, MSG_OPTION_1}, 174 {{ 0, 0, 0, OPTION_VENDOR, 0x8400}, MSG_OPTION_1}, 175 {{ 0, 0, 0, OPTION_VENDOR, 0xc031}, MSG_OPTION_1}, 176 {{ 0, 0, 0, OPTION_VENDOR, 0xc100}, MSG_OPTION_1}, 177 {{ 0, 0, 0, OPTION_VENDOR, 0xc031}, MSG_OPTION_1}, 178 {{ 0, 0, 0, OPTION_VENDOR, 0xd013}, MSG_OPTION_1}, 179 {{ 0, 0, 0, OPTION_VENDOR, 0xd031}, MSG_OPTION_1}, 180 {{ 0, 0, 0, OPTION_VENDOR, 0xd033}, MSG_OPTION_1}, 181 {{ 0, 0, 0, OPTION_VENDOR, 0xd035}, MSG_OPTION_1}, 182 {{ 0, 0, 0, OPTION_VENDOR, 0xd055}, MSG_OPTION_1}, 183 {{ 0, 0, 0, OPTION_VENDOR, 0xd057}, MSG_OPTION_1}, 184 {{ 0, 0, 0, OPTION_VENDOR, 0xd058}, MSG_OPTION_1}, 185 {{ 0, 0, 0, OPTION_VENDOR, 0xd155}, MSG_OPTION_1}, 186 {{ 0, 0, 0, OPTION_VENDOR, 0xd157}, MSG_OPTION_1}, 187 {{ 0, 0, 0, OPTION_VENDOR, 0xd255}, MSG_OPTION_1}, 188 {{ 0, 0, 0, OPTION_VENDOR, 0xd257}, MSG_OPTION_1}, 189 {{ 0, 0, 0, OPTION_VENDOR, 0xd357}, MSG_OPTION_1}, 190 {{ 0, 0, 0, ATHEROS_VENDOR, 0x20ff}, MSG_ATHEROS_1}, 191 }; 192 static uint32 kDevicesCount = sizeof(kDevices) / sizeof(kDevices[0]); 193 194 195 typedef struct _my_device { 196 usb_device device; 197 bool removed; 198 mutex lock; 199 struct _my_device *link; 200 201 // device state 202 usb_pipe bulk_in; 203 usb_pipe bulk_out; 204 uint8 interface; 205 uint8 alternate_setting; 206 207 // used to store callback information 208 sem_id notify; 209 status_t status; 210 size_t actual_length; 211 212 msgType type; 213 } my_device; 214 215 216 int32 api_version = B_CUR_DRIVER_API_VERSION; 217 static usb_module_info *gUSBModule = NULL; 218 static my_device *gDeviceList = NULL; 219 static uint32 gDeviceCount = 0; 220 static mutex gDeviceListLock; 221 222 223 // 224 //#pragma mark - Device Allocation Helper Functions 225 // 226 227 228 static void 229 my_free_device(my_device *device) 230 { 231 mutex_lock(&device->lock); 232 mutex_destroy(&device->lock); 233 delete_sem(device->notify); 234 free(device); 235 } 236 237 238 // 239 //#pragma mark - Bulk-only Functions 240 // 241 242 243 static void 244 my_callback(void *cookie, status_t status, void *data, 245 size_t actualLength) 246 { 247 my_device *device = (my_device *)cookie; 248 device->status = status; 249 device->actual_length = actualLength; 250 release_sem(device->notify); 251 } 252 253 254 static status_t 255 my_transfer_data(my_device *device, bool directionIn, void *data, 256 size_t dataLength) 257 { 258 status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in 259 : device->bulk_out, data, dataLength, my_callback, device); 260 if (result != B_OK) { 261 TRACE_ALWAYS("failed to queue data transfer\n"); 262 return result; 263 } 264 265 do { 266 bigtime_t timeout = directionIn ? 100000 : 100000; 267 result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 268 timeout); 269 if (result == B_TIMED_OUT) { 270 // Cancel the transfer and collect the sem that should now be 271 // released through the callback on cancel. Handling of device 272 // reset is done in usb_printer_operation() when it detects that 273 // the transfer failed. 274 gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in 275 : device->bulk_out); 276 acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0); 277 } 278 } while (result == B_INTERRUPTED); 279 280 if (result != B_OK) { 281 TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n"); 282 return result; 283 } 284 285 return B_OK; 286 } 287 288 289 enum msgType 290 my_get_msg_type(const usb_device_descriptor *desc) 291 { 292 for (uint32 i = 0; i < kDevicesCount; i++) { 293 if (kDevices[i].desc.dev_class != 0x0 294 && kDevices[i].desc.dev_class != desc->device_class) 295 continue; 296 if (kDevices[i].desc.dev_subclass != 0x0 297 && kDevices[i].desc.dev_subclass != desc->device_subclass) 298 continue; 299 if (kDevices[i].desc.dev_protocol != 0x0 300 && kDevices[i].desc.dev_protocol != desc->device_protocol) 301 continue; 302 if (kDevices[i].desc.vendor != 0x0 303 && kDevices[i].desc.vendor != desc->vendor_id) 304 continue; 305 if (kDevices[i].desc.product != 0x0 306 && kDevices[i].desc.product != desc->product_id) 307 continue; 308 309 return kDevices[i].type; 310 } 311 312 return MSG_NONE; 313 } 314 315 316 317 status_t 318 my_modeswitch(my_device* device) 319 { 320 if (device->type == MSG_NONE) 321 return B_OK; 322 323 status_t err = my_transfer_data(device, false, kDevicesMsg[device->type], 324 sizeof(kDevicesMsg[device->type])); 325 if (err != B_OK) { 326 TRACE_ALWAYS("inquire message failed\n"); 327 return err; 328 } 329 330 TRACE("device switched: %p\n", device); 331 332 char data[36]; 333 err = my_transfer_data(device, true, data, sizeof(data)); 334 if (err != B_OK) { 335 TRACE_ALWAYS("inquire response failed\n"); 336 return err; 337 } 338 339 TRACE("device switched: %p %.8s %.16s %.4s\n", device, data + 8, data + 16, 340 data + 32); 341 342 return B_OK; 343 } 344 345 346 // 347 //#pragma mark - Device Attach/Detach Notifications and Callback 348 // 349 350 351 static status_t 352 my_device_added(usb_device newDevice, void **cookie) 353 { 354 TRACE("device_added(0x%08lx)\n", newDevice); 355 my_device *device = (my_device *)malloc(sizeof(my_device)); 356 device->device = newDevice; 357 device->removed = false; 358 device->interface = 0xff; 359 device->alternate_setting = 0; 360 361 // scan through the interfaces to find our bulk-only data interface 362 const usb_configuration_info *configuration = 363 gUSBModule->get_configuration(newDevice); 364 if (configuration == NULL) { 365 free(device); 366 return B_ERROR; 367 } 368 369 for (size_t i = 0; i < configuration->interface_count; i++) { 370 usb_interface_info *interface = configuration->interface[i].active; 371 if (interface == NULL) 372 continue; 373 374 if (true) { 375 376 bool hasIn = false; 377 bool hasOut = false; 378 for (size_t j = 0; j < interface->endpoint_count; j++) { 379 usb_endpoint_info *endpoint = &interface->endpoint[j]; 380 if (endpoint == NULL 381 || endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK) 382 continue; 383 384 if (!hasIn && (endpoint->descr->endpoint_address 385 & USB_ENDPOINT_ADDR_DIR_IN)) { 386 device->bulk_in = endpoint->handle; 387 hasIn = true; 388 } else if (!hasOut && (endpoint->descr->endpoint_address 389 & USB_ENDPOINT_ADDR_DIR_IN) == 0) { 390 device->bulk_out = endpoint->handle; 391 hasOut = true; 392 } 393 394 if (hasIn && hasOut) 395 break; 396 } 397 398 if (!(hasIn && hasOut)) 399 continue; 400 401 device->interface = interface->descr->interface_number; 402 device->alternate_setting = interface->descr->alternate_setting; 403 404 break; 405 } 406 } 407 408 if (device->interface == 0xff) { 409 TRACE_ALWAYS("no valid interface found\n"); 410 free(device); 411 return B_ERROR; 412 } 413 414 const usb_device_descriptor *descriptor 415 = gUSBModule->get_device_descriptor(newDevice); 416 if (descriptor == NULL) { 417 free(device); 418 return B_ERROR; 419 } 420 device->type = my_get_msg_type(descriptor); 421 422 mutex_init(&device->lock, DRIVER_NAME " device lock"); 423 424 device->notify = create_sem(0, DRIVER_NAME " callback notify"); 425 if (device->notify < B_OK) { 426 mutex_destroy(&device->lock); 427 free(device); 428 return device->notify; 429 } 430 431 mutex_lock(&gDeviceListLock); 432 device->link = gDeviceList; 433 gDeviceList = device; 434 mutex_unlock(&gDeviceListLock); 435 436 *cookie = device; 437 438 return my_modeswitch(device); 439 } 440 441 442 static status_t 443 my_device_removed(void *cookie) 444 { 445 TRACE("device_removed(0x%08lx)\n", (uint32)cookie); 446 my_device *device = (my_device *)cookie; 447 448 mutex_lock(&gDeviceListLock); 449 if (gDeviceList == device) { 450 gDeviceList = device->link; 451 } else { 452 my_device *element = gDeviceList; 453 while (element) { 454 if (element->link == device) { 455 element->link = device->link; 456 break; 457 } 458 459 element = element->link; 460 } 461 } 462 gDeviceCount--; 463 464 device->removed = true; 465 gUSBModule->cancel_queued_transfers(device->bulk_in); 466 gUSBModule->cancel_queued_transfers(device->bulk_out); 467 my_free_device(device); 468 469 mutex_unlock(&gDeviceListLock); 470 return B_OK; 471 } 472 473 474 // 475 //#pragma mark - Driver Entry Points 476 // 477 478 479 status_t 480 init_hardware() 481 { 482 TRACE("init_hardware()\n"); 483 return B_OK; 484 } 485 486 487 status_t 488 init_driver() 489 { 490 TRACE("init_driver()\n"); 491 static usb_notify_hooks notifyHooks = { 492 &my_device_added, 493 &my_device_removed 494 }; 495 496 gDeviceList = NULL; 497 gDeviceCount = 0; 498 mutex_init(&gDeviceListLock, DRIVER_NAME " device list lock"); 499 500 TRACE("trying module %s\n", B_USB_MODULE_NAME); 501 status_t result = get_module(B_USB_MODULE_NAME, 502 (module_info **)&gUSBModule); 503 if (result < B_OK) { 504 TRACE_ALWAYS("getting module failed 0x%08lx\n", result); 505 mutex_destroy(&gDeviceListLock); 506 return result; 507 } 508 509 size_t descriptorsSize = kDevicesCount * sizeof(usb_support_descriptor); 510 usb_support_descriptor *supportedDevices = 511 (usb_support_descriptor *)malloc(descriptorsSize); 512 if (supportedDevices == NULL) { 513 TRACE_ALWAYS("descriptor allocation failed\n"); 514 put_module(B_USB_MODULE_NAME); 515 mutex_destroy(&gDeviceListLock); 516 return result; 517 } 518 519 for (uint32 i = 0; i < kDevicesCount; i++) 520 supportedDevices[i] = kDevices[i].desc; 521 522 gUSBModule->register_driver(DRIVER_NAME, supportedDevices, kDevicesCount, 523 NULL); 524 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 525 free(supportedDevices); 526 return B_OK; 527 } 528 529 530 void 531 uninit_driver() 532 { 533 TRACE("uninit_driver()\n"); 534 gUSBModule->uninstall_notify(DRIVER_NAME); 535 mutex_lock(&gDeviceListLock); 536 mutex_destroy(&gDeviceListLock); 537 put_module(B_USB_MODULE_NAME); 538 } 539 540 541 const char ** 542 publish_devices() 543 { 544 TRACE("publish_devices()\n"); 545 return NULL; 546 } 547 548 549 device_hooks * 550 find_device(const char *name) 551 { 552 TRACE("find_device()\n"); 553 return NULL; 554 } 555