minidlna support now Samsung TV C550/C650 (thx amir909)
[tomato.git] / release / src / router / usbmodeswitch / usb_modeswitch.c
blobf184640edba0cd3f98e6343a20bced97c0b0e47c
1 /*
2 Mode switching tool for controlling flip flop (multiple device) USB gear
3 Version 1.1.7, 2011/02/27
5 Copyright (C) 2007 - 2011 Josua Dietze (mail to "usb_admin" at the domain
6 from the README; please do not post the complete address to the Internet!
7 Or write a personal message through the forum to "Josh". NO SUPPORT VIA
8 E-MAIL - please use the forum for that)
10 Command line parsing, decent usage/config output/handling, bugfixes and advanced
11 options added by:
12 Joakim Wennergren (jokedst) (gmail.com)
14 TargetClass parameter implementation to support new Option devices/firmware:
15 Paul Hardwick (http://www.pharscape.org)
17 Created with initial help from:
18 "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
20 Config file parsing stuff borrowed from:
21 Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
23 Hexstr2bin function borrowed from:
24 Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
26 Other contributions: see README
28 Device information contributors are named in the "usb_modeswitch.setup" file.
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 2 of the License, or
33 (at your option) any later version.
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details:
40 http://www.gnu.org/licenses/gpl.txt
44 /* Recommended tab size: 4 */
46 #define VERSION "1.1.6"
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <assert.h>
52 #include <signal.h>
53 #include <ctype.h>
54 #include <getopt.h>
55 #include <syslog.h>
57 #ifndef LIBUSB10
58 #include <usb.h>
60 inline int get_devnum(struct usb_device * dev)
62 return dev->devnum;
64 inline int get_busnum(struct usb_device * dev)
66 return (int)strtol(dev->bus->dirname,NULL,10);
68 #else
69 #include <libusb.h>
70 #include <unistd.h>
72 #define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN
73 #define USB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT
74 #define USB_ENDPOINT_TYPE_MASK LIBUSB_ENDPOINT_ADDRESS_MASK
75 #define USB_ENDPOINT_DIR_MASK LIBUSB_ENDPOINT_DIR_MASK
76 #define USB_ENDPOINT_TYPE_BULK LIBUSB_TRANSFER_TYPE_BULK
77 #define USB_TYPE_STANDARD LIBUSB_REQUEST_TYPE_STANDARD
78 #define USB_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR
79 #define USB_RECIP_DEVICE LIBUSB_RECIPIENT_DEVICE
80 #define USB_REQ_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
81 #define USB_REQ_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
83 #define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
84 #define LIBUSB_HAS_GET_DRIVER_NP
87 #define usb_device libusb_device
88 #define usb_dev_handle libusb_device_handle
89 #define usb_endpoint_descriptor libusb_endpoint_descriptor
91 #define usb_init() libusb_init ( &ctx )
92 #define usb_set_debug(x) libusb_set_debug( ctx, 3 )
93 #define usb_find_busses() (0)
94 #define usb_find_devices() (0)
95 #define usb_close libusb_close
96 #define usb_get_string_simple libusb_get_string_descriptor_ascii
97 #define usb_reset libusb_reset_device
98 #define usb_claim_interface libusb_claim_interface
99 #define usb_clear_halt libusb_clear_halt
100 #define usb_release_interface libusb_release_interface
101 #define usb_control_msg libusb_control_transfer
102 #define usb_set_configuration libusb_set_configuration
103 #define usb_detach_kernel_driver_np libusb_detach_kernel_driver
105 libusb_device_handle * usb_open(libusb_device *dev){
106 libusb_device_handle * handle;
107 libusb_open(dev, &handle);
108 return handle;
111 int get_busnum(struct libusb_device * dev)
113 return libusb_get_bus_number(dev);
116 int get_devnum(struct libusb_device * dev)
118 return libusb_get_device_address(dev);
121 int usb_get_driver_np(struct libusb_device_handle *dev, int interface,
122 char *name, unsigned int namelen)
124 int r = libusb_kernel_driver_active(dev, interface);
125 if (r == 1) {
126 /* libusb-1.0 doesn't expose driver name, so fill in a dummy value */
127 snprintf(name, namelen, "dummy");
128 return 0;
129 } else return r;
132 int usb_bulk_io(struct libusb_device_handle *dev, int ep, char *bytes,
133 int size, int timeout)
135 int actual_length;
136 int r;
137 printf("endpoint %x size %d timeout %d", ep, size, timeout);
138 r = libusb_bulk_transfer(dev, ep & 0xff, bytes, size,
139 &actual_length, timeout);
141 /* if we timed out but did transfer some data, report as successful short
142 * read. FIXME: is this how libusb-0.1 works? */
143 if (r == 0 || (r == LIBUSB_ERROR_TIMEOUT && actual_length > 0))
144 return actual_length;
146 return r;
149 int usb_bulk_read(struct usb_dev_handle *dev, int ep, char *bytes,
150 int size, int timeout)
152 if (!(ep & LIBUSB_ENDPOINT_IN)) {
153 /* libusb-0.1 will strangely fix up a read request from endpoint
154 * 0x01 to be from endpoint 0x81. do the same thing here, but
155 * warn about this silly behaviour. */
156 puts("endpoint %x is missing IN direction bit, fixing");
157 ep |= LIBUSB_ENDPOINT_IN;
160 return usb_bulk_io(dev, ep, bytes, size, timeout);
163 int usb_bulk_write(struct usb_dev_handle *dev, int ep, char *bytes,
164 int size, int timeout)
166 if (ep & LIBUSB_ENDPOINT_IN) {
167 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
168 * 0x81 to be to endpoint 0x01. do the same thing here, but
169 * warn about this silly behaviour. */
170 puts("endpoint %x has excessive IN direction bit, fixing");
171 ep &= ~LIBUSB_ENDPOINT_IN;
174 return usb_bulk_io(dev, ep, bytes, size, timeout);
177 static struct libusb_context *ctx = NULL;
179 #endif
181 #include "usb_modeswitch.h"
183 #define LINE_DIM 1024
184 #define BUF_SIZE 4096
185 #define DESCR_MAX 129
187 #define SEARCH_DEFAULT 0
188 #define SEARCH_TARGET 1
190 #define SHOW_PROGRESS if (show_progress) printf
192 //int write_bulk(int endpoint, char *message, int length);
193 //int read_bulk(int endpoint, char *buffer, int length);
195 //int find_first_bulk_output_endpoint(struct usb_device *dev);
196 //int find_first_bulk_input_endpoint(struct usb_device *dev);
198 char *TempPP=NULL;
200 struct usb_device *dev;
201 struct usb_dev_handle *devh;
203 int DefaultVendor=0, DefaultProduct=0, TargetVendor=0, TargetProduct=-1, TargetClass=0;
204 int MessageEndpoint=0, ResponseEndpoint=0, ReleaseDelay=0;
205 int targetDeviceCount=0;
206 int devnum=-1, busnum=-1;
207 int ret;
209 char DetachStorageOnly=0, HuaweiMode=0, SierraMode=0, SonyMode=0, GCTMode=0, KobilMode=0;
210 char verbose=0, show_progress=1, ResetUSB=0, CheckSuccess=0, config_read=0;
211 char NeedResponse=0, NoDriverLoading=0, InquireDevice=1, sysmode=0;
213 char imanufact[DESCR_MAX], iproduct[DESCR_MAX], iserial[DESCR_MAX];
215 char MessageContent[LINE_DIM];
216 char MessageContent2[LINE_DIM];
217 char MessageContent3[LINE_DIM];
218 char TargetProductList[LINE_DIM];
219 char ByteString[LINE_DIM/2];
220 char buffer[BUF_SIZE];
222 /* Settable Interface and Configuration (for debugging mostly) (jmw) */
223 int Interface = 0, Configuration = 0, AltSetting = -1;
226 static struct option long_options[] = {
227 {"help", no_argument, 0, 'h'},
228 {"version", no_argument, 0, 'e'},
229 {"default-vendor", required_argument, 0, 'v'},
230 {"default-product", required_argument, 0, 'p'},
231 {"target-vendor", required_argument, 0, 'V'},
232 {"target-product", required_argument, 0, 'P'},
233 {"target-class", required_argument, 0, 'C'},
234 {"message-endpoint", required_argument, 0, 'm'},
235 {"message-content", required_argument, 0, 'M'},
236 {"message-content2", required_argument, 0, '2'},
237 {"message-content3", required_argument, 0, '3'},
238 {"release-delay", required_argument, 0, 'w'},
239 {"response-endpoint", required_argument, 0, 'r'},
240 {"detach-only", no_argument, 0, 'd'},
241 {"huawei-mode", no_argument, 0, 'H'},
242 {"sierra-mode", no_argument, 0, 'S'},
243 {"sony-mode", no_argument, 0, 'O'},
244 {"kobil-mode", no_argument, 0, 'T'},
245 {"gct-mode", no_argument, 0, 'G'},
246 {"need-response", no_argument, 0, 'n'},
247 {"reset-usb", no_argument, 0, 'R'},
248 {"config-file", required_argument, 0, 'c'},
249 {"verbose", no_argument, 0, 'W'},
250 {"quiet", no_argument, 0, 'Q'},
251 {"sysmode", no_argument, 0, 'D'},
252 {"no-inquire", no_argument, 0, 'I'},
253 {"check-success", required_argument, 0, 's'},
254 {"interface", required_argument, 0, 'i'},
255 {"configuration", required_argument, 0, 'u'},
256 {"altsetting", required_argument, 0, 'a'},
257 {0, 0, 0, 0}
261 void readConfigFile(const char *configFilename)
263 if (verbose) printf("\nReading config file: %s\n", configFilename);
264 ParseParamHex(configFilename, TargetVendor);
265 ParseParamHex(configFilename, TargetProduct);
266 ParseParamString(configFilename, TargetProductList);
267 ParseParamHex(configFilename, TargetClass);
268 ParseParamHex(configFilename, DefaultVendor);
269 ParseParamHex(configFilename, DefaultProduct);
270 ParseParamBool(configFilename, DetachStorageOnly);
271 ParseParamBool(configFilename, HuaweiMode);
272 ParseParamBool(configFilename, SierraMode);
273 ParseParamBool(configFilename, SonyMode);
274 ParseParamBool(configFilename, GCTMode);
275 ParseParamBool(configFilename, KobilMode);
276 ParseParamBool(configFilename, NoDriverLoading);
277 ParseParamHex(configFilename, MessageEndpoint);
278 ParseParamString(configFilename, MessageContent);
279 ParseParamString(configFilename, MessageContent2);
280 ParseParamString(configFilename, MessageContent3);
281 ParseParamInt(configFilename, ReleaseDelay);
282 ParseParamHex(configFilename, NeedResponse);
283 ParseParamHex(configFilename, ResponseEndpoint);
284 ParseParamHex(configFilename, ResetUSB);
285 ParseParamHex(configFilename, InquireDevice);
286 ParseParamInt(configFilename, CheckSuccess);
287 ParseParamHex(configFilename, Interface);
288 ParseParamHex(configFilename, Configuration);
289 ParseParamHex(configFilename, AltSetting);
291 /* TargetProductList has priority over TargetProduct */
292 if (TargetProduct != -1 && TargetProductList[0] != '\0') {
293 TargetProduct = -1;
294 SHOW_PROGRESS("Warning: TargetProductList overrides TargetProduct!\n");
297 config_read = 1;
301 void printConfig()
303 if ( DefaultVendor )
304 printf ("DefaultVendor= 0x%04x\n", DefaultVendor);
305 else
306 printf ("DefaultVendor= not set\n");
307 if ( DefaultProduct )
308 printf ("DefaultProduct= 0x%04x\n", DefaultProduct);
309 else
310 printf ("DefaultProduct= not set\n");
311 if ( TargetVendor )
312 printf ("TargetVendor= 0x%04x\n", TargetVendor);
313 else
314 printf ("TargetVendor= not set\n");
315 if ( TargetProduct > -1 )
316 printf ("TargetProduct= 0x%04x\n", TargetProduct);
317 else
318 printf ("TargetProduct= not set\n");
319 if ( TargetClass )
320 printf ("TargetClass= 0x%02x\n", TargetClass);
321 else
322 printf ("TargetClass= not set\n");
323 printf ("TargetProductList=\"%s\"\n", TargetProductList);
324 printf ("\nDetachStorageOnly=%i\n", (int)DetachStorageOnly);
325 printf ("HuaweiMode=%i\n", (int)HuaweiMode);
326 printf ("SierraMode=%i\n", (int)SierraMode);
327 printf ("SonyMode=%i\n", (int)SonyMode);
328 printf ("GCTMode=%i\n", (int)GCTMode);
329 printf ("KobilMode=%i\n", (int)KobilMode);
330 if ( MessageEndpoint )
331 printf ("MessageEndpoint=0x%02x\n", MessageEndpoint);
332 else
333 printf ("MessageEndpoint= not set\n");
334 printf ("MessageContent=\"%s\"\n", MessageContent);
335 if ( strlen(MessageContent2) )
336 printf ("MessageContent2=\"%s\"\n", MessageContent2);
337 if ( strlen(MessageContent3) )
338 printf ("MessageContent3=\"%s\"\n", MessageContent3);
339 printf ("NeedResponse=%i\n", (int)NeedResponse);
340 if ( ResponseEndpoint )
341 printf ("ResponseEndpoint=0x%02x\n", ResponseEndpoint);
342 else
343 printf ("ResponseEndpoint= not set\n");
344 printf ("Interface=0x%02x\n", Interface);
345 if ( Configuration > 0 )
346 printf ("Configuration=0x%02x\n", Configuration);
347 if ( AltSetting > -1 )
348 printf ("AltSetting=0x%02x\n", AltSetting);
349 if ( InquireDevice )
350 printf ("\nInquireDevice enabled (default)\n");
351 else
352 printf ("\nInquireDevice disabled\n");
353 if ( CheckSuccess )
354 printf ("Success check enabled, max. wait time %d seconds\n", CheckSuccess);
355 else
356 printf ("Success check disabled\n");
357 if ( sysmode )
358 printf ("System integration mode enabled\n");
359 else
360 printf ("System integration mode disabled\n");
361 printf ("\n");
365 int readArguments(int argc, char **argv)
367 int c, option_index = 0, count=0;
368 if (argc==1)
370 printHelp();
371 printVersion();
372 exit(1);
375 while (1)
377 c = getopt_long (argc, argv, "heWQDndHSOGTRIv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:",
378 long_options, &option_index);
380 /* Detect the end of the options. */
381 if (c == -1)
382 break;
383 count++;
384 switch (c)
386 case 'R': ResetUSB = 1; break;
387 case 'v': DefaultVendor = strtol(optarg, NULL, 16); break;
388 case 'p': DefaultProduct = strtol(optarg, NULL, 16); break;
389 case 'V': TargetVendor = strtol(optarg, NULL, 16); break;
390 case 'P': TargetProduct = strtol(optarg, NULL, 16); break;
391 case 'C': TargetClass = strtol(optarg, NULL, 16); break;
392 case 'm': MessageEndpoint = strtol(optarg, NULL, 16); break;
393 case 'M': strcpy(MessageContent, optarg); break;
394 case '2': strcpy(MessageContent2, optarg); break;
395 case '3': strcpy(MessageContent3, optarg); break;
396 case 'w': ReleaseDelay = strtol(optarg, NULL, 10); count--; break;
397 case 'n': NeedResponse = 1; break;
398 case 'r': ResponseEndpoint = strtol(optarg, NULL, 16); break;
399 case 'd': DetachStorageOnly = 1; break;
400 case 'H': HuaweiMode = 1; break;
401 case 'S': SierraMode = 1; break;
402 case 'O': SonyMode = 1; break;
403 case 'G': GCTMode = 1; break;
404 case 'T': KobilMode = 1; break;
405 case 'c': readConfigFile(optarg); break;
406 case 'W': verbose = 1; show_progress = 1; count--; break;
407 case 'Q': show_progress = 0; verbose = 0; count--; break;
408 case 'D': sysmode = 1; count--; break;
409 case 's': CheckSuccess = strtol(optarg, NULL, 10); count--; break;
410 case 'I': InquireDevice = 0; break;
412 case 'i': Interface = strtol(optarg, NULL, 16); break;
413 case 'u': Configuration = strtol(optarg, NULL, 16); break;
414 case 'a': AltSetting = strtol(optarg, NULL, 16); break;
416 case 'e':
417 printVersion();
418 exit(0);
419 break;
420 case 'h':
421 printVersion();
422 printHelp();
423 exit(0);
424 break;
426 default: /* Unsupported - error message has already been printed */
427 printf ("\n");
428 printHelp();
429 exit(1);
433 return count;
437 int main(int argc, char **argv)
439 int numDefaults=0, specialMode=0, sonySuccess=0;
440 int currentConfig=0, defaultClass=0, interfaceClass=0;
442 /* Make sure we have empty strings even if not set by config */
443 TargetProductList[0] = '\0';
444 MessageContent[0] = '\0';
445 MessageContent2[0] = '\0';
446 MessageContent3[0] = '\0';
449 signal(SIGTERM, release_usb_device);
451 * Parameter parsing, USB preparation/diagnosis, plausibility checks
454 /* Check command arguments, use params instead of config file when given */
455 switch (readArguments(argc, argv)) {
456 case 0: /* no argument or -W, -q or -s */
457 break;
458 default: /* one or more arguments except -W, -q or -s */
459 if (!config_read) /* if arguments contain -c, the config file was already processed */
460 if (verbose) printf("Taking all parameters from the command line\n\n");
463 if (verbose)
464 printVersion();
466 if (verbose)
467 printConfig();
469 /* libusb initialization */
470 usb_init();
472 if (verbose)
473 usb_set_debug(15);
475 usb_find_busses();
476 usb_find_devices();
478 /* Plausibility checks. The default IDs are mandatory */
479 if (!(DefaultVendor && DefaultProduct)) {
480 SHOW_PROGRESS("No default vendor/product ID given. Aborting.\n\n");
481 exit(1);
483 if (strlen(MessageContent)) {
484 if (strlen(MessageContent) % 2 != 0) {
485 fprintf(stderr, "Error: MessageContent hex string has uneven length. Aborting.\n\n");
486 exit(1);
488 if ( hexstr2bin(MessageContent, ByteString, strlen(MessageContent)/2) == -1) {
489 fprintf(stderr, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent);
490 exit(1);
493 SHOW_PROGRESS("\n");
495 if (show_progress)
496 if (CheckSuccess && !(TargetVendor || TargetProduct > -1 || TargetProductList[0] != '\0') && !TargetClass)
497 printf("Note: target parameter missing; success check limited\n");
499 /* Count existing target devices, remember for success check */
500 if (TargetVendor || TargetClass) {
501 SHOW_PROGRESS("Looking for target devices ...\n");
502 search_devices(&targetDeviceCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
503 if (targetDeviceCount) {
504 SHOW_PROGRESS(" Found devices in target mode or class (%d)\n", targetDeviceCount);
505 } else
506 SHOW_PROGRESS(" No devices in target mode or class found\n");
509 /* Count default devices, get the last one found */
510 SHOW_PROGRESS("Looking for default devices ...\n");
511 dev = search_devices(&numDefaults, DefaultVendor, DefaultProduct, "\0", TargetClass, Configuration, SEARCH_DEFAULT);
512 if (numDefaults) {
513 SHOW_PROGRESS(" Found devices in default mode, class or configuration (%d)\n", numDefaults);
514 } else {
515 SHOW_PROGRESS(" No devices in default mode found. Nothing to do. Bye.\n\n");
516 exit(0);
518 if (dev != NULL) {
519 devnum = get_devnum(dev);
520 busnum = get_busnum(dev);
521 SHOW_PROGRESS("Accessing device %03d on bus %03d ...\n", devnum, busnum);
522 devh = usb_open(dev);
523 } else {
524 SHOW_PROGRESS(" No default device found. Is it connected? Bye.\n\n");
525 exit(0);
528 /* Get current configuration of default device */
529 currentConfig = get_current_configuration(devh);
531 /* Get class of default device/interface */
532 #ifndef LIBUSB10
533 defaultClass = dev->descriptor.bDeviceClass;
534 interfaceClass = get_interface0_class(dev, currentConfig);
535 #else
536 struct libusb_device_descriptor descriptor;
537 libusb_get_device_descriptor(dev, &descriptor);
538 defaultClass = descriptor.bDeviceClass;
539 struct libusb_config_descriptor *config;
540 libusb_get_config_descriptor(dev, 0, &config);
541 interfaceClass = config->interface[0].altsetting[0].bInterfaceClass;
542 libusb_free_config_descriptor(config);
543 #endif
544 if (interfaceClass == -1) {
545 fprintf(stderr, "Error: getting the interface class failed. Aborting.\n\n");
546 exit(1);
549 if (defaultClass == 0)
550 defaultClass = interfaceClass;
551 else
552 if (interfaceClass == 8 && defaultClass != 8) {
553 /* Weird device with default class other than 0 and differing interface class */
554 SHOW_PROGRESS("Ambiguous Class/InterfaceClass: 0x%02x/0x08\n", defaultClass);
555 defaultClass = 8;
558 /* Check or get endpoints */
559 if (strlen(MessageContent) || InquireDevice) {
560 if (!MessageEndpoint)
561 MessageEndpoint = find_first_bulk_output_endpoint(dev);
562 if (!MessageEndpoint) {
563 fprintf(stderr,"Error: message endpoint not given or found. Aborting.\n\n");
564 exit(1);
566 if (!ResponseEndpoint)
567 ResponseEndpoint = find_first_bulk_input_endpoint(dev);
568 if (!ResponseEndpoint) {
569 fprintf(stderr,"Error: response endpoint not given or found. Aborting.\n\n");
570 exit(1);
572 SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
575 if (MessageEndpoint && ResponseEndpoint) {
576 SHOW_PROGRESS("Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint, ResponseEndpoint);
577 } else
578 if (InquireDevice && defaultClass == 0x08) {
579 SHOW_PROGRESS("Endpoints not found, skipping SCSI inquiry\n");
580 InquireDevice = 0;
583 if (InquireDevice && show_progress) {
584 if (defaultClass == 0x08) {
585 SHOW_PROGRESS("Inquiring device details; driver will be detached ...\n");
586 detachDriver();
587 if (deviceInquire() >= 0)
588 InquireDevice = 2;
589 } else
590 SHOW_PROGRESS("Not a storage device, skipping SCSI inquiry\n");
593 deviceDescription();
594 if (show_progress) {
595 printf("\nUSB description data (for identification)\n");
596 printf("-------------------------\n");
597 printf("Manufacturer: %s\n", imanufact);
598 printf(" Product: %s\n", iproduct);
599 printf(" Serial No.: %s\n", iserial);
600 printf("-------------------------\n");
603 /* Some scenarios are exclusive, so check for unwanted combinations */
604 specialMode = DetachStorageOnly + HuaweiMode + SierraMode + SonyMode + KobilMode;
605 if ( specialMode > 1 ) {
606 SHOW_PROGRESS("Invalid mode combination. Check your configuration. Aborting.\n\n");
607 exit(1);
610 if ( !specialMode && !strlen(MessageContent) && AltSetting == -1 && Configuration == 0 )
611 SHOW_PROGRESS("Warning: no switching method given.\n");
614 * The switching actions
617 if (sysmode) {
618 openlog("usb_modeswitch", 0, LOG_SYSLOG);
619 syslog(LOG_NOTICE, "switching %04x:%04x (%s: %s)", DefaultVendor, DefaultProduct, imanufact, iproduct);
622 if (DetachStorageOnly) {
623 SHOW_PROGRESS("Only detaching storage driver for switching ...\n");
624 if (InquireDevice == 2) {
625 SHOW_PROGRESS(" Any driver was already detached for inquiry\n");
626 } else {
627 ret = detachDriver();
628 if (ret == 2)
629 SHOW_PROGRESS(" You may want to remove the storage driver manually\n");
633 if (HuaweiMode) {
634 switchHuaweiMode();
636 if (SierraMode) {
637 switchSierraMode();
639 if (GCTMode) {
640 detachDriver();
641 switchGCTMode();
643 if(KobilMode) {
644 detachDriver();
645 switchKobilMode();
647 if (SonyMode) {
648 if (CheckSuccess)
649 SHOW_PROGRESS("Note: ignoring CheckSuccess. Separate checks for Sony mode\n");
650 CheckSuccess = 0; /* separate and implied success control */
651 sonySuccess = switchSonyMode();
654 if (strlen(MessageContent) && MessageEndpoint) {
655 if (specialMode == 0) {
656 if (InquireDevice != 2)
657 detachDriver();
658 switchSendMessage();
659 } else
660 SHOW_PROGRESS("Warning: ignoring MessageContent. Can't combine with special mode\n");
663 if (Configuration != 0) {
664 if (currentConfig != Configuration) {
665 if (switchConfiguration()) {
666 currentConfig = get_current_configuration(devh);
667 if (currentConfig == Configuration) {
668 SHOW_PROGRESS("The configuration was set successfully\n");
669 } else {
670 SHOW_PROGRESS("Setting the configuration failed\n");
673 } else {
674 SHOW_PROGRESS("Target configuration %d already active. Doing nothing\n", currentConfig);
678 if (AltSetting != -1) {
679 switchAltSetting();
682 /* No "removal" check if these are set */
683 if ((Configuration != 0 || AltSetting != -1) && !ResetUSB) {
684 usb_close(devh);
685 devh = 0;
688 if (ResetUSB) {
689 resetUSB();
690 usb_close(devh);
691 devh = 0;
694 if (CheckSuccess) {
695 if (checkSuccess()) {
696 if (sysmode) {
697 if (NoDriverLoading)
698 printf("ok:\n");
699 else
700 if (TargetProduct < 1)
701 printf("ok:no_data\n");
702 else
703 printf("ok:%04x:%04x\n", TargetVendor, TargetProduct);
705 } else
706 if (sysmode)
707 printf("fail:\n");
708 } else {
709 if (SonyMode)
710 if (sonySuccess) {
711 if (sysmode) {
712 syslog(LOG_NOTICE, "switched S.E. MD400 to modem mode");
713 printf("ok:\n"); /* ACM device, no driver action */
715 SHOW_PROGRESS("-> device should be stable now. Bye.\n\n");
716 } else {
717 if (sysmode)
718 printf("fail:\n");
719 SHOW_PROGRESS("-> switching was probably not completed. Bye.\n\n");
721 else
722 SHOW_PROGRESS("-> Run lsusb to note any changes. Bye.\n\n");
725 if (sysmode)
726 closelog();
727 if (devh)
728 usb_close(devh);
729 exit(0);
733 /* Get descriptor strings if available (identification details) */
734 void deviceDescription ()
736 int ret;
737 char* c;
738 memset (imanufact, ' ', DESCR_MAX);
739 memset (iproduct, ' ', DESCR_MAX);
740 memset (iserial, ' ', DESCR_MAX);
742 #ifndef LIBUSB10
743 int iManufacturer = dev->descriptor.iManufacturer;
744 int iProduct = dev->descriptor.iProduct;
745 int iSerialNumber = dev->descriptor.iSerialNumber;
746 #else
747 struct libusb_device_descriptor descriptor;
748 libusb_get_device_descriptor(dev, &descriptor);
750 int iManufacturer = descriptor.iManufacturer;
751 int iProduct = descriptor.iProduct;
752 int iSerialNumber = descriptor.iSerialNumber;
753 #endif
755 if (iManufacturer) {
756 ret = usb_get_string_simple(devh, iManufacturer, imanufact, DESCR_MAX);
757 if (ret < 0)
758 fprintf(stderr, "Error: could not get description string \"manufacturer\"\n");
759 } else
760 strcpy(imanufact, "not provided");
761 c = strstr(imanufact, " ");
762 if (c)
763 memset((void*)c, '\0', 1);
765 if (iProduct) {
766 ret = usb_get_string_simple(devh, iProduct, iproduct, DESCR_MAX);
767 if (ret < 0)
768 fprintf(stderr, "Error: could not get description string \"product\"\n");
769 } else
770 strcpy(iproduct, "not provided");
771 c = strstr(iproduct, " ");
772 if (c)
773 memset((void*)c, '\0', 1);
775 if (iSerialNumber) {
776 ret = usb_get_string_simple(devh, iSerialNumber, iserial, DESCR_MAX);
777 if (ret < 0)
778 fprintf(stderr, "Error: could not get description string \"serial number\"\n");
779 } else
780 strcpy(iserial, "not provided");
781 c = strstr(iserial, " ");
782 if (c)
783 memset((void*)c, '\0', 1);
787 /* Print result of SCSI command INQUIRY (identification details) */
788 int deviceInquire ()
790 const unsigned char inquire_msg[] = {
791 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
792 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
793 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
796 char *command;
797 char data[36];
798 int i, ret;
800 command = malloc(31);
801 if (command == NULL) {
802 ret = 1;
803 goto out;
806 memcpy(command, inquire_msg, sizeof (inquire_msg));
808 ret = usb_claim_interface(devh, Interface);
809 if (ret != 0) {
810 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping device inquiry\n", ret);
811 goto out;
813 usb_clear_halt(devh, MessageEndpoint);
815 ret = usb_bulk_write(devh, MessageEndpoint, (char *)command, 31, 0);
816 if (ret < 0) {
817 SHOW_PROGRESS(" Could not send INQUIRY message (error %d)\n", ret);
818 goto out;
821 ret = usb_bulk_read(devh, ResponseEndpoint, data, 36, 0);
822 if (ret < 0) {
823 SHOW_PROGRESS(" Could not get INQUIRY response (error %d)\n", ret);
824 goto out;
827 i = usb_bulk_read(devh, ResponseEndpoint, command, 13, 0);
829 printf("\nSCSI inquiry data (for identification)\n");
830 printf("-------------------------\n");
832 printf(" Vendor String: ");
833 for (i = 8; i < 16; i++) printf("%c",data[i]);
834 printf("\n");
836 printf(" Model String: ");
837 for (i = 16; i < 32; i++) printf("%c",data[i]);
838 printf("\n");
840 printf("Revision String: ");
841 for (i = 32; i < 36; i++) printf("%c",data[i]);
843 printf("\n-------------------------\n");
845 out:
846 if (strlen(MessageContent) == 0)
847 usb_clear_halt(devh, MessageEndpoint);
848 usb_release_interface(devh, Interface);
849 free(command);
850 return ret;
854 void resetUSB ()
856 int success;
857 int bpoint = 0;
859 if (show_progress) {
860 printf("Resetting usb device ");
861 fflush(stdout);
864 sleep( 1 );
865 do {
866 success = usb_reset(devh);
867 if ( ((bpoint % 10) == 0) && show_progress ) {
868 printf(".");
869 fflush(stdout);
871 bpoint++;
872 if (bpoint > 100)
873 success = 1;
874 } while (success < 0);
876 if ( success ) {
877 SHOW_PROGRESS("\n Reset failed. Can be ignored if device switched OK.\n");
878 } else
879 SHOW_PROGRESS("\n OK, device was reset\n");
883 int switchSendMessage ()
885 int ret;
887 /* May be activated in future versions */
888 // if (MessageContent2[0] != '\0' || MessageContent3[0] != '\0')
889 // NeedResponse = 1;
891 SHOW_PROGRESS("Setting up communication with interface %d ...\n", Interface);
892 if (InquireDevice != 2) {
893 ret = usb_claim_interface(devh, Interface);
894 if (ret != 0) {
895 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping message sending\n", ret);
896 return 0;
899 usb_clear_halt(devh, MessageEndpoint);
900 SHOW_PROGRESS("Using endpoint 0x%02x for message sending ...\n", MessageEndpoint);
901 if (show_progress)
902 fflush(stdout);
904 if ( sendMessage(MessageContent, 1) )
905 goto skip;
907 if (NeedResponse) {
908 SHOW_PROGRESS("Reading the response to the message (CSW) ...\n");
909 ret = read_bulk(ResponseEndpoint, ByteString, 13);
910 if (ret < 0)
911 goto skip;
914 if (strlen(MessageContent2)) {
915 if ( sendMessage(MessageContent2, 2) )
916 goto skip;
918 if (NeedResponse) {
919 SHOW_PROGRESS("Reading the response to message 2 ...\n");
920 ret = read_bulk(ResponseEndpoint, ByteString, 13);
921 if (ret < 0)
922 goto skip;
926 if (strlen(MessageContent3)) {
927 if ( sendMessage(MessageContent3, 3) )
928 goto skip;
929 if (NeedResponse) {
930 SHOW_PROGRESS("Reading the response to message 3 ...\n");
931 ret = read_bulk(ResponseEndpoint, ByteString, 13);
932 if (ret < 0)
933 goto skip;
937 SHOW_PROGRESS("Resetting response endpoint 0x%02x\n", ResponseEndpoint);
938 ret = usb_clear_halt(devh, ResponseEndpoint);
939 if (ret)
940 SHOW_PROGRESS(" Error resetting endpoint: %d\n", ret);
941 SHOW_PROGRESS("Resetting message endpoint 0x%02x\n", MessageEndpoint);
942 ret = usb_clear_halt(devh, MessageEndpoint);
943 if (ret)
944 SHOW_PROGRESS(" Error resetting endpoint: %d\n", ret);
945 usleep(200000);
946 if (ReleaseDelay) {
947 SHOW_PROGRESS("Blocking the interface for %d ms before releasing ...\n", ReleaseDelay);
948 usleep(ReleaseDelay*1000);
950 ret = usb_release_interface(devh, Interface);
951 if (ret)
952 goto skip;
953 return 1;
955 skip:
956 SHOW_PROGRESS(" Device is gone, skipping any further commands\n");
957 usb_close(devh);
958 devh = 0;
959 return 2;
962 #define SWITCH_CONFIG_MAXTRIES 5
964 int switchConfiguration ()
966 int count = SWITCH_CONFIG_MAXTRIES;
967 int ret;
969 SHOW_PROGRESS("Changing configuration to %i ...\n", Configuration);
970 while (((ret = usb_set_configuration(devh, Configuration)) < 0) && --count) {
971 SHOW_PROGRESS(" Device is busy, trying to detach kernel driver\n");
972 detachDriver();
974 if (ret == 0 ) {
975 SHOW_PROGRESS(" OK, configuration set\n");
976 return 1;
978 SHOW_PROGRESS(" Setting the configuration returned error %d. Trying to continue\n", ret);
979 return 0;
983 int switchAltSetting ()
985 int ret;
987 SHOW_PROGRESS("Changing to alt setting %i ...\n", AltSetting);
988 ret = usb_claim_interface(devh, Interface);
989 #ifndef LIBUSB10
990 ret = usb_set_altinterface(devh, AltSetting);
991 #else
992 ret = libusb_set_interface_alt_setting(devh, Interface, AltSetting);
993 #endif
994 usb_release_interface(devh, Interface);
995 if (ret != 0) {
996 SHOW_PROGRESS(" Changing to alt setting returned error %d. Trying to continue\n", ret);
997 return 0;
998 } else {
999 SHOW_PROGRESS(" OK, changed to alt setting\n");
1000 return 1;
1005 void switchHuaweiMode ()
1007 int ret;
1009 SHOW_PROGRESS("Sending Huawei control message ...\n");
1010 ret = usb_control_msg(devh, USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_FEATURE, 00000001, 0, buffer, 0, 1000);
1011 if (ret != 0) {
1012 fprintf(stderr, "Error: sending Huawei control message failed (error %d). Aborting.\n\n", ret);
1013 exit(1);
1014 } else
1015 SHOW_PROGRESS(" OK, Huawei control message sent\n");
1019 void switchSierraMode ()
1021 int ret;
1023 SHOW_PROGRESS("Trying to send Sierra control message\n");
1024 ret = usb_control_msg(devh, 0x40, 0x0b, 00000001, 0, buffer, 0, 1000);
1025 if (ret != 0) {
1026 fprintf(stderr, "Error: sending Sierra control message failed (error %d). Aborting.\n\n", ret);
1027 exit(1);
1028 } else
1029 SHOW_PROGRESS(" OK, Sierra control message sent\n");
1033 void switchGCTMode ()
1035 int ret;
1037 ret = usb_claim_interface(devh, Interface);
1038 if (ret != 0) {
1039 SHOW_PROGRESS(" Could not claim interface (error %d). Skipping GCT sequence \n", ret);
1040 return;
1043 SHOW_PROGRESS("Sending GCT control message 1 ...\n");
1044 ret = usb_control_msg(devh, 0xa1, 0xa0, 0, Interface, buffer, 1, 1000);
1045 SHOW_PROGRESS("Sending GCT control message 2 ...\n");
1046 ret = usb_control_msg(devh, 0xa1, 0xfe, 0, Interface, buffer, 1, 1000);
1047 SHOW_PROGRESS(" OK, GCT control messages sent\n");
1048 usb_release_interface(devh, Interface);
1052 int switchKobilMode() {
1053 int ret;
1055 SHOW_PROGRESS("Sending Kobil control message ...\n");
1056 ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 0x88, 0, 0, buffer, 8, 1000);
1057 if (ret != 0) {
1058 fprintf(stderr, "Error: sending Kobil control message failed (error %d). Aborting.\n\n", ret);
1059 exit(1);
1060 } else
1061 SHOW_PROGRESS(" OK, Kobil control message sent\n");
1062 return 1;
1066 int switchSonyMode ()
1068 int i, found, ret;
1069 detachDriver();
1071 if (CheckSuccess) {
1072 printf("Note: CheckSuccess pointless with Sony mode, disabling\n");
1073 CheckSuccess = 0;
1076 SHOW_PROGRESS("Trying to send Sony control message\n");
1077 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1078 if (ret < 0) {
1079 fprintf(stderr, "Error: sending Sony control message failed (error %d). Aborting.\n\n", ret);
1080 exit(1);
1081 } else
1082 SHOW_PROGRESS(" OK, control message sent, waiting for device to return ...\n");
1084 usb_close(devh);
1085 devh = 0;
1087 /* Now waiting for the device to reappear */
1088 devnum=-1;
1089 busnum=-1;
1090 i=0;
1091 dev = 0;
1092 while ( dev == 0 && i < 30 ) {
1093 if ( i > 5 ) {
1094 usb_find_busses();
1095 usb_find_devices();
1096 dev = search_devices(&found, DefaultVendor, DefaultProduct, "\0", TargetClass, 0, SEARCH_TARGET);
1098 if ( dev != 0 )
1099 break;
1100 sleep(1);
1101 if (show_progress) {
1102 printf("#");
1103 fflush(stdout);
1105 i++;
1107 SHOW_PROGRESS("\n After %d seconds:",i);
1108 if ( dev ) {
1109 SHOW_PROGRESS(" device came back, proceeding\n");
1110 devh = usb_open( dev );
1111 if (devh == 0) {
1112 fprintf(stderr, "Error: could not get handle on device\n");
1113 return 0;
1115 } else {
1116 SHOW_PROGRESS(" device still gone, cancelling\n");
1117 return 0;
1119 sleep(1);
1121 SHOW_PROGRESS("Sending Sony control message again ...\n");
1122 ret = usb_control_msg(devh, 0xc0, 0x11, 2, 0, buffer, 3, 100);
1123 if (ret < 0) {
1124 fprintf(stderr, "Error: sending Sony control message (2) failed (error %d)\n", ret);
1125 return 0;
1127 SHOW_PROGRESS(" OK, control message sent\n");
1128 return 1;
1131 /* Detach driver either as the main action or as preparation for other
1132 * switching methods
1134 int detachDriver()
1136 int ret;
1138 #ifndef LIBUSB_HAS_GET_DRIVER_NP
1139 printf(" Cant't do driver detection and detaching on this platform.\n");
1140 return 2;
1141 #endif
1143 SHOW_PROGRESS("Looking for active driver ...\n");
1144 ret = usb_get_driver_np(devh, Interface, buffer, BUF_SIZE);
1145 if (ret != 0) {
1146 SHOW_PROGRESS(" No driver found. Either detached before or never attached\n");
1147 return 1;
1149 SHOW_PROGRESS(" OK, driver found (\"%s\")\n", buffer);
1150 if (DetachStorageOnly && strcmp(buffer,"usb-storage")) {
1151 SHOW_PROGRESS(" Warning: driver is not usb-storage\n");
1154 #ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
1155 SHOW_PROGRESS(" Can't do driver detaching on this platform\n");
1156 return 2;
1157 #endif
1160 ret = usb_detach_kernel_driver_np(devh, Interface);
1161 if (ret == 0) {
1162 SHOW_PROGRESS(" OK, driver \"%s\" detached\n", buffer);
1163 } else
1164 SHOW_PROGRESS(" Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer, ret);
1165 return 1;
1169 int sendMessage(char* message, int count)
1171 int message_length, ret;
1173 if (strlen(message) % 2 != 0) {
1174 fprintf(stderr, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count);
1175 return 1;
1177 message_length = strlen(message) / 2;
1178 if ( hexstr2bin(message, ByteString, message_length) == -1) {
1179 fprintf(stderr, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", count, MessageContent);
1180 return 1;
1182 SHOW_PROGRESS("Trying to send message %d to endpoint 0x%02x ...\n", count, MessageEndpoint);
1183 fflush(stdout);
1184 ret = write_bulk(MessageEndpoint, ByteString, message_length);
1185 if (ret == -19)
1186 return 1;
1188 return 0;
1192 int checkSuccess()
1194 int i=0, ret;
1195 int newTargetCount, success=0;
1197 SHOW_PROGRESS("\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess);
1198 sleep(1);
1200 /* if target ID is not given but target class is, assign default as target;
1201 * it will be needed for sysmode output
1203 if (!TargetVendor && TargetClass) {
1204 TargetVendor = DefaultVendor;
1205 TargetProduct = DefaultProduct;
1208 if (devh) // devh is 0 if device vanished during command transmission
1209 for (i=0; i < CheckSuccess; i++) {
1211 /* Test if default device still can be accessed; positive result does
1212 * not necessarily mean failure
1214 SHOW_PROGRESS(" Waiting for original device to vanish ...\n");
1216 ret = usb_claim_interface(devh, Interface);
1217 usb_release_interface(devh, Interface);
1218 if (ret < 0) {
1219 SHOW_PROGRESS(" Original device can't be accessed anymore. Good.\n");
1220 if (i == CheckSuccess-1)
1221 SHOW_PROGRESS(" If you want target checking, increase 'CheckSuccess' value.\n");
1222 usb_close(devh);
1223 devh = 0;
1224 break;
1226 if (i == CheckSuccess-1) {
1227 SHOW_PROGRESS(" Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n");
1228 } else
1229 sleep(1);
1233 if ( TargetVendor && (TargetProduct > -1 || TargetProductList[0] != '\0') ) {
1235 /* Recount target devices (compare with previous count) if target data is given.
1236 * Target device on the same bus with higher device number is returned,
1237 * description is read for syslog message
1239 for (i=i; i < CheckSuccess; i++) {
1240 SHOW_PROGRESS(" Searching for target devices ...\n");
1241 ret = usb_find_busses();
1242 if (ret >= 0)
1243 ret = usb_find_devices();
1244 if (ret < 0) {
1245 SHOW_PROGRESS("Error: libusb1 bug, no more searching, try to work around\n");
1246 success = 3;
1247 break;
1249 dev = search_devices(&newTargetCount, TargetVendor, TargetProduct, TargetProductList, TargetClass, 0, SEARCH_TARGET);
1250 if (dev && (newTargetCount > targetDeviceCount)) {
1251 printf("\nFound target device, now opening\n");
1252 devh = usb_open(dev);
1253 deviceDescription();
1254 usb_close(devh);
1255 devh = 0;
1256 if (verbose) {
1257 printf("\nFound target device %03d on bus %03d\n", \
1258 get_devnum(dev), get_busnum(dev));
1259 printf("\nTarget device description data\n");
1260 printf("-------------------------\n");
1261 printf("Manufacturer: %s\n", imanufact);
1262 printf(" Product: %s\n", iproduct);
1263 printf(" Serial No.: %s\n", iserial);
1264 printf("-------------------------\n");
1266 SHOW_PROGRESS(" Found correct target device\n\nMode switch succeeded. Bye.\n\n");
1267 success = 2;
1268 break;
1270 if (i == CheckSuccess-1) {
1271 SHOW_PROGRESS(" No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n");
1272 } else
1273 sleep(1);
1275 } else
1276 /* No target data given, rely on the vanished device */
1277 if (!devh) {
1278 SHOW_PROGRESS(" (For a better success check provide target IDs or class)\n");
1279 SHOW_PROGRESS(" Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n");
1280 success = 1;
1283 switch (success) {
1284 case 3:
1285 if (sysmode)
1286 syslog(LOG_NOTICE, "switched to new device, but hit libusb1 bug");
1287 TargetProduct = -1;
1288 success = 1;
1289 break;
1290 case 2:
1291 if (sysmode)
1292 syslog(LOG_NOTICE, "switched to %04x:%04x (%s: %s)", TargetVendor, TargetProduct, imanufact, iproduct);
1293 success = 1;
1294 break;
1295 case 1:
1296 if (sysmode)
1297 syslog(LOG_NOTICE, "device seems to have switched");
1298 default:
1301 if (sysmode)
1302 closelog();
1304 return success;
1309 int write_bulk(int endpoint, char *message, int length)
1311 int ret;
1312 ret = usb_bulk_write(devh, endpoint, message, length, 3000);
1313 if (ret >= 0 ) {
1314 SHOW_PROGRESS(" OK, message successfully sent\n");
1315 } else
1316 if (ret == -19) {
1317 SHOW_PROGRESS(" Device seems to have vanished right after sending. Good.\n");
1318 } else
1319 SHOW_PROGRESS(" Sending the message returned error %d. Trying to continue\n", ret);
1320 return ret;
1324 int read_bulk(int endpoint, char *buffer, int length)
1326 int ret;
1327 ret = usb_bulk_read(devh, endpoint, buffer, length, 3000);
1328 usb_bulk_read(devh, endpoint, buffer, 13, 100);
1329 if (ret >= 0 ) {
1330 SHOW_PROGRESS(" OK, response successfully read (%d bytes).\n", ret);
1331 } else
1332 if (ret == -19) {
1333 SHOW_PROGRESS(" Device seems to have vanished after reading. Good.\n");
1334 } else
1335 SHOW_PROGRESS(" Response reading got error %d, can probably be ignored\n", ret);
1336 return ret;
1340 void release_usb_device(int dummy) {
1341 SHOW_PROGRESS("Program cancelled by system. Bye.\n\n");
1342 if (devh) {
1343 usb_release_interface(devh, Interface);
1344 usb_close(devh);
1346 if (sysmode)
1347 closelog();
1348 exit(0);
1353 /* Iterates over busses and devices, counts the ones with the given
1354 * ID/class and returns the last one of them
1356 struct usb_device* search_devices( int *numFound, int vendor, int product, char* productList, int targetClass, int configuration, int mode)
1358 #ifndef LIBUSB10
1359 struct usb_bus *bus;
1360 #endif
1361 char *listcopy=NULL, *token, buffer[2];
1362 int devClass;
1363 struct usb_device* right_dev = NULL;
1364 struct usb_dev_handle *testdevh;
1366 /* only target class given, target vendor and product assumed unchanged */
1367 if ( targetClass && !(vendor || product) ) {
1368 vendor = DefaultVendor;
1369 product = DefaultProduct;
1371 *numFound = 0;
1373 /* Sanity check */
1374 if (!vendor || (!product && productList == '\0') )
1375 return NULL;
1377 if (productList != '\0')
1378 listcopy = malloc(strlen(productList)+1);
1380 #ifndef LIBUSB10
1381 for (bus = usb_get_busses(); bus; bus = bus->next) {
1382 struct usb_device *dev;
1383 for (dev = bus->devices; dev; dev = dev->next) {
1384 #else
1385 struct libusb_device **devs;
1386 int i=0;
1388 if (libusb_get_device_list( ctx, &devs ) < 0){
1389 perror ("failed to access USB");
1390 return 0;
1393 while ( (dev = devs[i++]) != NULL) {
1394 #endif
1395 #ifndef LIBUSB10
1396 int idVendor = dev->descriptor.idVendor;
1397 int idProduct = dev->descriptor.idProduct;
1398 #else
1399 struct libusb_device_descriptor descriptor;
1400 libusb_get_device_descriptor(dev, &descriptor);
1401 int idVendor = descriptor.idVendor;
1402 int idProduct = descriptor.idProduct;
1403 #endif
1404 if (verbose)
1405 printf (" searching devices, found USB ID %04x:%04x\n", idVendor, idProduct);
1406 if (idVendor != vendor)
1407 continue;
1408 if (verbose)
1409 printf (" found matching vendor ID\n");
1410 // product list given
1411 if ( strlen(productList) ) {
1412 strcpy(listcopy, productList);
1413 token = strtok(listcopy, ",");
1414 while (token != NULL) {
1415 if (strlen(token) != 4) {
1416 SHOW_PROGRESS("Error: entry in product ID list has wrong length: %s. Ignoring\n", token);
1417 goto NextToken;
1419 if ( hexstr2bin(token, buffer, strlen(token)/2) == -1) {
1420 SHOW_PROGRESS("Error: entry in product ID list is not a hex string: %s. Ignoring\n", token);
1421 goto NextToken;
1423 product = 0;
1424 product += (unsigned char)buffer[0];
1425 product <<= 8;
1426 product += (unsigned char)buffer[1];
1427 if (product == idProduct) {
1428 if (verbose)
1429 printf (" found matching product ID from list\n");
1430 (*numFound)++;
1431 if (busnum == -1)
1432 right_dev = dev;
1433 else
1434 if (get_devnum(dev) >= devnum && get_busnum(dev) == busnum) {
1435 right_dev = dev;
1436 TargetProduct = idProduct;
1437 break;
1441 NextToken:
1442 token = strtok(NULL, ",");
1444 /* Product ID is given */
1445 } else
1446 if (product == idProduct) {
1447 if (verbose)
1448 printf (" found matching product ID\n");
1449 if (targetClass == 0 && configuration == 0) {
1450 (*numFound)++;
1451 right_dev = dev;
1452 if (verbose)
1453 printf (" adding device\n");
1454 } else {
1455 if (targetClass != 0) {
1456 #ifndef LIBUSB10
1457 devClass = dev->descriptor.bDeviceClass;
1458 int ifaceClass = dev->config[0].interface[0].altsetting[0].bInterfaceClass;
1459 #else
1460 struct libusb_device_descriptor descriptor;
1461 libusb_get_device_descriptor(dev, &descriptor);
1462 devClass = descriptor.bDeviceClass;
1463 struct libusb_config_descriptor *config;
1464 libusb_get_config_descriptor(dev, 0, &config);
1465 int ifaceClass = config->interface[0].altsetting[0].bInterfaceClass;
1466 libusb_free_config_descriptor(config);
1467 #endif
1468 if (devClass == 0)
1469 devClass = ifaceClass;
1470 else
1471 /* Check for some quirky devices */
1472 if (devClass != ifaceClass)
1473 devClass = ifaceClass;
1474 if (devClass == targetClass) {
1475 if (verbose)
1476 printf (" target class %02x matching\n", targetClass);
1477 if (mode == SEARCH_TARGET) {
1478 (*numFound)++;
1479 right_dev = dev;
1480 if (verbose)
1481 printf (" adding device\n");
1482 } else
1483 if (verbose)
1484 printf (" not adding device\n");
1485 } else {
1486 if (verbose)
1487 printf (" target class %02x not matching\n", targetClass);
1488 if (mode == SEARCH_DEFAULT) {
1489 (*numFound)++;
1490 right_dev = dev;
1491 if (verbose)
1492 printf (" adding device\n");
1495 } else {
1496 // check configuration (only if no target class given)
1497 testdevh = usb_open(dev);
1498 int testconfig = get_current_configuration(testdevh);
1499 if (testconfig != configuration) {
1500 if (verbose)
1501 printf (" device configuration %d not matching parameter\n", testconfig);
1502 (*numFound)++;
1503 right_dev = dev;
1504 if (verbose)
1505 printf (" adding device\n");
1506 } else
1507 if (verbose)
1508 printf (" not adding device, target configuration already set\n");
1511 /* hack: if busnum has other than init value, we are called from
1512 * successCheck() and do probe for plausible new devnum/busnum
1514 if (busnum != -1)
1515 if (get_devnum(dev) < devnum || get_busnum(dev) != busnum) {
1516 if (verbose)
1517 printf (" busnum/devnum indicates an unrelated device\n");
1518 right_dev = NULL;
1521 #ifndef LIBUSB10
1523 #endif
1525 if (productList != NULL)
1526 free(listcopy);
1527 return right_dev;
1531 #define USB_DIR_OUT 0x00
1532 #define USB_DIR_IN 0x80
1534 /* Autodetect bulk endpoints (ab) */
1536 int find_first_bulk_output_endpoint(struct usb_device *dev)
1538 int i;
1539 #ifndef LIBUSB10
1540 struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]);
1541 struct usb_endpoint_descriptor *ep;
1542 #else
1543 struct libusb_config_descriptor *config;
1544 libusb_get_config_descriptor(dev, 0, &config);
1545 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1546 const struct usb_endpoint_descriptor *ep;
1547 #endif
1549 for(i=0;i < alt->bNumEndpoints;i++) {
1550 ep=&(alt->endpoint[i]);
1551 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1552 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT ) ) {
1553 return ep->bEndpointAddress;
1556 #ifdef LIBUSB10
1557 libusb_free_config_descriptor(config);
1558 #endif
1560 return 0;
1564 int find_first_bulk_input_endpoint(struct usb_device *dev)
1566 int i;
1567 #ifndef LIBUSB10
1568 struct usb_interface_descriptor *alt = &(dev->config[0].interface[0].altsetting[0]);
1569 struct usb_endpoint_descriptor *ep;
1570 #else
1571 struct libusb_config_descriptor *config;
1572 libusb_get_config_descriptor(dev, 0, &config);
1573 const struct libusb_interface_descriptor *alt = &(config[0].interface[0].altsetting[0]);
1574 const struct usb_endpoint_descriptor *ep;
1575 #endif
1576 for(i=0;i < alt->bNumEndpoints;i++) {
1577 ep=&(alt->endpoint[i]);
1578 if( ( (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) &&
1579 ( (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) ) {
1580 return ep->bEndpointAddress;
1583 #ifdef LIBUSB10
1584 libusb_free_config_descriptor(config);
1585 #endif
1587 return 0;
1590 int get_current_configuration(struct usb_dev_handle* devh)
1592 int ret;
1594 SHOW_PROGRESS("Getting the current device configuration ...\n");
1595 ret = usb_control_msg(devh, USB_DIR_IN + USB_TYPE_STANDARD + USB_RECIP_DEVICE, USB_REQ_GET_CONFIGURATION, 0, 0, buffer, 1, 1000);
1596 if (ret < 0) {
1597 fprintf(stderr, "Error: getting the current configuration failed (error %d). Aborting.\n\n", ret);
1598 exit(1);
1599 } else {
1600 SHOW_PROGRESS(" OK, got current device configuration (%d)\n", buffer[0]);
1601 return buffer[0];
1606 #ifndef LIBUSB10
1607 int get_interface0_class(struct usb_device *dev, int devconfig)
1609 int i;
1610 for (i=0; i<dev->descriptor.bNumConfigurations; i++)
1611 if (dev->config[i].bConfigurationValue == devconfig)
1612 return dev->config[i].interface[0].altsetting[0].bInterfaceClass;
1613 return -1;
1615 #endif
1618 /* Parameter parsing */
1620 char* ReadParseParam(const char* FileName, char *VariableName)
1622 static char Str[LINE_DIM];
1623 char *VarName, *Comment=NULL, *Equal=NULL;
1624 char *FirstQuote, *LastQuote, *P1, *P2;
1625 int Line=0, Len=0, Pos=0;
1626 FILE *file=fopen(FileName, "r");
1628 if (file==NULL) {
1629 fprintf(stderr, "Error: Could not find file %s\n\n", FileName);
1630 exit(1);
1633 while (fgets(Str, LINE_DIM-1, file) != NULL) {
1634 Line++;
1635 Len=strlen(Str);
1636 if (Len==0) goto Next;
1637 if (Str[Len-1]=='\n' or Str[Len-1]=='\r') Str[--Len]='\0';
1638 Equal = strchr (Str, '='); // search for equal sign
1639 Pos = strcspn (Str, ";#!"); // search for comment
1640 Comment = (Pos==Len) ? NULL : Str+Pos;
1641 if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next; // Only comment
1642 *Equal++ = '\0';
1643 if (Comment!=NULL) *Comment='\0';
1645 // String
1646 FirstQuote=strchr (Equal, '"'); // search for double quote char
1647 LastQuote=strrchr (Equal, '"');
1648 if (FirstQuote!=NULL) {
1649 if (LastQuote==NULL) {
1650 fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote.\n", FileName, Line);
1651 goto Next;
1653 *FirstQuote=*LastQuote='\0';
1654 Equal=FirstQuote+1;
1657 // removes leading/trailing spaces
1658 Pos=strspn (Str, " \t");
1659 if (Pos==strlen(Str)) {
1660 fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name.\n", FileName, Line);
1661 goto Next; // No function name
1663 while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '\t'))!=NULL)
1664 if (P1!=NULL) *P1='\0';
1665 else if (P2!=NULL) *P2='\0';
1666 VarName=Str+Pos;
1668 Pos=strspn (Equal, " \t");
1669 if (Pos==strlen(Equal)) {
1670 fprintf(stderr, "Error reading parameter file %s line %d - Missing value.\n", FileName, Line);
1671 goto Next; // No function name
1673 Equal+=Pos;
1675 if (strcmp(VarName, VariableName)==0) { // Found it
1676 fclose(file);
1677 return Equal;
1679 Next:;
1682 fclose(file);
1683 return NULL;
1687 int hex2num(char c)
1689 if (c >= '0' && c <= '9')
1690 return c - '0';
1691 if (c >= 'a' && c <= 'f')
1692 return c - 'a' + 10;
1693 if (c >= 'A' && c <= 'F')
1694 return c - 'A' + 10;
1695 return -1;
1699 int hex2byte(const char *hex)
1701 int a, b;
1702 a = hex2num(*hex++);
1703 if (a < 0)
1704 return -1;
1705 b = hex2num(*hex++);
1706 if (b < 0)
1707 return -1;
1708 return (a << 4) | b;
1711 int hexstr2bin(const char *hex, char *buffer, int len)
1713 int i;
1714 int a;
1715 const char *ipos = hex;
1716 char *opos = buffer;
1718 for (i = 0; i < len; i++) {
1719 a = hex2byte(ipos);
1720 if (a < 0)
1721 return -1;
1722 *opos++ = a;
1723 ipos += 2;
1725 return 0;
1728 void printVersion()
1730 char* version = VERSION;
1731 printf("\n * usb_modeswitch: handle USB devices with multiple modes\n");
1732 printf(" * Version %s (C) Josua Dietze 2010\n", version);
1733 #ifndef LIBUSB10
1734 printf(" * Based on libusb0 (0.1.12 and above)\n\n");
1735 #else
1736 printf(" * Based on libusb10 (1.0.1 and above)\n\n");
1737 #endif
1738 printf(" ! PLEASE REPORT NEW CONFIGURATIONS !\n\n");
1741 void printHelp()
1743 printf ("Usage: usb_modeswitch [-hvpVPmMrdHn] [-c filename]\n\n");
1744 printf (" -h, --help this help\n");
1745 printf (" -e, --version print version information and exit\n");
1746 printf (" -v, --default-vendor NUM vendor ID of original mode (mandatory)\n");
1747 printf (" -p, --default-product NUM product ID of original mode (mandatory)\n");
1748 printf (" -V, --target-vendor NUM target mode vendor ID (optional)\n");
1749 printf (" -P, --target-product NUM target mode product ID (optional)\n");
1750 printf (" -C, --target-class NUM target mode device class (optional)\n");
1751 printf (" -m, --message-endpoint NUM direct the message transfer there (optional)\n");
1752 printf (" -M, --message-content <msg> message to send (hex number as string)\n");
1753 printf (" -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n");
1754 printf (" -n, --need-response read response to the message transfer (CSW)\n");
1755 printf (" -r, --response-endpoint NUM read response from there (optional)\n");
1756 printf (" -d, --detach-only detach the active driver, no further action\n");
1757 printf (" -H, --huawei-mode apply a special procedure\n");
1758 printf (" -S, --sierra-mode apply a special procedure\n");
1759 printf (" -O, --sony-mode apply a special procedure\n");
1760 printf (" -G, --gct-mode apply a special procedure\n");
1761 printf (" -T, --kobil-mode apply a special procedure\n");
1762 printf (" -R, --reset-usb reset the device after all other actions\n");
1763 printf (" -Q, --quiet don't show progress or error messages\n");
1764 printf (" -W, --verbose print all settings and debug output\n");
1765 printf (" -D, --sysmode specific result and syslog message\n");
1766 printf (" -s, --success NUM check switching result after NUM secs\n");
1767 printf (" -I, --no-inquire do not get SCSI attributes (default on)\n\n");
1768 printf (" -c, --config-file <filename> load configuration from file\n\n");
1769 printf (" -i, --interface NUM select initial USB interface (default 0)\n");
1770 printf (" -u, --configuration NUM select USB configuration\n");
1771 printf (" -a, --altsetting NUM select alternative USB interface setting\n\n");