1char *version="1.0.0"; 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <assert.h> 7#include <signal.h> 8#include <ctype.h> 9#include <getopt.h> 10#include <syslog.h> 11 12#include <usb.h> 13#include "lcdoshift.h" 14 15#define LINE_DIM 1024 16#define BUF_SIZE 4096 17#define DESCR_MAX 129 18 19#define SHOW_PROGRESS if (show_progress) printf 20 21int write_bulk(int endpoint, char *message, int length); 22int read_bulk(int endpoint, char *buffer, int length); 23 24int find_first_bulk_output_endpoint(struct usb_device *dev); 25int find_first_bulk_input_endpoint(struct usb_device *dev); 26 27char *TempPP=NULL; 28 29struct usb_device *dev; 30struct usb_dev_handle *devh; 31 32int DefaultVendor=0x1c9e, DefaultProduct=0, TargetVendor=0, TargetProduct=0, TargetClass=0; 33int MessageEndpoint=0, ResponseEndpoint=0, defaultClass=0; 34int targetDeviceCount=0; 35int devnum=-1, busnum=-1; 36int ret; 37 38char DetachStorageOnly=0, HuaweiMode=0, SierraMode=0, SonyMode=0, GCTMode=0; 39char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0; 40char NeedResponse=0, InquireDevice=0, sysmode=0; 41 42char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX]; 43 44char MessageContent[LINE_DIM] = "55534243123456780000000080000606f50402527000000000000000000000"; 45char TargetProductList[LINE_DIM]; 46char ByteString[LINE_DIM/2]; 47char buffer[BUF_SIZE]; 48 49// Settable Interface and Configuration (for debugging mostly) (jmw) 50int Interface = 0, Configuration = -1, AltSetting = -1; 51 52 53static struct option long_options[] = { 54 {"help", no_argument, 0, 'h'}, 55 {"version", no_argument, 0, 'e'}, 56 {"default-vendor", required_argument, 0, 'v'}, 57 {"default-product", required_argument, 0, 'p'}, 58 {"target-vendor", required_argument, 0, 'V'}, 59 {"target-product", required_argument, 0, 'P'}, 60 {"target-class", required_argument, 0, 'C'}, 61 {"message-endpoint", required_argument, 0, 'm'}, 62 {"message-content", required_argument, 0, 'M'}, 63 {"response-endpoint", required_argument, 0, 'r'}, 64 {"detach-only", no_argument, 0, 'd'}, 65 {"huawei-mode", no_argument, 0, 'H'}, 66 {"sierra-mode", no_argument, 0, 'S'}, 67 {"sony-mode", no_argument, 0, 'O'}, 68 {"gct-mode", no_argument, 0, 'G'}, 69 {"need-response", no_argument, 0, 'n'}, 70 {"reset-usb", no_argument, 0, 'R'}, 71 {"config", required_argument, 0, 'c'}, 72 {"verbose", no_argument, 0, 'W'}, 73 {"quiet", no_argument, 0, 'Q'}, 74 {"sysmode", no_argument, 0, 'D'}, 75 {"no-inquire", no_argument, 0, 'I'}, 76 {"check-success", required_argument, 0, 's'}, 77 {"interface", required_argument, 0, 'i'}, 78 {"configuration", required_argument, 0, 'u'}, 79 {"altsetting", required_argument, 0, 'a'}, 80 {0, 0, 0, 0} 81}; 82 83 84void readConfigFile(const char *configFilename) 85{ 86 if (verbose) printf("Reading config file: %s\n", configFilename); 87 ParseParamHex(configFilename, TargetVendor); 88 ParseParamHex(configFilename, TargetProduct); 89 ParseParamString(configFilename, TargetProductList); 90 ParseParamHex(configFilename, TargetClass); 91 ParseParamHex(configFilename, DefaultVendor); 92 ParseParamHex(configFilename, DefaultProduct); 93 ParseParamBool(configFilename, DetachStorageOnly); 94 ParseParamBool(configFilename, HuaweiMode); 95 ParseParamBool(configFilename, SierraMode); 96 ParseParamBool(configFilename, SonyMode); 97 ParseParamBool(configFilename, GCTMode); 98 ParseParamHex(configFilename, MessageEndpoint); 99 ParseParamString(configFilename, MessageContent); 100 ParseParamHex(configFilename, NeedResponse); 101 ParseParamHex(configFilename, ResponseEndpoint); 102 ParseParamHex(configFilename, ResetUSB); 103 ParseParamHex(configFilename, InquireDevice); 104 ParseParamInt(configFilename, CheckSuccess); 105 ParseParamHex(configFilename, Interface); 106 ParseParamHex(configFilename, Configuration); 107 ParseParamHex(configFilename, AltSetting); 108 109 // TargetProductList has priority over TargetProduct 110 if (strlen(TargetProductList)) 111 TargetProduct = 0; 112 113 config_read = 1; 114} 115 116 117void printConfig() 118{ 119 printf ("DefaultVendor= 0x%04x\n", DefaultVendor); 120 printf ("DefaultProduct= 0x%04x\n", DefaultProduct); 121 if ( TargetVendor ) 122 printf ("TargetVendor= 0x%04x\n", TargetVendor); 123 else 124 printf ("TargetVendor= not set\n"); 125 if ( TargetProduct ) 126 printf ("TargetProduct= 0x%04x\n", TargetProduct); 127 else 128 printf ("TargetProduct= not set\n"); 129 if ( strlen(TargetProductList) ) 130 printf ("TargetProductList=%s\n", TargetProductList); 131// else 132// printf ("TargetProduct= not set\n"); 133 if ( TargetClass ) 134 printf ("TargetClass= 0x%02x\n", TargetClass); 135 else 136 printf ("TargetClass= not set\n"); 137 printf ("\nDetachStorageOnly=%i\n", (int)DetachStorageOnly); 138 printf ("HuaweiMode=%i\n", (int)HuaweiMode); 139 printf ("SierraMode=%i\n", (int)SierraMode); 140 printf ("SonyMode=%i\n", (int)SonyMode); 141 printf ("GCTMode=%i\n", (int)GCTMode); 142 if ( MessageEndpoint ) 143 printf ("MessageEndpoint=0x%02x\n", MessageEndpoint); 144 else 145 printf ("MessageEndpoint= not set\n"); 146 if ( strlen(MessageContent) ) 147 printf ("MessageContent=\"%s\"\n", MessageContent); 148 else 149 printf ("MessageContent= not set\n"); 150 printf ("NeedResponse=%i\n", (int)NeedResponse); 151 if ( ResponseEndpoint ) 152 printf ("ResponseEndpoint=0x%02x\n", ResponseEndpoint); 153 else 154 printf ("ResponseEndpoint= not set\n"); 155 printf ("Interface=0x%02x\n", Interface); 156 if ( Configuration > -1 ) 157 printf ("Configuration=0x%02x\n", Configuration); 158 if ( AltSetting > -1 ) 159 printf ("AltSetting=0x%02x\n", AltSetting); 160 if ( InquireDevice ) 161 printf ("\nInquireDevice enabled (default)\n"); 162 else 163 printf ("\nInquireDevice disabled\n"); 164 if ( CheckSuccess ) 165 printf ("Success check enabled, max. wait time %d seconds\n", CheckSuccess); 166 else 167 printf ("Success check disabled\n"); 168 if ( sysmode ) 169 printf ("System integration mode enabled\n"); 170 else 171 printf ("System integration mode disabled\n"); 172 printf ("\n"); 173} 174 175 176int readArguments(int argc, char **argv) 177{ 178 int c, option_index = 0, count=0; 179 if(argc==1) return 0; 180 181 while (1) 182 { 183 c = getopt_long (argc, argv, "heWQDndHSOGRIv:p:V:P:C:m:M:r:c:i:u:a:s:", 184 long_options, &option_index); 185 186 /* Detect the end of the options. */ 187 if (c == -1) 188 break; 189 count++; 190 switch (c) 191 { 192 case 'R': ResetUSB = 1; break; 193 case 'v': DefaultVendor = strtol(optarg, NULL, 16); break; 194 case 'p': DefaultProduct = strtol(optarg, NULL, 16); break; 195 case 'V': TargetVendor = strtol(optarg, NULL, 16); break; 196 case 'P': TargetProduct = strtol(optarg, NULL, 16); break; 197 case 'C': TargetClass = strtol(optarg, NULL, 16); break; 198 case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break; 199 case 'M': strcpy(MessageContent, optarg); break; 200 case 'n': NeedResponse = 1; break; 201 case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break; 202 case 'd': DetachStorageOnly = 1; break; 203 case 'H': HuaweiMode = 1; break; 204 case 'S': SierraMode = 1; break; 205 case 'O': SonyMode = 1; break; 206 case 'G': GCTMode = 1; break; 207 case 'c': readConfigFile(optarg); break; 208 case 'W': verbose = 1; show_progress = 1; count--; break; 209 case 'Q': show_progress = 0; verbose = 0; count--; break; 210 case 'D': sysmode = 1; count--; break; 211 case 's': CheckSuccess = strtol(optarg, NULL, 16); count--; break; 212 case 'I': InquireDevice = 0; break; 213 214 case 'i': Interface = strtol(optarg, NULL, 16); break; 215 case 'u': Configuration = strtol(optarg, NULL, 16); break; 216 case 'a': AltSetting = strtol(optarg, NULL, 16); break; 217 218 case 'e': 219 printVersion(); 220 exit(0); 221 break; 222 case 'h': 223 printVersion(); 224 printf ("Usage: usb-modeswitch [-hvpVPmMrdHn] [-c filename]\n\n"); 225 printf (" -h, --help this help\n"); 226 printf (" -e, --version print version number and exit\n"); 227 printf (" -v, --default-vendor NUM vendor ID to look for (mandatory)\n"); 228 printf (" -p, --default-product NUM product ID to look for (mandatory)\n"); 229 printf (" -V, --target-vendor NUM target vendor (optional, for success check)\n"); 230 printf (" -P, --target-product NUM target model (optional, for success check)\n"); 231 printf (" -C, --target-class NUM target device class\n"); 232 printf (" -m, --message-endpoint NUM where to direct the message (optional)\n"); 233 printf (" -M, --message-content <msg> command to send (hex number as string)\n"); 234 printf (" -n, --need-response read a response to the message transfer\n"); 235 printf (" -r, --response-endpoint NUM where from read the response (optional)\n"); 236 printf (" -d, --detach-only just detach the storage driver\n"); 237 printf (" -H, --huawei-mode apply a special procedure\n"); 238 printf (" -S, --sierra-mode apply a special procedure\n"); 239 printf (" -O, --sony-mode apply a special procedure\n"); 240 printf (" -G, --gct-mode apply a special procedure\n"); 241 printf (" -R, --reset-usb reset the device in the end\n"); 242 printf (" -c, --config <filename> load different config file\n"); 243 printf (" -Q, --quiet don't show progress or error messages\n"); 244 printf (" -W, --verbose print all settings before running\n"); 245 printf (" -D, --sysmode specific result and syslog message\n"); 246 printf (" -s, --success NUM check switching result after NUM secs\n"); 247 printf (" -I, --no-inquire do not get device details (default on)\n\n"); 248 printf (" -i, --interface NUM select initial USB interface (default 0)\n"); 249 printf (" -u, --configuration NUM select USB configuration\n"); 250 printf (" -a, --altsetting NUM select alternative USB interface setting\n\n"); 251 exit(0); 252 break; 253 254 default: //Unsupported - error message has already been printed 255 printf ("\n"); 256 exit(1); 257 } 258 } 259 260 return count; 261} 262 263 264int main(int argc, char **argv) 265{ 266 int numDefaults = 0, specialMode = 0, sonySuccess = 0; 267 268 /* 269 * Parameter parsing, USB preparation/diagnosis, plausibility checks 270 */ 271 272 // Check command arguments, use params instead of config file when given 273 switch (readArguments(argc, argv)) { 274 case 0: // no argument or -W, -q or -s 275 readConfigFile("/etc/usb-modeswitch.conf"); 276 break; 277 default: // one or more arguments except -W, -q or -s 278 if (!config_read) // if arguments contain -c, the config file was already processed 279 if (verbose) printf("Taking all parameters from the command line\n\n"); 280 } 281 282 if (verbose) 283 printVersion(); 284 285 sleep(1); 286 if (verbose) 287 printConfig(); 288 289 // libusb initialization 290 usb_init(); 291 292 if (verbose) 293 usb_set_debug(15); 294 295 usb_find_busses(); 296 usb_find_devices(); 297 298 // Plausibility checks. The default IDs are mandatory 299 if (!(DefaultVendor && DefaultProduct)) { 300 SHOW_PROGRESS("No default vendor/product ID given. Aborting.\n\n"); 301 exit(1); 302 } 303 if (strlen(MessageContent)) { 304 if (strlen(MessageContent) % 2 != 0) { 305 fprintf(stderr, "Error: MessageContent hex string has uneven length. Aborting.\n\n"); 306 exit(1); 307 } 308 if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) { 309 fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent); 310 exit(1); 311 } 312 } 313 SHOW_PROGRESS("\n"); 314 315 if (show_progress) 316 if (CheckSuccess && !(TargetVendor || TargetProduct || strlen(TargetProductList)) && !TargetClass) 317 printf("Note: target parameter missing; success check limited\n"); 318 319 // Count existing target devices (remember for success check) 320 if (TargetVendor || TargetClass) { 321 SHOW_PROGRESS("Looking for target devices ...\n"); 322 search_devices(&targetDeviceCount, TargetVendor, TargetProduct, TargetProductList, TargetClass); 323 if (targetDeviceCount) { 324 SHOW_PROGRESS(" Found devices in target mode or class (%d)\n", targetDeviceCount); 325 } else 326 SHOW_PROGRESS(" No devices in target mode or class found\n"); 327 } 328 329 // Count default devices, return the last one found 330 SHOW_PROGRESS("Looking for default devices ...\n"); 331 dev = search_devices(&numDefaults, DefaultVendor, DefaultProduct, "\0", TargetClass); 332 if (numDefaults) { 333 SHOW_PROGRESS(" Found default devices (%d)\n", numDefaults); 334 if (TargetClass && !(TargetVendor || TargetProduct)) { 335 if ( dev != NULL ) { 336 SHOW_PROGRESS(" Found a default device NOT in target class mode\n"); 337 } else { 338 SHOW_PROGRESS(" All devices in target class mode. Nothing to do. Bye.\n\n"); 339 exit(0); 340 } 341 } 342 } 343 if (dev != NULL) { 344 devnum = dev->devnum; 345 busnum = (int)strtol(dev->bus->dirname,NULL,10); 346 SHOW_PROGRESS("Accessing device %03d on bus %03d ...\n", devnum, busnum); 347 devh = usb_open(dev); 348 } else { 349 SHOW_PROGRESS(" No default device found. Is it connected? Bye.\n\n"); 350 exit(0); 351 } 352 353 // Get class of default device 354 defaultClass = dev->descriptor.bDeviceClass; 355 if (defaultClass == 0) 356 defaultClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass; 357 else 358 if (dev->config[0].interface[0].altsetting[0].bInterfaceClass == 8 && defaultClass != 8) { 359 // Weird device with default class other than 0 and differing interface class 360 SHOW_PROGRESS("Ambiguous Class/InterfaceClass: 0x%02x/0x08", defaultClass); 361 defaultClass = 8; 362 } 363 364 // Check or get endpoints if needed 365 if (!MessageEndpoint && (strlen(MessageContent) || InquireDevice) ) { 366// SHOW_PROGRESS(" Finding endpoints ...\n"); 367 MessageEndpoint = find_first_bulk_output_endpoint(dev); 368 if (!MessageEndpoint && strlen(MessageContent)) { 369 fprintf(stderr,"Error: message endpoint not given or found. Aborting.\n\n"); 370 exit(1); 371 } 372 } 373 if (!ResponseEndpoint && (NeedResponse || InquireDevice) ) { 374 ResponseEndpoint = find_first_bulk_input_endpoint(dev); 375 if (!ResponseEndpoint && NeedResponse) { 376 fprintf(stderr,"Error: response endpoint not given or found. Aborting.\n\n"); 377 exit(1); 378 } 379 } 380 if (MessageEndpoint && ResponseEndpoint) { 381 SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint); 382 } else 383 if (InquireDevice && defaultClass == 0x08) { 384 SHOW_PROGRESS("Endpoints not found, skipping SCSI inquiry\n"); 385 InquireDevice = 0; 386 } 387 388 if (InquireDevice && show_progress) { 389 if (defaultClass == 0x08) { 390 SHOW_PROGRESS("Inquiring device details; driver will be detached ...\n"); 391 detachDriver(); 392 if (deviceInquire() >= 0) 393 InquireDevice = 2; 394 } else 395 SHOW_PROGRESS("Not a storage device, skipping SCSI inquiry\n"); 396 } 397 398 deviceDescription(); 399 if (show_progress) { 400 printf("\nUSB description data (for identification)\n"); 401 printf("-------------------------\n"); 402 printf("Manufacturer: %s\n", imanufact); 403 printf(" Product: %s\n", iproduct); 404 printf(" Serial No.: %s\n", iserial); 405 printf("-------------------------\n"); 406 } 407 408 // Some scenarios are exclusive, so check for unwanted combinations 409 specialMode = DetachStorageOnly + HuaweiMode + SierraMode + SonyMode; 410 if ( specialMode > 1 ) { 411 SHOW_PROGRESS("Invalid mode combination. Check your configuration. Aborting.\n\n"); 412 exit(1); 413 } 414 415 if ( !specialMode && !strlen(MessageContent) ) 416 SHOW_PROGRESS("Warning: no switching method given.\n"); 417 418 /* 419 * The switching actions 420 */ 421 422 if (sysmode) { 423 openlog("usb-modeswitch", 0, LOG_SYSLOG); 424 syslog(LOG_NOTICE, "switching %04x:%04x (%s: %s)", DefaultVendor, DefaultProduct, imanufact, iproduct); 425 } 426 427 if (DetachStorageOnly) { 428 SHOW_PROGRESS("Only detaching storage driver for switching ...\n"); 429 if (InquireDevice == 2) { 430 SHOW_PROGRESS(" Any driver was already detached for inquiry\n"); 431 } else { 432 ret = detachDriver(); 433 if (ret == 2) 434 SHOW_PROGRESS(" You may want to remove the storage driver manually\n"); 435 } 436 } 437 438 if (strlen(MessageContent) && MessageEndpoint) { 439 if (specialMode == 0) { 440 if (InquireDevice != 2) 441 detachDriver(); 442 switchSendMessage(); 443 } else 444 SHOW_PROGRESS("Warning: ignoring MessageContent. Can't combine with special mode\n"); 445 } 446 447 if (Configuration != -1) { 448 switchConfiguration (); 449 } 450 451 if (AltSetting != -1) { 452 switchAltSetting(); 453 } 454 455 if (ResetUSB) { 456 resetUSB(); 457 } 458 459 if (CheckSuccess) { 460 signal(SIGTERM, release_usb_device); 461 if (checkSuccess()) { 462 if (sysmode) 463 printf("ok:%04x:%04x\n", TargetVendor, TargetProduct); 464 exit(0); 465 } else{ 466 if (sysmode) 467 printf("fail:\n"); 468 exit(0); 469 } 470 } else { 471 if (SonyMode) 472 if (sonySuccess) { 473 if (sysmode) { 474 syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode"); 475 printf("ok:\n"); // ACM device, no driver action 476 } 477 SHOW_PROGRESS("-> device should be stable now. Bye.\n\n"); 478 } else { 479 if (sysmode) 480 printf("fail:\n"); 481 SHOW_PROGRESS("-> switching was probably not completed. Bye.\n\n"); 482 } 483 else 484 SHOW_PROGRESS("-> Run lsusb to note any changes. Bye.\n\n"); 485 if (sysmode) 486 closelog(); 487 exit(0); 488 } 489 490 if (devh) 491 usb_close(devh); 492 493 return 0; 494} 495 496 497/* Get descriptor strings if available (identification details) */ 498void deviceDescription () 499{ 500 int ret; 501 char* c; 502 memset (imanufact, ' ', DESCR_MAX); 503 memset (iproduct, ' ', DESCR_MAX); 504 memset (iserial, ' ', DESCR_MAX); 505 506 if (dev->descriptor.iManufacturer) { 507 ret = usb_get_string_simple(devh, dev->descriptor.iManufacturer, imanufact, DESCR_MAX); 508 if (ret < 0) 509 fprintf(stderr, "Error: could not get description string \"manufacturer\"\n"); 510 } else 511 strcpy(imanufact, "not provided"); 512 c = strstr(imanufact, " "); 513 if (c) 514 memset((void*)c, '\0', 1); 515 516 if (dev->descriptor.iProduct) { 517 ret = usb_get_string_simple(devh, dev->descriptor.iProduct, iproduct, DESCR_MAX); 518 if (ret < 0) 519 fprintf(stderr, "Error: could not get description string \"product\"\n"); 520 } else 521 strcpy(iproduct, "not provided"); 522 c = strstr(iproduct, " "); 523 if (c) 524 memset((void*)c, '\0', 1); 525 526 if (dev->descriptor.iSerialNumber) { 527 ret = usb_get_string_simple(devh, dev->descriptor.iSerialNumber, iserial, DESCR_MAX); 528 if (ret < 0) 529 fprintf(stderr, "Error: could not get description string \"serial number\"\n"); 530 } else 531 strcpy(iserial, "not provided"); 532 c = strstr(iserial, " "); 533 if (c) 534 memset((void*)c, '\0', 1); 535 536} 537 538/* Print result of SCSI command INQUIRY (identification details) */ 539int deviceInquire () 540{ 541 const unsigned char inquire_msg[] = { 542 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 543 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, 544 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 546 }; 547 char *command; 548 char data[36]; 549 int i, ret; 550 551 command = malloc(31); 552 if (command == NULL) { 553 ret = 1; 554 goto out; 555 } 556 557 memcpy(command, inquire_msg, sizeof (inquire_msg)); 558 559 ret = usb_claim_interface(devh, Interface); 560 if (ret != 0) { 561 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping device inquiry\n", ret); 562 goto out; 563 } 564 usb_clear_halt(devh, MessageEndpoint); 565 566 ret = usb_bulk_write(devh, MessageEndpoint, (char *)command, 31, 0); 567 if (ret < 0) { 568 SHOW_PROGRESS(" Could not send INQUIRY message (error %d)\n", ret); 569 goto out; 570 } 571 572 ret = usb_bulk_read(devh, ResponseEndpoint, data, 36, 0); 573 if (ret < 0) { 574 SHOW_PROGRESS(" Could not get INQUIRY response (error %d)\n", ret); 575 goto out; 576 } 577 578 i = usb_bulk_read(devh, ResponseEndpoint, command, 13, 0); 579 580 printf("\nSCSI inquiry data (for identification)\n"); 581 printf("-------------------------\n"); 582 583 printf(" Vendor String: "); 584 for (i = 8; i < 16; i++) printf("%c",data[i]); 585 printf("\n"); 586 587 printf(" Model String: "); 588 for (i = 16; i < 32; i++) printf("%c",data[i]); 589 printf("\n"); 590 591 printf("Revision String: "); 592 for (i = 32; i < 36; i++) printf("%c",data[i]); 593 594 printf("\n-------------------------\n"); 595 596out: 597 if (strlen(MessageContent) == 0) 598 usb_clear_halt(devh, MessageEndpoint); 599 usb_release_interface(devh, Interface); 600 free(command); 601 return ret; 602} 603 604 605void resetUSB () 606{ 607 int success; 608 int bpoint = 0; 609 610 if (show_progress) { 611 printf("Resetting usb device "); 612 fflush(stdout); 613 } 614 615 sleep( 1 ); 616 do { 617 success = usb_reset(devh); 618 if ( ((bpoint % 10) == 0) && show_progress ) { 619 printf("."); 620 fflush(stdout); 621 } 622 bpoint++; 623 if (bpoint > 100) 624 success = 1; 625 } while (success < 0); 626 627 if ( success ) { 628 SHOW_PROGRESS("\n Reset failed. Can be ignored if device switched OK.\n"); 629 } else 630 SHOW_PROGRESS("\n OK, device was reset\n"); 631} 632 633 634int switchSendMessage () 635{ 636 int message_length, ret; 637 638 SHOW_PROGRESS("Setting up communication with interface %d ...\n", Interface); 639 if (InquireDevice != 2) { 640 ret = usb_claim_interface(devh, Interface); 641 if (ret != 0) { 642 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping message sending\n", ret); 643 return 0; 644 } 645 } 646 usb_clear_halt(devh, MessageEndpoint); 647 SHOW_PROGRESS("Trying to send the message to endpoint 0x%02x ...\n", MessageEndpoint); 648 fflush(stdout); 649 650 message_length = strlen(MessageContent) / 2; 651 ret = write_bulk(MessageEndpoint, ByteString, message_length); 652 if (ret == -19) 653 goto skip; 654 655 if (NeedResponse) { 656 SHOW_PROGRESS("Reading the response to the message ...\n"); 657 ret = read_bulk(ResponseEndpoint, ByteString, LINE_DIM/2); 658 if (ret == -19) 659 goto skip; 660 } 661 662 ret = usb_clear_halt(devh, MessageEndpoint); 663 if (ret) 664 goto skip; 665 ret = usb_release_interface(devh, Interface); 666 if (ret) 667 goto skip; 668 return 1; 669 670skip: 671 SHOW_PROGRESS(" Device is gone, skipping any further commands\n"); 672 usb_close(devh); 673 devh = 0; 674 return 2; 675} 676 677 678int switchConfiguration () 679{ 680 int ret; 681 682 SHOW_PROGRESS("Changing configuration to %i ...\n", Configuration); 683 ret = usb_set_configuration(devh, Configuration); 684 if (ret == 0 ) { 685 SHOW_PROGRESS(" OK, configuration set\n"); 686 return 1; 687 } 688 SHOW_PROGRESS(" Setting the configuration returned error %d. Trying to continue\n", ret); 689 return 0; 690} 691 692 693int switchAltSetting () 694{ 695 int ret; 696 697 SHOW_PROGRESS("Changing to alt setting %i ...\n", AltSetting); 698 ret = usb_claim_interface(devh, Interface); 699 ret = usb_set_altinterface(devh, AltSetting); 700 usb_release_interface(devh, Interface); 701 if (ret != 0) { 702 SHOW_PROGRESS(" Changing to alt setting returned error %d. Trying to continue\n", ret); 703 return 0; 704 } else { 705 SHOW_PROGRESS(" OK, changed to alt setting\n"); 706 return 1; 707 } 708} 709 710// Detach driver either as the main action or as preparation for other modes 711int detachDriver() 712{ 713 int ret; 714 715#ifndef LIBUSB_HAS_GET_DRIVER_NP 716 printf(" Cant't do driver detection and detaching on this platform.\n"); 717 return 2; 718#endif 719 720 SHOW_PROGRESS("Looking for active driver ...\n"); 721 ret = usb_get_driver_np(devh, Interface, buffer, BUF_SIZE); 722 if (ret != 0) { 723 SHOW_PROGRESS(" No driver found. Either detached before or never attached\n"); 724 return 1; 725 } 726 SHOW_PROGRESS(" OK, driver found (\"%s\")\n", buffer); 727 if (DetachStorageOnly && strcmp(buffer,"usb-storage")) { 728 SHOW_PROGRESS(" Warning: driver is not usb-storage\n"); 729// return 1; 730 } 731 732#ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 733 SHOW_PROGRESS(" Can't do driver detaching on this platform\n"); 734 return 2; 735#endif 736 737 738 ret = usb_detach_kernel_driver_np(devh, Interface); 739 if (ret == 0) { 740 SHOW_PROGRESS(" OK, driver \"%s\" detached\n", buffer); 741// usb_clear_halt(devh, MessageEndpoint); 742// usb_clear_halt(devh, ResponseEndpoint); 743 } else 744 SHOW_PROGRESS(" Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer, ret); 745 return 1; 746} 747 748 749int checkSuccess() 750{ 751 int i=0, ret; 752 int newTargetCount, success=0; 753 754 SHOW_PROGRESS("\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess); 755 sleep(1); 756 757 if (devh) // devh is 0 if device vanished during command transmission 758 for (i=0; i < CheckSuccess; i++) { 759 760 // Test if default device still can be accessed; positive result does 761 // not necessarily mean failure 762 SHOW_PROGRESS(" Waiting for original device to vanish ...\n"); 763 764 ret = usb_claim_interface(devh, Interface); 765 if (ret < 0) { 766 SHOW_PROGRESS(" Original device can't be accessed anymore. Good.\n"); 767 if (i == CheckSuccess-1) 768 SHOW_PROGRESS(" If you want target checking, increase 'CheckSuccess' value.\n"); 769 usb_close(devh); 770 devh = NULL; 771 break; 772 } else 773 usb_release_interface(devh, Interface); 774 775 if (i == CheckSuccess-1) { 776 SHOW_PROGRESS(" Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n"); 777 } else 778 sleep(1); 779 } 780 else 781 SHOW_PROGRESS(" Original device is gone already, not checking\n"); 782 783 784 if ( (TargetVendor && (TargetProduct || strlen(TargetProductList))) || TargetClass ) 785 786 // Recount target devices (compare with previous count) if target data is given. 787 // Target device on the same bus with higher device number is returned, 788 // description is read for syslog message 789 for (i=i; i < CheckSuccess; i++) { 790 SHOW_PROGRESS(" Searching for target devices ...\n"); 791 usb_find_devices(); 792 dev = search_devices(&newTargetCount, TargetVendor, TargetProduct, TargetProductList, TargetClass); 793 if (dev && (newTargetCount > targetDeviceCount)) { 794 devh = usb_open(dev); 795 deviceDescription(); 796 usb_close(devh); 797 if (verbose) { 798 printf("\nFound target device %03d on bus %03d\n", \ 799 dev->devnum, (int)strtol(dev->bus->dirname,NULL,10)); 800 printf("\nTarget device description data\n"); 801 printf("-------------------------\n"); 802 printf("Manufacturer: %s\n", imanufact); 803 printf(" Product: %s\n", iproduct); 804 printf(" Serial No.: %s\n", iserial); 805 printf("-------------------------\n"); 806 } 807 SHOW_PROGRESS(" Found correct target device\n\nMode switch succeeded. Bye.\n\n"); 808 success = 2; 809 break; 810 } 811 if (i == CheckSuccess-1) { 812 SHOW_PROGRESS(" No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n"); 813 } else 814 sleep(1); 815 } 816 else 817 // No target data given, rely on the vanished device 818 if (!devh) { 819 SHOW_PROGRESS(" (For a better success check provide target IDs or class)\n"); 820 SHOW_PROGRESS(" Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n"); 821 success = 1; 822 } 823 824 switch (success) { 825 case 2: 826 if (sysmode) 827 syslog(LOG_NOTICE, "switched to %04x:%04x (%s: %s)", TargetVendor, TargetProduct, imanufact, iproduct); 828 success = 1; 829 break; 830 case 1: 831 if (sysmode) 832 syslog(LOG_NOTICE, "device seems to have switched"); 833 default: 834 ; 835 } 836 if (sysmode) 837 closelog(); 838 839 return success; 840 841} 842 843 844int write_bulk(int endpoint, char *message, int length) 845{ 846 int ret; 847 ret = usb_bulk_write(devh, endpoint, message, length, 100); 848 if (ret >= 0 ) { 849 SHOW_PROGRESS(" OK, message successfully sent\n"); 850 } else 851 if (ret == -19) { 852 SHOW_PROGRESS(" Device seems to have vanished right after sending. Good.\n"); 853 } else 854 SHOW_PROGRESS(" Sending the message returned error %d. Trying to continue\n", ret); 855 return ret; 856 857} 858 859int read_bulk(int endpoint, char *buffer, int length) 860{ 861 int ret; 862 ret = usb_bulk_read(devh, endpoint, buffer, length, 100); 863 usb_bulk_read(devh, endpoint, buffer, 13, 100); 864 if (ret >= 0 ) { 865 SHOW_PROGRESS(" OK, response successfully read (%d bytes).\n", ret); 866 } else 867 if (ret == -19) { 868 SHOW_PROGRESS(" Device seems to have vanished after reading. Good.\n"); 869 } else 870 SHOW_PROGRESS(" Response reading got error %d, can probably be ignored\n", ret); 871 return ret; 872 873} 874 875void release_usb_device(int dummy) { 876 SHOW_PROGRESS("Program cancelled by system. Bye.\n\n"); 877 usb_release_interface(devh, Interface); 878 usb_close(devh); 879 if (sysmode) 880 closelog(); 881 exit(0); 882 883} 884 885 886// iterates over busses and devices, counts the ones found and returns the last one of them 887 888struct usb_device* search_devices( int *numFound, int vendor, int product, char* productList, int targetClass) 889{ 890 struct usb_bus *bus; 891 char *listcopy, *token, buffer[2]; 892 int devClass; 893 struct usb_device* right_dev = NULL; 894 895 if ( targetClass && !(vendor || product) ) { 896 vendor = DefaultVendor; 897 product = DefaultProduct; 898 } 899 *numFound = 0; 900 if (!vendor || (!product && productList==NULL)) 901 return NULL; 902 if (productList != NULL) 903 listcopy = malloc(strlen(productList)+1); 904 905 for (bus = usb_get_busses(); bus; bus = bus->next) { 906 struct usb_device *dev; 907 for (dev = bus->devices; dev; dev = dev->next) { 908 if (verbose) 909 printf (" searching devices, found USB ID %04x:%04x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); 910 if (dev->descriptor.idVendor != vendor) 911 continue; 912 if (verbose) 913 printf (" found matching vendor ID\n"); 914 // product list given 915 if ( strlen(productList) ) { 916 strcpy(listcopy, productList); 917 token = strtok(listcopy, ","); 918 while (token != NULL) { 919 if (strlen(token) != 4) { 920 SHOW_PROGRESS("Error: entry in product ID list has wrong length: %s. Ignoring\n", token); 921 goto NextToken; 922 } 923 if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) { 924 SHOW_PROGRESS("Error: entry in product ID list is not a hex string: %s. Ignoring\n", token); 925 goto NextToken; 926 } 927 product = 0; 928 product += (unsigned char)buffer[0]; 929 product <<= 8; 930 product += (unsigned char)buffer[1]; 931 if (product == dev->descriptor.idProduct) { 932 if (verbose) 933 printf (" found matching product ID from list\n"); 934 (*numFound)++; 935 if (busnum == -1) 936 right_dev = dev; 937 else 938 if (dev->devnum >= devnum && (int)strtol(dev->bus->dirname,NULL,10) == busnum) { 939 right_dev = dev; 940 TargetProduct = dev->descriptor.idProduct; 941 break; 942 } 943 } 944 945 NextToken: 946 token = strtok(NULL, ","); 947 } 948 // product is given 949 } else 950 if (product == dev->descriptor.idProduct) { 951 if (verbose) 952 printf (" found matching product ID\n"); 953 (*numFound)++; 954 devClass = dev->descriptor.bDeviceClass; 955 if (devClass == 0) 956 devClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass; 957 else 958 if (devClass != dev->config[0].interface[0].altsetting[0].bInterfaceClass) 959 devClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass; 960 if (busnum == -1) { 961 if (devClass != targetClass || targetClass == 0) 962 right_dev = dev; 963 } else 964 if (devClass == targetClass || targetClass == 0) 965 if (dev->devnum >= devnum && (int)strtol(dev->bus->dirname,NULL,10) == busnum) 966 right_dev = dev; 967 } 968 if (right_dev && busnum != -1) 969 break; 970 } 971 if (right_dev && busnum != -1) 972 break; 973 } 974 if (productList != NULL) 975 free(listcopy); 976 return right_dev; 977} 978 979 980#define USB_DIR_OUT 0x00 981#define USB_DIR_IN 0x80 982 983// Autodetect bulk endpoints (ab) 984 985int find_first_bulk_output_endpoint(struct usb_device *dev) 986{ 987 int i; 988 struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]); 989 struct usb_endpoint_descriptor *ep; 990 991 for(i=0;i < alt->bNumEndpoints;i++) { 992 ep=&(alt->endpoint[i]); 993 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) && 994 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT ) ) { 995 return ep->bEndpointAddress; 996 } 997 } 998 999 return 0; 1000} 1001 1002 1003int find_first_bulk_input_endpoint(struct usb_device *dev) 1004{ 1005 int i; 1006 struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]); 1007 struct usb_endpoint_descriptor *ep; 1008 1009 for(i=0;i < alt->bNumEndpoints;i++) { 1010 ep=&(alt->endpoint[i]); 1011 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) && 1012 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) ) { 1013 return ep->bEndpointAddress; 1014 } 1015 } 1016 1017 return 0; 1018} 1019 1020 1021 1022// the parameter parsing stuff 1023 1024char* ReadParseParam(const char* FileName, char *VariableName) 1025{ 1026 static char Str[LINE_DIM]; 1027 char *VarName, *Comment=NULL, *Equal=NULL; 1028 char *FirstQuote, *LastQuote, *P1, *P2; 1029 int Line=0, Len=0, Pos=0; 1030 FILE *file=fopen(FileName, "r"); 1031 1032 if (file==NULL) { 1033 fprintf(stderr, "Error: Could not find file %s\n\n", FileName); 1034 exit(1); 1035 } 1036 1037 while (fgets(Str, LINE_DIM-1, file) != NULL) { 1038 Line++; 1039 Len=strlen(Str); 1040 if (Len==0) goto Next; 1041 if (Str[Len-1]=='\n' or Str[Len-1]=='\r') Str[--Len]='\0'; 1042 Equal = strchr (Str, '='); // search for equal sign 1043 Pos = strcspn (Str, ";#!"); // search for comment 1044 Comment = (Pos==Len) ? NULL : Str+Pos; 1045 if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next; // Only comment 1046 *Equal++ = '\0'; 1047 if (Comment!=NULL) *Comment='\0'; 1048 1049 // String 1050 FirstQuote=strchr (Equal, '"'); // search for double quote char 1051 LastQuote=strrchr (Equal, '"'); 1052 if (FirstQuote!=NULL) { 1053 if (LastQuote==NULL) { 1054 fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote.\n", FileName, Line); 1055 goto Next; 1056 } 1057 *FirstQuote=*LastQuote='\0'; 1058 Equal=FirstQuote+1; 1059 } 1060 1061 // removes leading/trailing spaces 1062 Pos=strspn (Str, " \t"); 1063 if (Pos==strlen(Str)) { 1064 fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name.\n", FileName, Line); 1065 goto Next; // No function name 1066 } 1067 while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL) 1068 if (P1!=NULL) *P1='\0'; 1069 else if (P2!=NULL) *P2='\0'; 1070 VarName=Str+Pos; 1071 //while (strspn(VarName, " \t")==strlen(VarName)) VarName++; 1072 1073 Pos=strspn (Equal, " \t"); 1074 if (Pos==strlen(Equal)) { 1075 fprintf(stderr, "Error reading parameter file %s line %d - Missing value.\n", FileName, Line); 1076 goto Next; // No function name 1077 } 1078 Equal+=Pos; 1079 1080 if (strcmp(VarName, VariableName)==0) { // Found it 1081 fclose(file); 1082 return Equal; 1083 } 1084 Next:; 1085 } 1086 1087 // not found 1088// fprintf(stderr, "Error reading parameter file %s - Variable %s not found.", 1089// FileName, VariableName); 1090 fclose(file); 1091 return NULL; 1092} 1093 1094 1095int hex2num(char c) 1096{ 1097 if (c >= '0' && c <= '9') 1098 return c - '0'; 1099 if (c >= 'a' && c <= 'f') 1100 return c - 'a' + 10; 1101 if (c >= 'A' && c <= 'F') 1102 return c - 'A' + 10; 1103 return -1; 1104} 1105 1106 1107int hex2byte(const char *hex) 1108{ 1109 int a, b; 1110 a = hex2num(*hex++); 1111 if (a < 0) 1112 return -1; 1113 b = hex2num(*hex++); 1114 if (b < 0) 1115 return -1; 1116 return (a << 4) | b; 1117} 1118 1119int hexstr2bin(const char *hex, char *buffer, int len) 1120{ 1121 int i; 1122 int a; 1123 const char *ipos = hex; 1124 char *opos = buffer; 1125// printf("Debug: hexstr2bin bytestring is "); 1126 1127 for (i = 0; i < len; i++) { 1128 a = hex2byte(ipos); 1129// printf("%02X", a); 1130 if (a < 0) 1131 return -1; 1132 *opos++ = a; 1133 ipos += 2; 1134 } 1135// printf(" \n"); 1136 return 0; 1137} 1138 1139void printVersion() 1140{ 1141 printf("\n * usb-modeswitch: handle USB devices with multiple modes\n"); 1142 printf(" * Version %s (C) Josua Dietze 2010\n", version); 1143 printf(" * Based on libusb 0.1.12\n\n"); 1144 printf(" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n"); 1145} 1146