usb modeswitch
是一种模式切换工具,用于控制具有 多种模式
的 USB 设备。
I
无线网卡首次插入电脑时,它们会被识别为一个闪存设备,然后开始安装存储于其中的驱动程序。在安装完驱动程序之后就会在内部切换 USB 设备的连接模式,存储设备会消失,然后会出现一个新的设备。
目前许多这种设备都可以在 Linux 的驱动下工作,如 usb-storage
(存储设备的驱动模块)和 options
(高速 Modem 的驱动模块),接下来的事情就是如何从存储设备到 Modem 的切换。
依赖于 libusb
库, usb modeswitch
可以从一个配置文件中获取重要的参数,然后完成全部的初始化和通信工作,这样便使得用户可以轻松地处理这个过程。
源码与安装
- usb modeswitch 2.5.2
- usb modeswitch.d 包含设备数据库和规则文件
- device_reference.txt 设备的配置集合
- libusb 1.0.22
标准自动化用法
通过 udev 事件和规则,标准自动化用法详见 usb_modeswitch 使用详解
内核相关问题
另一种能够影响内核行为的方法是“usb-storage”的“delay_use”参数,这个参数会设置存储设备插入系统到实际使用(可能会自动挂载)之间的延迟时间,以秒为单位。默认值为 5,这个参数可能会影响某些条件下的切换结果
嵌入式移植
- 建立
usb-storage
-options
对应表,具体对应关系从usb modeswitch.d
中获得,例如文件0421:062c
# Nokia CS-19
TargetVendor=0x0421
TargetProductList="062d,062f"
StandardEject=1
获得对应关系 0421:062c
- 0421:062d 0421:062f
- 切换设备
usb_modeswitch -c /etc/usb_modeswitch.d/0421:062c -v 0x0421 -p 0x062c &
此时能从终端看到设备 拔出
和 插入
的信息,示例如下:
[10559.330000] usb 1-1: new high speed USB device using EHCI-NationalChip and address 6
[10559.500000] usb 1-1: configuration #1 chosen from 1 choice
[10559.510000] scsi11 : SCSI emulation for USB Mass Storage devices
[10559.580000] scsi12 : SCSI emulation for USB Mass Storage devices
[Hotplug] dev: 1-1
[Hotplug] action: add
[Hotplug] dev: 1-1:1.0
[Hotplug] action: add
[Hotplug]: usb id stack
1-1+12d1:1446
[Hotplug] dev: 1-1:1.1
[Hotplug] action: add
Look for target devices ...
No devices in target mode or class found
Look for default devices ...
Found devices in default mode (1)
Access device 006 on bus 001
Get the current device configuration ...
Current configuration number is 1
Use interface number 0
with class 8
Use endpoints 0x01 (out) and 0x81 (in)
Using standard Huawei switching message
Looking for active drivers ...
OK, driver detached
OK, driver detached
Set up int[10560.320000] usb 1-1: USB disconnect, address 6
erface 0
Use endpoint 0x01 for message sending ...
Trying to send message 1 to endpoint 0x01 ...
Device seems to have vanished right after sending. Good.
Device is gone, skip any further commands
-> Run lsusb to note any changes. Bye!
[Hotplug] dev: 1-1:1.0
[Hotplug] action: remove
[Hotplug] dev: 1-1:1.1
[Hotplug] action: remove
[Hotplug] dev: 1-1
[Hotplug] action: remove
[Hotplug]: usb id stack
[10564.390000] usb 1-1: new high speed USB device using EHCI-NationalChip and address 7
[10564.550000] usb 1-1: configuration #1 chosen from 1 choice
[10564.580000] usb-storage: probe of 1-1:1.0 failed with error -5
[10564.590000] option 1-1:1.0: GSM modem (1-port) converter detected
[10564.630000] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB0
[Hotplug] dev: 1-1
[Hotplug] action: add
[10564.710000] usb-storage: probe of 1-1:1.1 failed with error -5
[10564.860000] usb-storage: probe of 1-1:1.2 failed with error -5
[10564.960000] usb-storage: probe of 1-1:1.3 failed with error -5
[10564.970000] option 1-1:1.3: GSM modem (1-port) converter detected
[10565.040000] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB1
[10565.080000] usb-storage: probe of 1-1:1.4 failed with error -5
[10565.090000] option 1-1:1.4: GSM modem (1-port) converter detected
[Hotplug]: usb id stack
1-1+12d1:1436
[10565.250000] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB2
[Hotplug] dev: 1-1:1.0
[Hotplug] action: add
[Hotplug] dev: 1-1:1.2
[Hotplug] action: add
[Hotplug] dev: 1-1:1.1
[Hotplug] action: add
[Hotplug] dev: 1-1:1.3
[Hotplug] action: add
[Hotplug] dev: 1-1:1.5
[Hotplug] action: add
[Hotplug] dev: 1-1:1.4
[Hotplug] action: add
>>>>>>>>>>>>>>>>>> 3G Start!
TIMEOUT 5
ABORT 'NO CARRIER'
ABORT 'ERROR'
ABORT 'NO DIALTONE'
ABORT 'BUSY'
ABORT 'NO ANSWER'
'' /rAT
OK /rATZ
OK /rAT+CGDCONT=1,"IP","3gnet",,0,0
OK-AT-OK ATDT*99#
CONNECT /d/c
[10575.350000] scsi18 : SCSI emulation for USB Mass Storage devices
[Hotplug] dev: 1-1:1.6
[Hotplug] action: add
[10585.390000] scsi19 : SCSI emulation for USB Mass Storage devices
[10585.400000] scsi 18:0:0:0: CD-ROM HUAWEI Mass Storage 2.31 PQ: 0 ANSI: 2
timeout set to 5 seconds
abort on (NO CARRIER)
abort on (ERROR)
abort on (NO DIALTONE)
abort on (BUSY)
abort on (NO ANSWER)
send (/rAT^M)
[10585.460000] scsi 18:0:0:0: Attached scsi generic sg0 type 5
expect (OK)
AT^M^M
OK
-- got it
上述打印可以看出基本流程
- 插入设备,识别为
usb-storage
- 检测到对应关系,启动
usb modeswitch
usb-storage
弹出option
设备3G
连接流程启动
代码分析
usb modeswitch v2.5.2
为例
/* Detach driver
*/
int detachDriver()
{
int ret;
SHOW_PROGRESS(output,"Looking for active driver ...\n");
ret = libusb_kernel_driver_active(devh, 0);
if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
fprintf(output," Can't do driver detection on this platform.\n");
return 2;
}
if (ret < 0) {
fprintf(output," Driver check failed with error %d. Try to continue\n", ret);
return 2;
}
if (ret == 0) {
SHOW_PROGRESS(output," No active driver found. Detached before or never attached\n");
return 1;
}
ret = libusb_detach_kernel_driver(devh, Interface);
if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
fprintf(output," Can't do driver detaching on this platform.\n");
return 2;
}
if (ret == 0) {
SHOW_PROGRESS(output," OK, driver detached\n");
} else
SHOW_PROGRESS(output," Driver detach failed (error %d). Try to continue\n", ret);
return 1;
}
int main(int argc, char **argv)
{
...
/* libusb initialization */
if ((libusbError = libusb_init(&ctx)) != LIBUSB_SUCCESS) {
fprintf(stderr, "Error: Failed to initialize libusb. %s (%d)\n\n",
libusb_error_name(libusbError), libusbError);
exit(1);
}
...
if (dev == NULL) {
SHOW_PROGRESS(output," No bus/device match. Is device connected? Abort\n\n");
close_all();
exit(0);
} else {
if (devnum == -1) {
devnum = libusb_get_device_address(dev);
busnum = libusb_get_bus_number(dev);
SHOW_PROGRESS(output,"Access device %03d on bus %03d\n", devnum, busnum);
}
libusb_open(dev, &devh);
if (devh == NULL) {
SHOW_PROGRESS(output,"Error opening the device. Abort\n\n");
abortExit();
}
}
...
} else if (ModeMap & HUAWEINEW_MODE) {
SHOW_PROGRESS(output,"Using standard Huawei switching message\n");
detachDriver();
strcpy(Messages[0],"55534243123456780000000000000011062000000101000100000000000000");
switchSendMessage();
}
...
/* No "removal" check if these are set */
if ((Configuration > 0 || AltSetting > -1) && !ResetUSB) {
libusb_close(devh);
devh = NULL;
}
if (ResetUSB) {
resetUSB();
devh = NULL;
}
...
}