2 Mode switching tool for controlling flip flop (multiple device) USB gear
3 Version 1.2.6, 2013/06/02
5 Copyright (C) 2007 - 2013 Josua Dietze (mail to "usb_admin" at the domain
6 of the home page; or write a personal message through the forum to "Josh".
7 NO SUPPORT VIA E-MAIL - please use the forum for that)
11 Command line parsing, decent usage/config output/handling, bugfixes and advanced
15 TargetClass parameter implementation to support new Option devices/firmware:
16 Paul Hardwick (http://www.pharscape.org)
18 Created with initial help from:
19 "usbsnoop2libusb.pl" by Timo Lindfors (http://iki.fi/lindi/usb/usbsnoop2libusb.pl)
21 Config file parsing stuff borrowed from:
22 Guillaume Dargaud (http://www.gdargaud.net/Hack/SourceCode.html)
24 Hexstr2bin function borrowed from:
25 Jouni Malinen (http://hostap.epitest.fi/wpa_supplicant, from "common.c")
27 Other contributions: see README
29 Device information contributors are named in the "device_reference.txt" file. See
32 This program is free software; you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation; either version 2 of the License, or
35 (at your option) any later version.
37 This program is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details:
42 http://www.gnu.org/licenses/gpl.txt
46 /* Recommended tab size: 4 */
48 #define VERSION "1.2.5"
59 #include "usb_modeswitch.h"
61 #define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
62 #define LIBUSB_HAS_GET_DRIVER_NP
64 #define USB_ENDPOINT_IN LIBUSB_ENDPOINT_IN
65 #define USB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT
66 #define USB_ENDPOINT_TYPE_MASK LIBUSB_ENDPOINT_ADDRESS_MASK
67 #define USB_ENDPOINT_DIR_MASK LIBUSB_ENDPOINT_DIR_MASK
68 #define USB_ENDPOINT_TYPE_BULK LIBUSB_TRANSFER_TYPE_BULK
69 #define USB_TYPE_STANDARD LIBUSB_REQUEST_TYPE_STANDARD
70 #define USB_TYPE_CLASS LIBUSB_REQUEST_TYPE_CLASS
71 #define USB_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR
72 #define USB_RECIP_DEVICE LIBUSB_RECIPIENT_DEVICE
73 #define USB_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE
74 #define USB_REQ_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
75 #define USB_REQ_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
77 #define usb_set_debug(x) libusb_set_debug(ctx, 3)
78 #define usb_close libusb_close
79 #define usb_get_string_simple libusb_get_string_descriptor_ascii
80 #define usb_reset libusb_reset_device
81 #define usb_claim_interface libusb_claim_interface
82 #define usb_clear_halt libusb_clear_halt
83 #define usb_release_interface libusb_release_interface
84 #define usb_control_msg libusb_control_transfer
85 #define usb_set_configuration libusb_set_configuration
86 #define usb_detach_kernel_driver_np libusb_detach_kernel_driver
88 /* libusb 1.0 wrappers */
89 int usb_bulk_io(struct libusb_device_handle
*handle
, int ep
, char *bytes
,
90 int size
, int timeout
)
94 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
95 r
= libusb_bulk_transfer(handle
, ep
& 0xff, bytes
, size
,
96 &actual_length
, timeout
);
98 /* if we timed out but did transfer some data, report as successful short
99 * read. FIXME: is this how libusb-0.1 works? */
100 if (r
== 0 || (r
== LIBUSB_ERROR_TIMEOUT
&& actual_length
> 0))
101 return actual_length
;
106 int usb_bulk_read(struct libusb_device_handle
*handle
, int ep
, char *bytes
,
107 int size
, int timeout
)
109 if (!(ep
& LIBUSB_ENDPOINT_IN
)) {
110 /* libusb-0.1 will strangely fix up a read request from endpoint
111 * 0x01 to be from endpoint 0x81. do the same thing here, but
112 * warn about this silly behaviour. */
113 printf("endpoint %x is missing IN direction bit, fixing", ep
);
114 ep
|= LIBUSB_ENDPOINT_IN
;
117 return usb_bulk_io(handle
, ep
, bytes
, size
, timeout
);
120 int usb_bulk_write(struct libusb_device_handle
*handle
, int ep
, char *bytes
,
121 int size
, int timeout
)
123 if (ep
& LIBUSB_ENDPOINT_IN
) {
124 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
125 * 0x81 to be to endpoint 0x01. do the same thing here, but
126 * warn about this silly behaviour. */
127 printf("endpoint %x has excessive IN direction bit, fixing", ep
);
128 ep
&= ~LIBUSB_ENDPOINT_IN
;
131 return usb_bulk_io(handle
, ep
, bytes
, size
, timeout
);
134 static int usb_interrupt_io(libusb_device_handle
*handle
, int ep
, char *bytes
,
135 int size
, int timeout
)
139 // usbi_dbg("endpoint %x size %d timeout %d", ep, size, timeout);
140 r
= libusb_interrupt_transfer(handle
, ep
& 0xff, bytes
, size
,
141 &actual_length
, timeout
);
143 /* if we timed out but did transfer some data, report as successful short
144 * read. FIXME: is this how libusb-0.1 works? */
145 if (r
== 0 || (r
== LIBUSB_ERROR_TIMEOUT
&& actual_length
> 0))
146 return actual_length
;
151 int usb_interrupt_read(libusb_device_handle
*handle
, int ep
, char *bytes
,
152 int size
, int timeout
)
154 if (!(ep
& USB_ENDPOINT_IN
)) {
155 /* libusb-0.1 will strangely fix up a read request from endpoint
156 * 0x01 to be from endpoint 0x81. do the same thing here, but
157 * warn about this silly behaviour. */
158 printf("endpoint %x is missing IN direction bit, fixing", ep
);
159 ep
|= USB_ENDPOINT_IN
;
161 return usb_interrupt_io(handle
, ep
, bytes
, size
, timeout
);
164 int usb_interrupt_write(libusb_device_handle
*handle
, int ep
, char *bytes
,
165 int size
, int timeout
)
167 if (ep
& USB_ENDPOINT_IN
) {
168 /* libusb-0.1 on BSD strangely fix up a write request to endpoint
169 * 0x81 to be to endpoint 0x01. do the same thing here, but
170 * warn about this silly behaviour. */
171 printf("endpoint %x has excessive IN direction bit, fixing", ep
);
172 ep
&= ~USB_ENDPOINT_IN
;
175 return usb_interrupt_io(handle
, ep
, bytes
, size
, timeout
);
178 int usb_get_driver_np(struct libusb_device_handle
*dev
, int interface
,
179 char *name
, unsigned int namelen
)
181 int r
= libusb_kernel_driver_active(dev
, interface
);
183 /* libusb-1.0 doesn't expose driver name, so fill in a dummy value */
184 snprintf(name
, namelen
, "dummy");
189 #define LINE_DIM 1024
191 #define BUF_SIZE 4096
192 #define DESCR_MAX 129
194 #define SEARCH_DEFAULT 0
195 #define SEARCH_TARGET 1
196 #define SEARCH_BUSDEV 2
198 #define SWITCH_CONFIG_MAXTRIES 5
200 #define SHOW_PROGRESS if (show_progress) fprintf
204 static struct libusb_context
*ctx
= NULL
;
205 static struct libusb_device
*dev
;
206 static struct libusb_device_handle
*devh
;
208 int DefaultVendor
=0, DefaultProduct
=0, TargetVendor
=0, TargetProduct
=-1, TargetClass
=0;
209 int MessageEndpoint
=0, ResponseEndpoint
=0, ReleaseDelay
=0;
210 int targetDeviceCount
=0, searchMode
;
211 int devnum
=-1, busnum
=-1;
214 char DetachStorageOnly
=0, HuaweiMode
=0, SierraMode
=0, SonyMode
=0, GCTMode
=0, KobilMode
=0;
215 char SequansMode
=0, MobileActionMode
=0, CiscoMode
=0, QisdaMode
=0, QuantaMode
=0;
216 char verbose
=0, show_progress
=1, ResetUSB
=0, CheckSuccess
=0, config_read
=0;
217 char NeedResponse
=0, NoDriverLoading
=0, InquireDevice
=1, sysmode
=0, mbim
=0;
219 char imanufact
[DESCR_MAX
], iproduct
[DESCR_MAX
], iserial
[DESCR_MAX
];
221 char MessageContent
[LINE_DIM
];
222 char MessageContent2
[LINE_DIM
];
223 char MessageContent3
[LINE_DIM
];
224 char TargetProductList
[LINE_DIM
];
225 char ByteString
[LINE_DIM
/2];
226 char buffer
[BUF_SIZE
];
231 /* Settable Interface and Configuration (for debugging mostly) (jmw) */
232 int Interface
= -1, Configuration
= 0, AltSetting
= -1;
235 static struct option long_options
[] = {
236 {"help", no_argument
, 0, 'h'},
237 {"version", no_argument
, 0, 'e'},
238 {"default-vendor", required_argument
, 0, 'v'},
239 {"default-product", required_argument
, 0, 'p'},
240 {"target-vendor", required_argument
, 0, 'V'},
241 {"target-product", required_argument
, 0, 'P'},
242 {"target-class", required_argument
, 0, 'C'},
243 {"message-endpoint", required_argument
, 0, 'm'},
244 {"message-content", required_argument
, 0, 'M'},
245 {"message-content2", required_argument
, 0, '2'},
246 {"message-content3", required_argument
, 0, '3'},
247 {"release-delay", required_argument
, 0, 'w'},
248 {"response-endpoint", required_argument
, 0, 'r'},
249 {"bus-num", required_argument
, 0, 'b'},
250 {"device-num", required_argument
, 0, 'g'},
251 {"detach-only", no_argument
, 0, 'd'},
252 {"huawei-mode", no_argument
, 0, 'H'},
253 {"sierra-mode", no_argument
, 0, 'S'},
254 {"sony-mode", no_argument
, 0, 'O'},
255 {"qisda-mode", no_argument
, 0, 'B'},
256 {"quanta-mode", no_argument
, 0, 'E'},
257 {"kobil-mode", no_argument
, 0, 'T'},
258 {"gct-mode", no_argument
, 0, 'G'},
259 {"sequans-mode", no_argument
, 0, 'N'},
260 {"mobileaction-mode", no_argument
, 0, 'A'},
261 {"cisco-mode", no_argument
, 0, 'L'},
262 {"need-response", no_argument
, 0, 'n'},
263 {"reset-usb", no_argument
, 0, 'R'},
264 {"config-file", required_argument
, 0, 'c'},
265 {"verbose", no_argument
, 0, 'W'},
266 {"quiet", no_argument
, 0, 'Q'},
267 {"sysmode", no_argument
, 0, 'D'},
268 {"no-inquire", no_argument
, 0, 'I'},
269 {"stdinput", no_argument
, 0, 't'},
270 {"find-mbim", no_argument
, 0, 'j'},
271 {"long-config", required_argument
, 0, 'f'},
272 {"check-success", required_argument
, 0, 's'},
273 {"interface", required_argument
, 0, 'i'},
274 {"configuration", required_argument
, 0, 'u'},
275 {"altsetting", required_argument
, 0, 'a'},
280 void readConfigFile(const char *configFilename
)
282 ParseParamHex(configFilename
, TargetVendor
);
283 ParseParamHex(configFilename
, TargetProduct
);
284 ParseParamString(configFilename
, TargetProductList
);
285 ParseParamHex(configFilename
, TargetClass
);
286 ParseParamHex(configFilename
, DefaultVendor
);
287 ParseParamHex(configFilename
, DefaultProduct
);
288 ParseParamBool(configFilename
, DetachStorageOnly
);
289 ParseParamBool(configFilename
, HuaweiMode
);
290 ParseParamBool(configFilename
, SierraMode
);
291 ParseParamBool(configFilename
, SonyMode
);
292 ParseParamBool(configFilename
, QisdaMode
);
293 ParseParamBool(configFilename
, QuantaMode
);
294 ParseParamBool(configFilename
, GCTMode
);
295 ParseParamBool(configFilename
, KobilMode
);
296 ParseParamBool(configFilename
, SequansMode
);
297 ParseParamBool(configFilename
, MobileActionMode
);
298 ParseParamBool(configFilename
, CiscoMode
);
299 ParseParamBool(configFilename
, NoDriverLoading
);
300 ParseParamHex(configFilename
, MessageEndpoint
);
301 ParseParamString(configFilename
, MessageContent
);
302 ParseParamString(configFilename
, MessageContent2
);
303 ParseParamString(configFilename
, MessageContent3
);
304 ParseParamInt(configFilename
, ReleaseDelay
);
305 ParseParamHex(configFilename
, NeedResponse
);
306 ParseParamHex(configFilename
, ResponseEndpoint
);
307 ParseParamHex(configFilename
, ResetUSB
);
308 ParseParamHex(configFilename
, InquireDevice
);
309 ParseParamInt(configFilename
, CheckSuccess
);
310 ParseParamHex(configFilename
, Interface
);
311 ParseParamHex(configFilename
, Configuration
);
312 ParseParamHex(configFilename
, AltSetting
);
314 /* TargetProductList has priority over TargetProduct */
315 if (TargetProduct
!= -1 && TargetProductList
[0] != '\0') {
317 SHOW_PROGRESS(output
,"Warning: TargetProductList overrides TargetProduct!\n");
327 printf ("DefaultVendor= 0x%04x\n", DefaultVendor
);
329 fprintf (output
,"DefaultVendor= not set\n");
330 if ( DefaultProduct
)
331 fprintf (output
,"DefaultProduct= 0x%04x\n", DefaultProduct
);
333 fprintf (output
,"DefaultProduct= not set\n");
335 fprintf (output
,"TargetVendor= 0x%04x\n", TargetVendor
);
337 fprintf (output
,"TargetVendor= not set\n");
338 if ( TargetProduct
> -1 )
339 fprintf (output
,"TargetProduct= 0x%04x\n", TargetProduct
);
341 fprintf (output
,"TargetProduct= not set\n");
343 fprintf (output
,"TargetClass= 0x%02x\n", TargetClass
);
345 fprintf (output
,"TargetClass= not set\n");
346 fprintf (output
,"TargetProductList=\"%s\"\n", TargetProductList
);
347 fprintf (output
,"\nDetachStorageOnly=%i\n", (int)DetachStorageOnly
);
348 fprintf (output
,"HuaweiMode=%i\n", (int)HuaweiMode
);
349 fprintf (output
,"SierraMode=%i\n", (int)SierraMode
);
350 fprintf (output
,"SonyMode=%i\n", (int)SonyMode
);
351 fprintf (output
,"QisdaMode=%i\n", (int)QisdaMode
);
352 fprintf (output
,"QuantaMode=%i\n", (int)QuantaMode
);
353 fprintf (output
,"GCTMode=%i\n", (int)GCTMode
);
354 fprintf (output
,"KobilMode=%i\n", (int)KobilMode
);
355 fprintf (output
,"SequansMode=%i\n", (int)SequansMode
);
356 fprintf (output
,"MobileActionMode=%i\n", (int)MobileActionMode
);
357 fprintf (output
,"CiscoMode=%i\n", (int)CiscoMode
);
358 if ( MessageEndpoint
)
359 fprintf (output
,"MessageEndpoint=0x%02x\n", MessageEndpoint
);
361 fprintf (output
,"MessageEndpoint= not set\n");
362 fprintf (output
,"MessageContent=\"%s\"\n", MessageContent
);
363 if ( strlen(MessageContent2
) )
364 fprintf (output
,"MessageContent2=\"%s\"\n", MessageContent2
);
365 if ( strlen(MessageContent3
) )
366 fprintf (output
,"MessageContent3=\"%s\"\n", MessageContent3
);
367 fprintf (output
,"NeedResponse=%i\n", (int)NeedResponse
);
368 if ( ResponseEndpoint
)
369 fprintf (output
,"ResponseEndpoint=0x%02x\n", ResponseEndpoint
);
371 fprintf (output
,"ResponseEndpoint= not set\n");
372 if ( Interface
> -1 )
373 fprintf (output
,"Interface=0x%02x\n", Interface
);
374 if ( Configuration
> 0 )
375 fprintf (output
,"Configuration=0x%02x\n", Configuration
);
376 if ( AltSetting
> -1 )
377 fprintf (output
,"AltSetting=0x%02x\n", AltSetting
);
379 fprintf (output
,"\nInquireDevice enabled (default)\n");
381 fprintf (output
,"\nInquireDevice disabled\n");
383 fprintf (output
,"Success check enabled, max. wait time %d seconds\n", CheckSuccess
);
385 fprintf (output
,"Success check disabled\n");
387 fprintf (output
,"System integration mode enabled\n");
389 fprintf (output
,"System integration mode disabled\n");
390 fprintf (output
,"\n");
394 int readArguments(int argc
, char **argv
)
396 int c
, option_index
= 0, count
=0;
397 char *longConfig
= NULL
;
407 c
= getopt_long (argc
, argv
, "hejWQDndHSOBEGTNALRItv:p:V:P:C:m:M:2:3:w:r:c:i:u:a:s:f:b:g:",
408 long_options
, &option_index
);
410 /* Detect the end of the options. */
416 case 'R': ResetUSB
= 1; break;
417 case 'v': DefaultVendor
= strtol(optarg
, NULL
, 16); break;
418 case 'p': DefaultProduct
= strtol(optarg
, NULL
, 16); break;
419 case 'V': TargetVendor
= strtol(optarg
, NULL
, 16); break;
420 case 'P': TargetProduct
= strtol(optarg
, NULL
, 16); break;
421 case 'C': TargetClass
= strtol(optarg
, NULL
, 16); break;
422 case 'm': MessageEndpoint
= strtol(optarg
, NULL
, 16); break;
423 case 'M': strncpy(MessageContent
, optarg
, LINE_DIM
); break;
424 case '2': strncpy(MessageContent2
, optarg
, LINE_DIM
); break;
425 case '3': strncpy(MessageContent3
, optarg
, LINE_DIM
); break;
426 case 'w': ReleaseDelay
= strtol(optarg
, NULL
, 10); break;
427 case 'n': NeedResponse
= 1; break;
428 case 'r': ResponseEndpoint
= strtol(optarg
, NULL
, 16); break;
429 case 'd': DetachStorageOnly
= 1; break;
430 case 'H': HuaweiMode
= 1; break;
431 case 'S': SierraMode
= 1; break;
432 case 'O': SonyMode
= 1; break;
433 case 'B': QisdaMode
= 1; break;
434 case 'E': QuantaMode
= 1; break;
435 case 'G': GCTMode
= 1; break;
436 case 'T': KobilMode
= 1; break;
437 case 'N': SequansMode
= 1; break;
438 case 'A': MobileActionMode
= 1; break;
439 case 'L': CiscoMode
= 1; break;
440 case 'c': readConfigFile(optarg
); break;
441 case 't': readConfigFile("stdin"); break;
442 case 'W': verbose
= 1; show_progress
= 1; count
--; break;
443 case 'Q': show_progress
= 0; verbose
= 0; count
--; break;
444 case 'D': sysmode
= 1; InquireDevice
= 0; count
--; break;
445 case 's': CheckSuccess
= strtol(optarg
, NULL
, 10); count
--; break;
446 case 'I': InquireDevice
= 0; break;
447 case 'b': busnum
= strtol(optarg
, NULL
, 10); break;
448 case 'g': devnum
= strtol(optarg
, NULL
, 10); break;
450 case 'i': Interface
= strtol(optarg
, NULL
, 16); break;
451 case 'u': Configuration
= strtol(optarg
, NULL
, 16); break;
452 case 'a': AltSetting
= strtol(optarg
, NULL
, 16); break;
453 case 'j': mbim
= 1; break;
456 longConfig
= malloc(strlen(optarg
)+5);
457 strcpy(longConfig
,"##\n");
458 strcat(longConfig
,optarg
);
459 strcat(longConfig
,"\n");
460 readConfigFile(longConfig
);
474 default: /* Unsupported - error message has already been printed */
475 fprintf (output
,"\n");
485 int main(int argc
, char **argv
)
487 int numDefaults
=0, specialMode
=0, sonySuccess
=0;
488 int currentConfig
=0, defaultClass
=0, interfaceClass
=0;
489 struct libusb_device_descriptor descriptor
;
490 struct libusb_config_descriptor
*config
;
493 /* Make sure we have empty strings even if not set by config */
494 TargetProductList
[0] = '\0';
495 MessageContent
[0] = '\0';
496 MessageContent2
[0] = '\0';
497 MessageContent3
[0] = '\0';
499 /* Useful for debugging during boot */
500 // output=fopen("/dev/console", "w");
503 signal(SIGTERM
, release_usb_device
);
506 * Parameter parsing, USB preparation/diagnosis, plausibility checks
509 /* Check command arguments, use params instead of config file when given */
510 switch (readArguments(argc
, argv
)) {
511 case 0: /* no argument or -W, -q or -s */
513 default: /* one or more arguments except -W, -q or -s */
514 if (!config_read
) /* if arguments contain -c, the config file was already processed */
515 if (verbose
) fprintf(output
,"Taking all parameters from the command line\n\n");
521 SHOW_PROGRESS(output
,"\n");
524 /* Some sanity checks. The default IDs are mandatory */
525 if (!(DefaultVendor
&& DefaultProduct
)) {
526 SHOW_PROGRESS(output
,"No default vendor/product ID given. Aborting.\n\n");
529 if (strlen(MessageContent
)) {
530 if (strlen(MessageContent
) % 2 != 0) {
531 fprintf(stderr
, "Error: MessageContent hex string has uneven length. Aborting.\n\n");
534 if ( hexstr2bin(MessageContent
, ByteString
, strlen(MessageContent
)/2) == -1) {
535 fprintf(stderr
, "Error: MessageContent %s\n is not a hex string. Aborting.\n\n", MessageContent
);
541 searchMode
= SEARCH_DEFAULT
;
543 SHOW_PROGRESS(output
,"Use given bus/device number: %03d/%03d ...\n", busnum
, devnum
);
544 searchMode
= SEARCH_BUSDEV
;
548 if (CheckSuccess
&& !(TargetVendor
|| TargetProduct
> -1 || TargetProductList
[0] != '\0') && !TargetClass
)
549 printf("Note: target parameter missing; success check limited\n");
551 /* libusb initialization */
558 printf("%d\n", findMBIMConfig(DefaultVendor
, DefaultProduct
, searchMode
) );
562 /* Count existing target devices, remember for success check */
563 if ((TargetVendor
|| TargetClass
) && searchMode
!= SEARCH_BUSDEV
) {
564 SHOW_PROGRESS(output
,"Looking for target devices ...\n");
565 search_devices(&targetDeviceCount
, TargetVendor
, TargetProduct
, TargetProductList
, TargetClass
, 0, SEARCH_TARGET
);
566 if (targetDeviceCount
) {
567 SHOW_PROGRESS(output
," Found devices in target mode or class (%d)\n", targetDeviceCount
);
569 SHOW_PROGRESS(output
," No devices in target mode or class found\n");
572 /* Count default devices, get the last one found */
573 SHOW_PROGRESS(output
,"Looking for default devices ...\n");
574 dev
= search_devices(&numDefaults
, DefaultVendor
, DefaultProduct
, "\0", TargetClass
, Configuration
, searchMode
);
576 SHOW_PROGRESS(output
," Found device in default mode, class or configuration (%d)\n", numDefaults
);
578 SHOW_PROGRESS(output
," No devices in default mode found. Nothing to do. Bye.\n\n");
582 SHOW_PROGRESS(output
," No bus/device match. Is device connected? Bye.\n\n");
586 devnum
= libusb_get_device_address(dev
);
587 busnum
= libusb_get_bus_number(dev
);
588 SHOW_PROGRESS(output
,"Accessing device %03d on bus %03d ...\n", devnum
, busnum
);
590 libusb_open(dev
, &devh
);
592 SHOW_PROGRESS(output
,"Error opening the device. Aborting.\n\n");
597 /* Get current configuration of default device
598 * A configuration value of -1 helps with quirky devices which have
599 * trouble determining the current configuration. We are just using the
600 * current config branch then.
601 * This affects only single-configuration devices so it's no problem.
602 * The dispatcher is using this always if no change of configuration
603 * is required for switching
605 if (Configuration
> -1)
606 currentConfig
= get_current_configuration(devh
);
608 SHOW_PROGRESS(output
,"Skipping the check for the current configuration\n");
612 libusb_get_device_descriptor(dev
, &descriptor
);
613 defaultClass
= descriptor
.bDeviceClass
;
614 libusb_get_config_descriptor(dev
, 0, &config
);
616 Interface
= config
->interface
[0].altsetting
[0].bInterfaceNumber
;
617 SHOW_PROGRESS(output
,"Using interface number %d\n", Interface
);
619 /* Get class of default device/interface */
620 interfaceClass
= get_interface_class(config
, Interface
);
621 libusb_free_config_descriptor(config
);
622 if (interfaceClass
== -1) {
623 fprintf(stderr
, "Error: getting the class of interface %d failed. Does it exist? Aborting.\n\n",Interface
);
627 if (defaultClass
== 0)
628 defaultClass
= interfaceClass
;
630 if (interfaceClass
== 8 && defaultClass
!= 8) {
631 /* Weird device with default class other than 0 and differing interface class */
632 SHOW_PROGRESS(output
,"Ambiguous Class/InterfaceClass: 0x%02x/0x08\n", defaultClass
);
636 if (strlen(MessageContent
) && strncmp("55534243",MessageContent
,8) == 0)
637 if (defaultClass
!= 8) {
638 fprintf(stderr
, "Error: can't use storage command in MessageContent with interface %d;\n"
639 " interface class is %d, should be 8. Aborting.\n\n", Interface
, defaultClass
);
643 /* Check or get endpoints */
644 if (strlen(MessageContent
) || InquireDevice
|| CiscoMode
) {
645 if (!MessageEndpoint
)
646 MessageEndpoint
= find_first_bulk_output_endpoint(dev
);
647 if (!MessageEndpoint
) {
648 fprintf(stderr
,"Error: message endpoint not given or found. Aborting.\n\n");
651 if (!ResponseEndpoint
)
652 ResponseEndpoint
= find_first_bulk_input_endpoint(dev
);
653 if (!ResponseEndpoint
) {
654 fprintf(stderr
,"Error: response endpoint not given or found. Aborting.\n\n");
657 SHOW_PROGRESS(output
,"Using endpoints 0x%02x (out) and 0x%02x (in)\n", MessageEndpoint
, ResponseEndpoint
);
660 if (!MessageEndpoint
|| !ResponseEndpoint
)
661 if (InquireDevice
&& defaultClass
== 0x08) {
662 SHOW_PROGRESS(output
,"Endpoints not found, skipping SCSI inquiry\n");
666 if (InquireDevice
&& show_progress
) {
667 if (defaultClass
== 0x08) {
668 SHOW_PROGRESS(output
,"Inquiring device details; driver will be detached ...\n");
670 if (deviceInquire() >= 0)
673 SHOW_PROGRESS(output
,"Not a storage device, skipping SCSI inquiry\n");
678 printf("\nUSB description data (for identification)\n");
679 printf("-------------------------\n");
680 printf("Manufacturer: %s\n", imanufact
);
681 printf(" Product: %s\n", iproduct
);
682 printf(" Serial No.: %s\n", iserial
);
683 printf("-------------------------\n");
686 /* Some scenarios are exclusive, so check for unwanted combinations */
687 specialMode
= DetachStorageOnly
+ HuaweiMode
+ SierraMode
+ SonyMode
+ QisdaMode
+ KobilMode
688 + SequansMode
+ MobileActionMode
+ CiscoMode
+ QuantaMode
;
689 if ( specialMode
> 1 ) {
690 SHOW_PROGRESS(output
,"Invalid mode combination. Check your configuration. Aborting.\n\n");
694 if ( !specialMode
&& !strlen(MessageContent
) && AltSetting
== -1 && Configuration
== 0 )
695 SHOW_PROGRESS(output
,"Warning: no switching method given.\n");
698 * The switching actions
702 openlog("usb_modeswitch", 0, LOG_SYSLOG
);
703 syslog(LOG_NOTICE
, "switching device %04x:%04x on %03d/%03d", DefaultVendor
, DefaultProduct
, busnum
, devnum
);
706 if (DetachStorageOnly
) {
707 SHOW_PROGRESS(output
,"Only detaching storage driver for switching ...\n");
708 if (InquireDevice
== 2) {
709 SHOW_PROGRESS(output
," Any driver was already detached for inquiry\n");
711 ret
= detachDriver();
713 SHOW_PROGRESS(output
," You may want to remove the storage driver manually\n");
740 if(MobileActionMode
) {
749 SHOW_PROGRESS(output
,"Note: ignoring CheckSuccess. Separate checks for Sony mode\n");
750 CheckSuccess
= 0; /* separate and implied success control */
751 sonySuccess
= switchSonyMode();
754 if (strlen(MessageContent
) && MessageEndpoint
) {
755 if (specialMode
== 0) {
756 if (InquireDevice
!= 2)
760 SHOW_PROGRESS(output
,"Warning: ignoring MessageContent. Can't combine with special mode\n");
763 if (Configuration
> 0) {
764 if (currentConfig
!= Configuration
) {
765 if (switchConfiguration()) {
766 currentConfig
= get_current_configuration(devh
);
767 if (currentConfig
== Configuration
) {
768 SHOW_PROGRESS(output
,"The configuration was set successfully\n");
770 SHOW_PROGRESS(output
,"Changing the configuration has failed\n");
774 SHOW_PROGRESS(output
,"Target configuration %d already active. Doing nothing\n", currentConfig
);
778 if (AltSetting
!= -1) {
782 /* No "removal" check if these are set */
783 if ((Configuration
> 0 || AltSetting
> -1) && !ResetUSB
) {
795 if (searchMode
== SEARCH_BUSDEV
&& sysmode
) {
796 SHOW_PROGRESS(output
,"Bus/dev search active, referring success check to wrapper. Bye.\n\n");
797 printf("ok:busdev\n");
800 if (checkSuccess()) {
805 if (TargetProduct
< 1)
806 printf("ok:no_data\n");
808 printf("ok:%04x:%04x\n", TargetVendor
, TargetProduct
);
817 syslog(LOG_NOTICE
, "switched S.E. MD400 to modem mode");
818 printf("ok:\n"); /* ACM device, no driver action */
820 SHOW_PROGRESS(output
,"-> device should be stable now. Bye.\n\n");
824 SHOW_PROGRESS(output
,"-> switching was probably not completed. Bye.\n\n");
827 SHOW_PROGRESS(output
,"-> Run lsusb to note any changes. Bye.\n\n");
838 /* Get descriptor strings if available (identification details) */
839 void deviceDescription ()
843 memset (imanufact
, ' ', DESCR_MAX
);
844 memset (iproduct
, ' ', DESCR_MAX
);
845 memset (iserial
, ' ', DESCR_MAX
);
847 struct libusb_device_descriptor descriptor
;
848 libusb_get_device_descriptor(dev
, &descriptor
);
850 int iManufacturer
= descriptor
.iManufacturer
;
851 int iProduct
= descriptor
.iProduct
;
852 int iSerialNumber
= descriptor
.iSerialNumber
;
855 ret
= usb_get_string_simple(devh
, iManufacturer
, imanufact
, DESCR_MAX
);
857 fprintf(stderr
, "Error: could not get description string \"manufacturer\"\n");
859 strcpy(imanufact
, "not provided");
860 c
= strstr(imanufact
, " ");
862 memset((void*)c
, '\0', 1);
865 ret
= usb_get_string_simple(devh
, iProduct
, iproduct
, DESCR_MAX
);
867 fprintf(stderr
, "Error: could not get description string \"product\"\n");
869 strcpy(iproduct
, "not provided");
870 c
= strstr(iproduct
, " ");
872 memset((void*)c
, '\0', 1);
875 ret
= usb_get_string_simple(devh
, iSerialNumber
, iserial
, DESCR_MAX
);
877 fprintf(stderr
, "Error: could not get description string \"serial number\"\n");
879 strcpy(iserial
, "not provided");
880 c
= strstr(iserial
, " ");
882 memset((void*)c
, '\0', 1);
886 /* Print result of SCSI command INQUIRY (identification details) */
889 const unsigned char inquire_msg
[] = {
890 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
891 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
892 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
899 command
= malloc(31);
900 if (command
== NULL
) {
905 memcpy(command
, inquire_msg
, sizeof (inquire_msg
));
907 ret
= usb_claim_interface(devh
, Interface
);
909 SHOW_PROGRESS(output
," Could not claim interface (error %d). Skipping device inquiry\n", ret
);
912 usb_clear_halt(devh
, MessageEndpoint
);
914 ret
= usb_bulk_write(devh
, MessageEndpoint
, (char *)command
, 31, 0);
916 SHOW_PROGRESS(output
," Could not send INQUIRY message (error %d)\n", ret
);
920 ret
= usb_bulk_read(devh
, ResponseEndpoint
, data
, 36, 0);
922 SHOW_PROGRESS(output
," Could not get INQUIRY response (error %d)\n", ret
);
926 i
= usb_bulk_read(devh
, ResponseEndpoint
, command
, 13, 0);
928 printf("\nSCSI inquiry data (for identification)\n");
929 printf("-------------------------\n");
931 printf(" Vendor String: ");
932 for (i
= 8; i
< 16; i
++) printf("%c",data
[i
]);
935 printf(" Model String: ");
936 for (i
= 16; i
< 32; i
++) printf("%c",data
[i
]);
939 printf("Revision String: ");
940 for (i
= 32; i
< 36; i
++) printf("%c",data
[i
]);
942 printf("\n-------------------------\n");
945 if (strlen(MessageContent
) == 0)
946 usb_clear_halt(devh
, MessageEndpoint
);
947 usb_release_interface(devh
, Interface
);
953 int findMBIMConfig(int vendor
, int product
, int mode
)
955 struct libusb_device
**devs
;
959 if (libusb_get_device_list(ctx
, &devs
) < 0) {
960 perror("failed to access USB");
964 SHOW_PROGRESS(output
,"Search USB devices...\n");
965 while ((dev
= devs
[i
++]) != NULL
) {
966 struct libusb_device_descriptor descriptor
;
967 libusb_get_device_descriptor(dev
, &descriptor
);
969 if (mode
== SEARCH_BUSDEV
) {
970 if ((libusb_get_bus_number(dev
) != busnum
) ||
971 (libusb_get_device_address(dev
) != devnum
)) {
975 // fprintf (output," searching devices, found USB ID %04x:%04x\n", descriptor.idVendor, descriptor.idProduct);
976 if (descriptor
.idVendor
!= vendor
)
978 if (product
!= descriptor
.idProduct
)
982 SHOW_PROGRESS(output
,"Found device, searching for MBIM configuration...\n");
984 // No check if there is only one configuration
985 if (descriptor
.bNumConfigurations
< 2)
988 // Checking all interfaces of all configurations
989 for (j
=0; j
<descriptor
.bNumConfigurations
; j
++) {
990 struct libusb_config_descriptor
*config
;
992 libusb_get_config_descriptor(dev
, j
, &config
);
993 resultConfig
= config
->bConfigurationValue
;
994 for (i
=0; i
<config
->bNumInterfaces
; i
++) {
995 // SHOW_PROGRESS(output,"MBIM Check: looking at ifc %d, class is %d, subclass is %d\n",
996 // i,config->interface[i].altsetting[0].bInterfaceClass,config->interface[i].altsetting[0].bInterfaceSubClass);
998 if ( config
->interface
[i
].altsetting
[0].bInterfaceClass
== 2 )
999 if ( config
->interface
[i
].altsetting
[0].bInterfaceSubClass
== 0x0e ) {
1000 // found MBIM interface in this configuration
1001 libusb_free_config_descriptor(config
);
1002 return resultConfig
;
1005 libusb_free_config_descriptor(config
);
1017 if (show_progress
) {
1018 printf("Resetting usb device ");
1024 success
= usb_reset(devh
);
1025 if ( ((bpoint
% 10) == 0) && show_progress
) {
1032 } while (success
< 0);
1035 SHOW_PROGRESS(output
,"\n Reset failed. Can be ignored if device switched OK.\n");
1037 SHOW_PROGRESS(output
,"\n OK, device was reset\n");
1041 int switchSendMessage ()
1043 const char* cmdHead
= "55534243";
1046 msg
[0] = MessageContent
;
1047 msg
[1] = MessageContent2
;
1048 msg
[2] = MessageContent3
;
1050 /* May be activated in future versions */
1051 // if (MessageContent2[0] != '\0' || MessageContent3[0] != '\0')
1052 // NeedResponse = 1;
1054 SHOW_PROGRESS(output
,"Setting up communication with interface %d\n", Interface
);
1055 if (InquireDevice
!= 2) {
1056 ret
= usb_claim_interface(devh
, Interface
);
1058 SHOW_PROGRESS(output
," Could not claim interface (error %d). Skipping message sending\n", ret
);
1062 usb_clear_halt(devh
, MessageEndpoint
);
1063 SHOW_PROGRESS(output
,"Using endpoint 0x%02x for message sending ...\n", MessageEndpoint
);
1067 for (i
=0; i
<3; i
++) {
1068 if ( strlen(msg
[i
]) == 0)
1071 if ( sendMessage(msg
[i
], i
+1) )
1075 if ( strstr(msg
[i
],cmdHead
) != NULL
) {
1077 SHOW_PROGRESS(output
,"Reading the response to message %d (CSW) ...\n", i
+1);
1078 ret
= read_bulk(ResponseEndpoint
, ByteString
, 13);
1080 // Other bulk transfer
1081 SHOW_PROGRESS(output
,"Reading the response to message %d ...\n", i
+1);
1082 ret
= read_bulk(ResponseEndpoint
, ByteString
, strlen(msg
[i
])/2 );
1089 SHOW_PROGRESS(output
,"Resetting response endpoint 0x%02x\n", ResponseEndpoint
);
1090 ret
= usb_clear_halt(devh
, ResponseEndpoint
);
1092 SHOW_PROGRESS(output
," Could not reset endpoint (probably harmless): %d\n", ret
);
1093 SHOW_PROGRESS(output
,"Resetting message endpoint 0x%02x\n", MessageEndpoint
);
1094 ret
= usb_clear_halt(devh
, MessageEndpoint
);
1096 SHOW_PROGRESS(output
," Could not reset endpoint (probably harmless): %d\n", ret
);
1100 SHOW_PROGRESS(output
,"Blocking the interface for %d ms before releasing ...\n", ReleaseDelay
);
1101 usleep(ReleaseDelay
*1000);
1103 ret
= usb_release_interface(devh
, Interface
);
1109 SHOW_PROGRESS(output
," Device is gone, skipping any further commands\n");
1115 int switchConfiguration ()
1117 int count
= SWITCH_CONFIG_MAXTRIES
;
1120 SHOW_PROGRESS(output
,"Changing configuration to %i ...\n", Configuration
);
1121 while (((ret
= usb_set_configuration(devh
, Configuration
)) < 0) && --count
) {
1122 SHOW_PROGRESS(output
," Device is busy, trying to detach kernel driver\n");
1126 SHOW_PROGRESS(output
," OK, configuration set\n");
1129 SHOW_PROGRESS(output
," Setting the configuration returned error %d. Trying to continue\n", ret
);
1134 int switchAltSetting ()
1138 SHOW_PROGRESS(output
,"Changing to alt setting %i ...\n", AltSetting
);
1139 ret
= usb_claim_interface(devh
, Interface
);
1140 ret
= libusb_set_interface_alt_setting(devh
, Interface
, AltSetting
);
1141 usb_release_interface(devh
, Interface
);
1143 SHOW_PROGRESS(output
," Changing to alt setting returned error %d. Trying to continue\n", ret
);
1146 SHOW_PROGRESS(output
," OK, changed to alt setting\n");
1152 void switchHuaweiMode ()
1156 SHOW_PROGRESS(output
,"Sending Huawei control message ...\n");
1157 ret
= usb_control_msg(devh
, USB_TYPE_STANDARD
| USB_RECIP_DEVICE
, USB_REQ_SET_FEATURE
, 00000001, 0, buffer
, 0, 1000);
1159 fprintf(stderr
, "Error: sending Huawei control message failed (error %d). Aborting.\n\n", ret
);
1162 SHOW_PROGRESS(output
," OK, Huawei control message sent\n");
1166 void switchSierraMode ()
1170 SHOW_PROGRESS(output
,"Trying to send Sierra control message\n");
1171 ret
= usb_control_msg(devh
, USB_TYPE_VENDOR
, 0x0b, 00000001, 0, buffer
, 0, 1000);
1172 if (ret
== LIBUSB_ERROR_PIPE
) {
1173 SHOW_PROGRESS(output
," communication with device stopped. May have switched, continue ...\n");
1177 fprintf(stderr
, "Error: sending Sierra control message failed (error %d). Aborting.\n\n", ret
);
1180 SHOW_PROGRESS(output
," OK, Sierra control message sent\n");
1184 void switchGCTMode ()
1188 ret
= usb_claim_interface(devh
, Interface
);
1190 SHOW_PROGRESS(output
," Could not claim interface (error %d). Skipping GCT sequence \n", ret
);
1194 SHOW_PROGRESS(output
,"Sending GCT control message 1 ...\n");
1195 ret
= usb_control_msg(devh
, 0xa1, 0xa0, 0, Interface
, buffer
, 1, 1000);
1196 SHOW_PROGRESS(output
,"Sending GCT control message 2 ...\n");
1197 ret
= usb_control_msg(devh
, 0xa1, 0xfe, 0, Interface
, buffer
, 1, 1000);
1198 SHOW_PROGRESS(output
," OK, GCT control messages sent\n");
1199 usb_release_interface(devh
, Interface
);
1203 int switchKobilMode() {
1206 SHOW_PROGRESS(output
,"Sending Kobil control message ...\n");
1207 ret
= usb_control_msg(devh
, USB_TYPE_VENDOR
| USB_RECIP_DEVICE
| USB_ENDPOINT_IN
, 0x88, 0, 0, buffer
, 8, 1000);
1209 fprintf(stderr
, "Error: sending Kobil control message failed (error %d). Aborting.\n\n", ret
);
1212 SHOW_PROGRESS(output
," OK, Kobil control message sent\n");
1216 void switchQuantaMode() {
1219 SHOW_PROGRESS(output
,"Sending Quanta control message ...\n");
1220 ret
= usb_control_msg(devh
, USB_TYPE_VENDOR
| USB_RECIP_DEVICE
| USB_ENDPOINT_IN
, 0xff, 0, 0, buffer
, 0, 1000);
1222 SHOW_PROGRESS(output
," Sending Quanta control message returned error %d, continue anyway ...\n", ret
);
1224 SHOW_PROGRESS(output
," OK, Quanta control message sent\n");
1228 int switchQisdaMode () {
1231 SHOW_PROGRESS(output
,"Sending Qisda control message ...\n");
1232 memcpy(buffer
, "\x05\x8c\x04\x08\xa0\xee\x20\x00\x5c\x01\x04\x08\x98\xcd\xea\xbf", 16);
1233 ret
= usb_control_msg(devh
, 0x40, 0x04, 00000000, 0, buffer
, 16, 1000);
1235 fprintf(stderr
, "Error: sending Qisda control message failed (error %d). Aborting.\n\n", ret
);
1238 SHOW_PROGRESS(output
," OK, Qisda control message sent\n");
1242 int switchSonyMode ()
1248 printf("Note: CheckSuccess pointless with Sony mode, disabling\n");
1252 SHOW_PROGRESS(output
,"Trying to send Sony control message\n");
1253 ret
= usb_control_msg(devh
, 0xc0, 0x11, 2, 0, buffer
, 3, 100);
1255 fprintf(stderr
, "Error: sending Sony control message failed (error %d). Aborting.\n\n", ret
);
1258 SHOW_PROGRESS(output
," OK, control message sent, waiting for device to return ...\n");
1263 /* Now waiting for the device to reappear */
1268 while ( dev
== 0 && i
< 30 ) {
1270 dev
= search_devices(&found
, DefaultVendor
, DefaultProduct
, "\0", TargetClass
, 0, SEARCH_TARGET
);
1275 if (show_progress
) {
1281 SHOW_PROGRESS(output
,"\n After %d seconds:",i
);
1283 SHOW_PROGRESS(output
," device came back, proceeding\n");
1284 libusb_open(dev
, &devh
);
1286 fprintf(stderr
, "Error: could not get handle on device\n");
1290 SHOW_PROGRESS(output
," device still gone, cancelling\n");
1295 SHOW_PROGRESS(output
,"Sending Sony control message again ...\n");
1296 ret
= usb_control_msg(devh
, 0xc0, 0x11, 2, 0, buffer
, 3, 100);
1298 fprintf(stderr
, "Error: sending Sony control message (2) failed (error %d)\n", ret
);
1301 SHOW_PROGRESS(output
," OK, control message sent\n");
1310 #define MOBILE_ACTION_READLOOP1 63
1311 #define MOBILE_ACTION_READLOOP2 73
1313 int switchActionMode ()
1316 SHOW_PROGRESS(output
,"Sending MobileAction control sequence ...\n");
1317 memcpy(buffer
, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE
);
1318 usb_control_msg(devh
, USB_TYPE_CLASS
+ USB_RECIP_INTERFACE
, 0x09, 0x0300, 0, buffer
, SIZE
, 1000);
1319 memcpy(buffer
, "\xb0\x04\x00\x00\x02\x90\x26\x86", SIZE
);
1320 usb_control_msg(devh
, USB_TYPE_CLASS
+ USB_RECIP_INTERFACE
, 0x09, 0x0300, 0, buffer
, SIZE
, 1000);
1321 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1322 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1323 memcpy(buffer
, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE
);
1324 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1325 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1326 memcpy(buffer
, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE
);
1327 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1328 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1329 memcpy(buffer
, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE
);
1330 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1331 for (i
=0; i
< MOBILE_ACTION_READLOOP1
; i
++) {
1332 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1334 memcpy(buffer
, "\x37\x01\xfe\xdb\xc1\x33\x1f\x83", SIZE
);
1335 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1336 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1337 memcpy(buffer
, "\x37\x0e\xb5\x9d\x3b\x8a\x91\x51", SIZE
);
1338 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1339 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1340 memcpy(buffer
, "\x34\x87\xba\x0d\xfc\x8a\x91\x51", SIZE
);
1341 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1342 for (i
=0; i
< MOBILE_ACTION_READLOOP2
; i
++) {
1343 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1345 memcpy(buffer
, "\x33\x04\xfe\x00\xf4\x6c\x1f\xf0", SIZE
);
1346 usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1347 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1348 memcpy(buffer
, "\x32\x07\xfe\xf0\x29\xb9\x3a\xf0", SIZE
);
1349 ret
= usb_interrupt_write(devh
, EP_OUT
, buffer
, SIZE
, 1000);
1350 usb_interrupt_read(devh
, EP_IN
, buffer
, SIZE
, 1000);
1352 SHOW_PROGRESS(output
," MobileAction control sequence did not complete\n Last error was %d\n",ret
);
1355 SHOW_PROGRESS(output
," MobileAction control sequence complete\n");
1361 #define SQN_SET_DEVICE_MODE_REQUEST 0x0b
1362 #define SQN_GET_DEVICE_MODE_REQUEST 0x0a
1364 #define SQN_DEFAULT_DEVICE_MODE 0x00
1365 #define SQN_MASS_STORAGE_MODE 0x01
1366 #define SQN_CUSTOM_DEVICE_MODE 0x02
1368 int switchSequansMode() {
1371 SHOW_PROGRESS(output
,"Sending Sequans vendor request\n");
1372 ret
= usb_control_msg(devh
, USB_TYPE_VENDOR
| USB_RECIP_DEVICE
, SQN_SET_DEVICE_MODE_REQUEST
, SQN_CUSTOM_DEVICE_MODE
, 0, buffer
, 0, 1000);
1374 fprintf(stderr
, "Error: sending Sequans request failed (error %d). Aborting.\n\n", ret
);
1377 SHOW_PROGRESS(output
," OK, Sequans request was sent\n");
1382 int switchCiscoMode() {
1386 SHOW_PROGRESS(output
,"Preparing for sending Cisco message sequence\n");
1388 msg
[0] = "55534243f83bcd810002000080000afd000000030000000100000000000000";
1389 msg
[1] = "55534243984300820002000080000afd000000070000000100000000000000";
1390 msg
[2] = "55534243984300820000000000000afd000100071000000000000000000000";
1391 msg
[3] = "55534243984300820002000080000afd000200230000000100000000000000";
1392 msg
[4] = "55534243984300820000000000000afd000300238200000000000000000000";
1393 msg
[5] = "55534243984300820002000080000afd000200260000000100000000000000";
1394 msg
[6] = "55534243984300820000000000000afd00030026c800000000000000000000";
1395 msg
[7] = "55534243d84c04820002000080000afd000010730000000100000000000000";
1396 msg
[8] = "55534243d84c04820002000080000afd000200240000000100000000000000";
1397 msg
[9] = "55534243d84c04820000000000000afd000300241300000000000000000000";
1398 msg
[10] = "55534243d84c04820000000000000afd000110732400000000000000000000";
1400 SHOW_PROGRESS(output
,"Setting up communication with interface %d\n", Interface
);
1401 ret
= usb_claim_interface(devh
, Interface
);
1403 SHOW_PROGRESS(output
," Could not claim interface (error %d). Skipping message sending\n", ret
);
1406 // usb_clear_halt(devh, MessageEndpoint);
1410 for (i
=0; i
<11; i
++) {
1411 if ( sendMessage(msg
[i
], i
+1) )
1414 SHOW_PROGRESS(output
,"Reading the response (CSW) to bulk message %d ...\n",i
+1);
1415 ret
= read_bulk(ResponseEndpoint
, ByteString
, 13);
1421 SHOW_PROGRESS(output
,"Blocking the interface for %d ms before releasing ...\n", ReleaseDelay
);
1422 usleep(ReleaseDelay
*1000);
1424 ret
= usb_release_interface(devh
, Interface
);
1430 SHOW_PROGRESS(output
,"Device returned error, skipping any further commands\n");
1442 #ifndef LIBUSB_HAS_GET_DRIVER_NP
1443 printf(" Cant't do driver detection and detaching on this platform.\n");
1447 SHOW_PROGRESS(output
,"Looking for active driver ...\n");
1448 ret
= usb_get_driver_np(devh
, Interface
, buffer
, BUF_SIZE
);
1450 SHOW_PROGRESS(output
," No driver found. Either detached before or never attached\n");
1453 if (strncmp("dummy",buffer
,5) == 0) {
1454 SHOW_PROGRESS(output
," OK, driver found; name unknown, limitation of libusb1\n");
1455 strcpy(buffer
,"unkown");
1457 SHOW_PROGRESS(output
," OK, driver found (\"%s\")\n", buffer
);
1461 #ifndef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
1462 SHOW_PROGRESS(output
," Can't do driver detaching on this platform\n");
1466 ret
= usb_detach_kernel_driver_np(devh
, Interface
);
1468 SHOW_PROGRESS(output
," OK, driver \"%s\" detached\n", buffer
);
1470 SHOW_PROGRESS(output
," Driver \"%s\" detach failed with error %d. Trying to continue\n", buffer
, ret
);
1476 int sendMessage(char* message
, int count
)
1478 int message_length
, ret
;
1480 if (strlen(message
) % 2 != 0) {
1481 fprintf(stderr
, "Error: MessageContent %d hex string has uneven length. Skipping ...\n", count
);
1484 message_length
= strlen(message
) / 2;
1485 if ( hexstr2bin(message
, ByteString
, message_length
) == -1) {
1486 fprintf(stderr
, "Error: MessageContent %d %s\n is not a hex string. Skipping ...\n", count
, MessageContent
);
1489 SHOW_PROGRESS(output
,"Trying to send message %d to endpoint 0x%02x ...\n", count
, MessageEndpoint
);
1491 ret
= write_bulk(MessageEndpoint
, ByteString
, message_length
);
1492 if (ret
== LIBUSB_ERROR_NO_DEVICE
)
1502 int newTargetCount
, success
=0;
1504 SHOW_PROGRESS(output
,"\nChecking for mode switch (max. %d times, once per second) ...\n", CheckSuccess
);
1507 /* If target parameters are given, don't check for vanished device
1508 * Changed for Cisco AM10 where a new device is added while the install
1509 * storage device stays active
1511 if ((TargetVendor
|| TargetClass
) && devh
) {
1516 /* if target ID is not given but target class is, assign default as target;
1517 * it will be needed for sysmode output
1519 if (!TargetVendor
&& TargetClass
) {
1520 TargetVendor
= DefaultVendor
;
1521 TargetProduct
= DefaultProduct
;
1524 /* devh is 0 if device vanished during command transmission or if target params were given
1527 for (i
=0; i
< CheckSuccess
; i
++) {
1529 /* Test if default device still can be accessed; positive result does
1530 * not necessarily mean failure
1532 SHOW_PROGRESS(output
," Waiting for original device to vanish ...\n");
1534 ret
= usb_claim_interface(devh
, Interface
);
1535 usb_release_interface(devh
, Interface
);
1537 SHOW_PROGRESS(output
," Original device can't be accessed anymore. Good.\n");
1542 if (i
== CheckSuccess
-1) {
1543 SHOW_PROGRESS(output
," Original device still present after the timeout\n\nMode switch most likely failed. Bye.\n\n");
1548 if ( TargetVendor
&& (TargetProduct
> -1 || TargetProductList
[0] != '\0') ) {
1550 /* Recount target devices (compare with previous count) if target data is given.
1551 * Target device on the same bus with higher device number is returned,
1552 * description is read for syslog message
1554 for (i
=i
; i
< CheckSuccess
; i
++) {
1555 SHOW_PROGRESS(output
," Searching for target devices ...\n");
1556 dev
= search_devices(&newTargetCount
, TargetVendor
, TargetProduct
, TargetProductList
, TargetClass
, 0, SEARCH_TARGET
);
1557 if (dev
&& (newTargetCount
> targetDeviceCount
)) {
1558 printf("\nFound target device, now opening\n");
1559 libusb_open(dev
, &devh
);
1560 deviceDescription();
1564 printf("\nFound target device %03d on bus %03d\n", \
1565 libusb_get_device_address(dev
), libusb_get_bus_number(dev
));
1566 printf("\nTarget device description data\n");
1567 printf("-------------------------\n");
1568 printf("Manufacturer: %s\n", imanufact
);
1569 printf(" Product: %s\n", iproduct
);
1570 printf(" Serial No.: %s\n", iserial
);
1571 printf("-------------------------\n");
1573 SHOW_PROGRESS(output
," Found correct target device\n\nMode switch succeeded. Bye.\n\n");
1577 if (i
== CheckSuccess
-1) {
1578 SHOW_PROGRESS(output
," No new devices in target mode or class found\n\nMode switch has failed. Bye.\n\n");
1583 /* No target data given, rely on the vanished device */
1585 SHOW_PROGRESS(output
," (For a better success check provide target IDs or class)\n");
1586 SHOW_PROGRESS(output
," Original device vanished after switching\n\nMode switch most likely succeeded. Bye.\n\n");
1593 syslog(LOG_NOTICE
, "switched to new device, but hit libusb1 bug");
1599 syslog(LOG_NOTICE
, "switched to %04x:%04x on %03d/%03d", TargetVendor
, TargetProduct
, busnum
, devnum
);
1604 syslog(LOG_NOTICE
, "device seems to have switched");
1616 int write_bulk(int endpoint
, char *message
, int length
)
1619 ret
= usb_bulk_write(devh
, endpoint
, message
, length
, 3000);
1621 SHOW_PROGRESS(output
," OK, message successfully sent\n");
1623 if (ret
== LIBUSB_ERROR_NO_DEVICE
) {
1624 SHOW_PROGRESS(output
," Device seems to have vanished right after sending. Good.\n");
1626 SHOW_PROGRESS(output
," Sending the message returned error %d. Trying to continue\n", ret
);
1631 int read_bulk(int endpoint
, char *buffer
, int length
)
1634 ret
= usb_bulk_read(devh
, endpoint
, buffer
, length
, 3000);
1635 usb_bulk_read(devh
, endpoint
, buffer
, 13, 100);
1637 SHOW_PROGRESS(output
," OK, response successfully read (%d bytes).\n", ret
);
1639 if (ret
== LIBUSB_ERROR_NO_DEVICE
) {
1640 SHOW_PROGRESS(output
," Device seems to have vanished after reading. Good.\n");
1642 SHOW_PROGRESS(output
," Response reading got error %d\n", ret
);
1647 void release_usb_device(int __attribute__((unused
)) dummy
) {
1648 SHOW_PROGRESS(output
,"Program cancelled by system. Bye.\n\n");
1650 usb_release_interface(devh
, Interface
);
1660 /* Iterates over busses and devices, counts the ones which match the given
1661 * parameters and returns the last one of them
1663 struct libusb_device
* search_devices( int *numFound
, int vendor
, int product
, char* productList
, int targetClass
, int configuration
, int mode
)
1665 char *listcopy
=NULL
, *token
, buffer
[2];
1667 struct libusb_device
* right_dev
= NULL
;
1668 struct libusb_device_handle
*testdevh
;
1669 struct libusb_device
**devs
;
1672 /* only target class given, target vendor and product assumed unchanged */
1673 if ( targetClass
&& !(vendor
|| product
) ) {
1674 vendor
= DefaultVendor
;
1675 product
= DefaultProduct
;
1680 if (!vendor
|| (!product
&& productList
== '\0') )
1683 if (productList
!= '\0')
1684 listcopy
= malloc(strlen(productList
)+1);
1686 if (libusb_get_device_list(ctx
, &devs
) < 0) {
1687 perror("failed to access USB");
1691 while ((dev
= devs
[i
++]) != NULL
) {
1692 struct libusb_device_descriptor descriptor
;
1693 libusb_get_device_descriptor(dev
, &descriptor
);
1694 int idVendor
= descriptor
.idVendor
;
1695 int idProduct
= descriptor
.idProduct
;
1697 if (mode
== SEARCH_BUSDEV
) {
1698 if ((libusb_get_bus_number(dev
) != busnum
) ||
1699 (libusb_get_device_address(dev
) != devnum
))
1702 SHOW_PROGRESS(output
," bus/device number matched\n");
1706 fprintf (output
," searching devices, found USB ID %04x:%04x\n",
1707 idVendor
, idProduct
);
1708 if (idVendor
!= vendor
)
1711 fprintf (output
," found matching vendor ID\n");
1712 // product list given
1713 if ( strlen(productList
) ) {
1714 strcpy(listcopy
, productList
);
1715 token
= strtok(listcopy
, ",");
1716 while (token
!= NULL
) {
1717 if (strlen(token
) != 4) {
1718 SHOW_PROGRESS(output
,"Error: entry in product ID list has wrong length: %s. Ignoring\n", token
);
1721 if ( hexstr2bin(token
, buffer
, strlen(token
)/2) == -1) {
1722 SHOW_PROGRESS(output
,"Error: entry in product ID list is not a hex string: %s. Ignoring\n", token
);
1726 product
+= (unsigned char)buffer
[0];
1728 product
+= (unsigned char)buffer
[1];
1729 if (product
== idProduct
) {
1731 fprintf (output
," found matching product ID from list\n");
1736 if (libusb_get_device_address(dev
) >= devnum
&& libusb_get_bus_number(dev
) == busnum
) {
1738 TargetProduct
= idProduct
;
1743 token
= strtok(NULL
, ",");
1745 /* Product ID is given */
1747 if (product
== idProduct
) {
1748 SHOW_PROGRESS(output
," found matching product ID\n");
1749 if (targetClass
== 0 && configuration
< 1) {
1751 SHOW_PROGRESS(output
," adding device\n");
1754 if (targetClass
!= 0) {
1755 struct libusb_device_descriptor descriptor
;
1756 libusb_get_device_descriptor(dev
, &descriptor
);
1757 devClass
= descriptor
.bDeviceClass
;
1758 struct libusb_config_descriptor
*config
;
1759 libusb_get_config_descriptor(dev
, 0, &config
);
1760 int ifaceClass
= config
->interface
[0].altsetting
[0].bInterfaceClass
;
1761 libusb_free_config_descriptor(config
);
1764 devClass
= ifaceClass
;
1766 /* Check for some quirky devices */
1767 if (devClass
!= ifaceClass
)
1768 devClass
= ifaceClass
;
1769 if (devClass
== targetClass
) {
1771 fprintf (output
," target class %02x matching\n", targetClass
);
1772 if (mode
== SEARCH_TARGET
) {
1776 fprintf (output
," adding device\n");
1779 fprintf (output
," not adding device\n");
1782 fprintf (output
," target class %02x not matching\n", targetClass
);
1783 if (mode
== SEARCH_DEFAULT
|| mode
== SEARCH_BUSDEV
) {
1787 fprintf (output
," adding device\n");
1791 // check configuration (only if no target class given)
1792 libusb_open(dev
, &testdevh
);
1793 int testconfig
= get_current_configuration(testdevh
);
1794 if (testconfig
!= configuration
) {
1796 fprintf (output
," device configuration %d not matching parameter\n", testconfig
);
1800 fprintf (output
," adding device\n");
1803 fprintf (output
," not adding device, target configuration already set\n");
1808 if (listcopy
!= NULL
)
1814 #define USB_DIR_OUT 0x00
1815 #define USB_DIR_IN 0x80
1817 /* Autodetect bulk endpoints (ab) */
1819 int find_first_bulk_output_endpoint(struct libusb_device
*dev
)
1822 struct libusb_config_descriptor
*config
;
1823 libusb_get_config_descriptor(dev
, 0, &config
);
1824 const struct libusb_interface_descriptor
*alt
= &(config
[0].interface
[0].altsetting
[0]);
1825 const struct libusb_endpoint_descriptor
*ep
;
1827 for(i
=0;i
< alt
->bNumEndpoints
;i
++) {
1828 ep
=&(alt
->endpoint
[i
]);
1829 if( ( (ep
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_BULK
) &&
1830 ( (ep
->bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) == USB_DIR_OUT
) ) {
1831 return ep
->bEndpointAddress
;
1834 libusb_free_config_descriptor(config
);
1840 int find_first_bulk_input_endpoint(struct libusb_device
*dev
)
1843 struct libusb_config_descriptor
*config
;
1844 libusb_get_config_descriptor(dev
, 0, &config
);
1845 const struct libusb_interface_descriptor
*alt
= &(config
[0].interface
[0].altsetting
[0]);
1846 const struct libusb_endpoint_descriptor
*ep
;
1847 for(i
=0;i
< alt
->bNumEndpoints
;i
++) {
1848 ep
=&(alt
->endpoint
[i
]);
1849 if( ( (ep
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_BULK
) &&
1850 ( (ep
->bEndpointAddress
& USB_ENDPOINT_DIR_MASK
) == USB_DIR_IN
) ) {
1851 return ep
->bEndpointAddress
;
1854 libusb_free_config_descriptor(config
);
1859 int get_current_configuration(struct libusb_device_handle
* devh
)
1863 SHOW_PROGRESS(output
,"Getting the current device configuration ...\n");
1864 ret
= usb_control_msg(devh
, USB_DIR_IN
+ USB_TYPE_STANDARD
+ USB_RECIP_DEVICE
, USB_REQ_GET_CONFIGURATION
, 0, 0, buffer
, 1, 1000);
1866 // There are quirky devices which fail to respond properly to this command
1867 fprintf(stderr
, "Error getting the current configuration (error %d). Assuming configuration 1.\n", ret
);
1868 if (Configuration
) {
1869 fprintf(stderr
, " No configuration setting possible for this device.\n");
1874 SHOW_PROGRESS(output
," OK, got current device configuration (%d)\n", buffer
[0]);
1879 int get_interface_class(struct libusb_config_descriptor
*cfg
, int ifcNumber
)
1883 for (i
=0; i
<cfg
->bNumInterfaces
; i
++) {
1884 // SHOW_PROGRESS(output,"Test: looking at ifc %d, class is %d\n",i,cfg->interface[i].altsetting[0].bInterfaceClass);
1885 if (cfg
->interface
[i
].altsetting
[0].bInterfaceNumber
== ifcNumber
)
1886 return cfg
->interface
[i
].altsetting
[0].bInterfaceClass
;
1892 /* Parameter parsing */
1894 char* ReadParseParam(const char* FileName
, char *VariableName
)
1896 static int numLines
= 0;
1897 static char* ConfigBuffer
[MAXLINES
];
1899 char *VarName
, *Comment
=NULL
, *Equal
=NULL
;
1900 char *FirstQuote
, *LastQuote
, *P1
, *P2
;
1902 unsigned Len
=0, Pos
=0;
1903 char Str
[LINE_DIM
], *token
, *configPos
;
1906 // Reading and storing input during the first call
1908 if (strncmp(FileName
,"##",2) == 0) {
1909 if (verbose
) fprintf(output
,"\nReading long config from command line\n");
1910 // "Embedded" configuration data
1911 configPos
= (char*)FileName
;
1912 token
= strtok(configPos
, "\n");
1913 strncpy(Str
,token
,LINE_DIM
-1);
1915 if (strcmp(FileName
, "stdin")==0) {
1916 if (verbose
) fprintf(output
,"\nReading long config from stdin\n");
1919 if (verbose
) fprintf(output
,"\nReading config file: %s\n", FileName
);
1920 file
=fopen(FileName
, "r");
1923 fprintf(stderr
, "Error: Could not find file %s\n\n", FileName
);
1926 token
= fgets(Str
, LINE_DIM
-1, file
);
1929 while (token
!= NULL
&& numLines
< MAXLINES
) {
1934 if (Str
[Len
-1]=='\n' or Str
[Len
-1]=='\r')
1936 Equal
= strchr (Str
, '='); // search for equal sign
1937 Pos
= strcspn (Str
, ";#!"); // search for comment
1938 Comment
= (Pos
==Len
) ? NULL
: Str
+Pos
;
1939 if (Equal
==NULL
or ( Comment
!=NULL
and Comment
<=Equal
))
1940 goto NextLine
; // Comment or irrelevant, don't save
1942 ConfigBuffer
[numLines
] = malloc(Len
*sizeof(char));
1943 strcpy(ConfigBuffer
[numLines
],Str
);
1947 token
= strtok(NULL
, "\n");
1949 strncpy(Str
,token
,LINE_DIM
-1);
1951 token
= fgets(Str
, LINE_DIM
-1, file
);
1957 // Now checking for parameters
1959 while (Line
< numLines
) {
1960 strcpy(Str
,ConfigBuffer
[Line
]);
1961 Equal
= strchr (Str
, '='); // search for equal sign
1965 FirstQuote
=strchr (Equal
, '"'); // search for double quote char
1966 LastQuote
=strrchr (Equal
, '"');
1967 if (FirstQuote
!=NULL
) {
1968 if (LastQuote
==NULL
) {
1969 fprintf(stderr
, "Error reading parameters from file %s - Missing end quote:\n%s\n", FileName
, Str
);
1972 *FirstQuote
=*LastQuote
='\0';
1976 // removes leading/trailing spaces
1977 Pos
=strspn (Str
, " \t");
1978 if (Pos
==strlen(Str
)) {
1979 fprintf(stderr
, "Error reading parameters from file %s - Missing variable name:\n%s\n", FileName
, Str
);
1980 goto Next
; // No function name
1982 while ((P1
=strrchr(Str
, ' '))!=NULL
or (P2
=strrchr(Str
, '\t'))!=NULL
)
1983 if (P1
!=NULL
) *P1
='\0';
1984 else if (P2
!=NULL
) *P2
='\0';
1987 Pos
=strspn (Equal
, " \t");
1988 if (Pos
==strlen(Equal
)) {
1989 fprintf(stderr
, "Error reading parameter from file %s - Missing value:\n%s\n", FileName
, Str
);
1990 goto Next
; // No function name
1994 if (strcmp(VarName
, VariableName
)==0) { // Found it
2007 if (c
>= '0' && c
<= '9')
2009 if (c
>= 'a' && c
<= 'f')
2010 return c
- 'a' + 10;
2011 if (c
>= 'A' && c
<= 'F')
2012 return c
- 'A' + 10;
2017 int hex2byte(const char *hex
)
2020 a
= hex2num(*hex
++);
2023 b
= hex2num(*hex
++);
2026 return (a
<< 4) | b
;
2029 int hexstr2bin(const char *hex
, char *buffer
, int len
)
2033 const char *ipos
= hex
;
2034 char *opos
= buffer
;
2036 for (i
= 0; i
< len
; i
++) {
2048 char* version
= VERSION
;
2049 printf("\n * usb_modeswitch: handle USB devices with multiple modes\n"
2050 " * Version %s (C) Josua Dietze 2012\n"
2051 " * Based on libusb0 (0.1.12 and above)\n\n"
2052 " ! PLEASE REPORT NEW CONFIGURATIONS !\n\n", version
);
2057 fprintf (output
,"\nUsage: usb_modeswitch [<params>] [-c filename]\n\n"
2058 " -h, --help this help\n"
2059 " -e, --version print version information and exit\n"
2060 " -j, --find-mbim return config no. with MBIM interface, exit\n"
2061 " -v, --default-vendor NUM vendor ID of original mode (mandatory)\n"
2062 " -p, --default-product NUM product ID of original mode (mandatory)\n"
2063 " -V, --target-vendor NUM target mode vendor ID (optional)\n"
2064 " -P, --target-product NUM target mode product ID (optional)\n"
2065 " -C, --target-class NUM target mode device class (optional)\n"
2066 " -b, --busnum NUM system bus number of device (for hard ID)\n"
2067 " -g, --devnum NUM system device number (for hard ID)\n"
2068 " -m, --message-endpoint NUM direct the message transfer there (optional)\n"
2069 " -M, --message-content <msg> message to send (hex number as string)\n"
2070 " -2 <msg>, -3 <msg> additional messages to send (-n recommended)\n"
2071 " -n, --need-response read response to the message transfer (CSW)\n"
2072 " -r, --response-endpoint NUM read response from there (optional)\n"
2073 " -d, --detach-only detach the active driver, no further action\n"
2074 " -H, --huawei-mode apply a special procedure\n"
2075 " -S, --sierra-mode apply a special procedure\n"
2076 " -O, --sony-mode apply a special procedure\n"
2077 " -G, --gct-mode apply a special procedure\n"
2078 " -N, --sequans-mode apply a special procedure\n"
2079 " -A, --mobileaction-mode apply a special procedure\n"
2080 " -T, --kobil-mode apply a special procedure\n"
2081 " -L, --cisco-mode apply a special procedure\n"
2082 " -B, --qisda-mode apply a special procedure\n"
2083 " -E, --quanta-mode apply a special procedure\n"
2084 " -R, --reset-usb reset the device after all other actions\n"
2085 " -Q, --quiet don't show progress or error messages\n"
2086 " -W, --verbose print all settings and debug output\n"
2087 " -D, --sysmode specific result and syslog message\n"
2088 " -s, --success <seconds> switching result check with timeout\n"
2089 " -I, --no-inquire do not get SCSI attributes (default on)\n\n"
2090 " -c, --config-file <filename> load long configuration from file\n\n"
2091 " -t, --stdinput read long configuration from stdin\n\n"
2092 " -f, --long-config <text> get long configuration from string\n\n"
2093 " -i, --interface NUM select initial USB interface (default 0)\n"
2094 " -u, --configuration NUM select USB configuration\n"
2095 " -a, --altsetting NUM select alternative USB interface setting\n\n");