一. 为什么要对USB 3G上网卡做模式切换?
从使用过的华为和ZTE的上网卡来看,它们都使用了Zero-CD。例如:在Windows PC上第一次插入上网卡,只有一个用于Mass Storage的Interface,在用户看来也就是显示出来一个U盘或光驱,里面存储的是驱动程序。安装驱动程序,在驱动正常工作后,其余几个Interface就显现出来,于是你看到了Modem,你运行相关的软件就可以拨号上网了。
二. Linux下的模式切换有如下方式。
1. 在用户空间使用 usb-modeswitch 来切换。
工具下载地址:http://www.draisberghof.de/usb_modeswitch
2. 修改内核代码加入对USB 3G上网卡的支持。
linux内核: 2.6.30.9
2.1. 在 unusual_devs.h 中加入如下内容
/* added to support HuaWei dongle
* K3765 ---> 0x1520
* K3520 ---> 0x1001
* K4505 ---> 0x1521
* E1756 ---> 0x1446
*/
UNUSUAL_DEV( 0x12d1, 0x1520, 0x0000, 0x0000,
"HUAWEI",
"HSPA K3765",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_scsi_init,
0),
UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000,
"HUAWEI",
"HSPA K3520",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_scsi_init,
0),
UNUSUAL_DEV( 0x12d1, 0x1C24, 0x0000, 0xffff,
"HUAWEI",
"HSPA E173",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_scsi_init,
0),
UNUSUAL_DEV( 0x12d1, 0x1521, 0x0000, 0x0000,
"HUAWEI",
"HSPA K4505",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_scsi_init,
0),
UNUSUAL_DEV( 0x12d1, 0x1446, 0x0000, 0x0000,
"HUAWEI",
"HSPA E1756",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_scsi_init,
0),
2.2. 在initialize.c 中实现函数 usb_stor_huawei_scsi_init
/* added to support HuaWei dongles. */
int usb_stor_huawei_scsi_init(struct us_data *us)
{
int result = 0;
int act_len = 0;
unsigned char cmd[32] = { 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00 };
result = usb_stor_bulk_transfer_buf (us, us->send_bulk_pipe, cmd, 31, &act_len);
US_DEBUGP("usb_stor_bulk_transfer_buf performing result is %d, transfer the actual length=%d\n", result, act_len);
return result;
}
在上述2个文件中加入所示代码后,重编内核,即可完成对相应3G上网卡的切换。
在 storage/usual-tables.c 中有如下定义:
struct usb_device_id usb_storage_usb_ids[] = {
# include "unusual_devs.h"
{ } /* Terminating entry */
};
EXPORT_SYMBOL_GPL(usb_storage_usb_ids);
在storage/usb.c 中也有一个类似的定义:
static struct us_unusual_dev us_unusual_dev_list[] = {
# include "unusual_devs.h"
{ } /* Terminating entry */
};
很显然这应该定义的是2个不同数据类型的数组,但是数组的每一个元素对应到unusual_devs.h中,则是相同的。
即数组中相同index指向了unusual_devs.h 中的同一个东西,但是却各自表述。(很有点92共识的味道。)
当USB 3G上网卡插入的时候,在usb.c 中的函数 storage_probe(struct usb_interface *intf, const struct usb_device_id *id)
会被调用。注意该函数的参数 id, 根据上面的分析,可以很容易的根据这个usb_device_id 找到对应的us_unusual_dev,
(id - usb_storage_usb_ids) + us_unusual_dev_list, 相关代码如下:
/*
* Call the general probe procedures.
*
* The unusual_dev_list array is parallel to the usb_storage_usb_ids
* table, so we use the index of the id entry to find the
* corresponding unusual_devs entry.
*/
result = usb_stor_probe1(&us, intf, id,
(id - usb_storage_usb_ids) + us_unusual_dev_list);