为什么要切换模式:
3G上网卡自带程序,接到PC后先作为移动硬盘使用,安装程序后切换为modem
如何自动切换模式
1. 编写控制程序自动使用各种型号3G上网卡
a. usb_modeswitch -c /etc/... // 1. 对于不同的3G上网卡配置信息不一样
b. insmod ... //装载驱动程序
c. pppd call wcdma-dailer 联通 // 2. 对于不同的3G上网卡使用不的/dev/ttyUSB,
pppd call evdo-dailer 电信 //对应不同的运营商调用不同的脚本文件
pppd call td-dailer 移动 //从而确定使用哪一个usb串口拨号
写一个控制程序:(功能描述)
a. 接上3G上网卡后它会调用usb_modeswitch并提供对应的配置信息
b. 当识别出/dev/ttyUSB...后, 它创建一个链接文件/dev/gsmmodem指向拨号时要用的/dev/ttyUSB
参考PC上对3G上网卡的识别过程:
在PC上编译、安装: libusb-1.0.9.tar.bz2, usb-modeswitch-2.0.1.tar.bz2, usb-modeswitch-data-20131113.tar.bz2,ppp-2.4.5.tar.gz
直接在PC上编译安装,./configure后面不需指定运行环境和安装目录
重启电脑
接上USB 3G上网卡(下面点击connect)
查看切换情况,gsmmodem指向了最终要使用的串口,以后修改配置文件,只需使用/dev/gsmmodem
分析PC操作过程:(使用的是udev)
a. 从/lib/udev/rules.d/40-usb_modeswitch.rules可知
接上3G上网卡后将执行: usb_modeswitch '%b/%k'
执行的是:/lib/udev/usb_modeswitch
它又会调用/usr/sbin/usb_modeswitch_dispatcher
b. /usr/sbin/usb_modeswitch_dispatcher会调用usb_modeswitch进行模式切换
它调用:/usr/sbin/usb_modeswitch -W -D -s 20 $configParam $busParam $devParam -v $usb(idVendor) -p $usb(idProduct)-f "$configBuffer"
它并不使用配置文件,而是使用-f参数, 这些参数来自/usr/share/usb_modeswitch
在/usr/share/usb_modeswitch里有众多文件,已"vid:pid"为名
/usr/sbin/usb_modeswitch_dispatcher根据3G上网卡的vid,pid找到/usr/share/usb_modeswitch里的文件,
然后执行:usb_modeswitch -V vid -P pid -f "文件里的内容"
c. 怎么创建接文件/dev/gsmmodem:(确定指向哪一个串口)
# The facility to add a symbolic link pointing to the
# ttyUSB port which provides interrupt transfer, i.e.
# the port to connect through.
# Will check for interrupt endpoint in ttyUSB port (lowest if
# there is more than one); if found, return "gsmmodem[n]" name
# to udev for symlink creation
/dev/gsmmodem是指向一个/dev/ttyUSBX, 这个/dev/ttyUSBX所对应的interface含有"中断类型的端点"
如果有多个/dev/ttyUSBX有中断类型端点, 则/dev/gsmmodem指向最小的/dev/ttyUSBX
怎么判断ttyUSB有无中断类型端点:
# In case the device path is returned as /sys/class/tty/ttyUSB,
# get the USB device path from linked tree "device"
/* 1. 对于每一个/dev/ttyUSBX
* 都有一个对应的/sys/class/tty/ttyUSBX
* 2. 它是一个链接文件, 指向: /sys/......../1-1:1.0/ttyUSB0/tty/ttyUSB0
* 3. 进入/sys/......../1-1:1.0/目录,
* 里面有多个"ep_"的子目录
* 4. 子目录里有名为type的文件
* 5. 如果这个文件的内容为Interrupt, 则返回1
*
*/
2、控制程序编写
(1) 在电脑上接上3G上网卡,出现设备usbdev1.17
(2) 根据usbdevM.N找出它的VID,PID *; M表示总线, N表示设备地址 如usbdev1.17表示在第1条总线上,地址为17的USB设备;可以仿照lsusb
具体程序(3g_manager.c)
#define USB_MODESWITCH_ETC_DIR "/usr/share/usb_modeswitch"
###########################
/* 进行usb模式切换: 调用usb_modeswitch
*/
##########################
int do_switch(int argc, char **argv)
{
libusb_device **devs;
int r;
ssize_t cnt;
libusb_device *dev;
int i = 0;
struct libusb_device_descriptor desc;
int bus;
int address;
int vid;
int pid;
char tmpBuf[1024];
char *cmdBuf;
DIR *dir;
struct dirent *entry;
int fd;
struct stat stat;
/* 在使用mdev的嵌入式系统中, 接上一个USB设备后,
* 在/dev/目录下将出现/dev/usbdevM.N设备
* M表示总线, N表示设备地址 如usbdev1.17表示在第1条总线上,地址为17的USB设备
*/
/* 用法:
* 3g_manager switch usbdev1.17
* 3g_manager link ttyUSB1
*/
//接收输入的参数
sscanf(argv[2]+6, "%d.%d", &bus, &address);//第二个参数向右移动6位,把1赋值给bus,把17赋值到address
/* 根据usbdevM.N找出它的VID,PID */
r = libusb_init(NULL);//初始化libusb
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);//计算usb设备数目
if (cnt < 0)
return (int) cnt;
while ((dev = devs[i++]) != NULL) { //比较每一个设备的总线号和设备地址
if ((bus == libusb_get_bus_number(dev)) && (address == libusb_get_device_address(dev)))
{
r = libusb_get_device_descriptor(dev, &desc);//获取他的设备描述符
if (r < 0) {
printf("failed to get device descriptor");
return -1;
}
vid = desc.idVendor;//取其VID
pid = desc.idProduct;取其PID
break;
}
}
//设备被拔掉
if (!dev)
{
printf("there is not this usbdev!\n");
return -1;
}
/* 根据VID,PID在/usr/share/usb_modeswitch找到名中含有"VID:PID"的文件(因为可能还有后缀) */
sprintf(tmpBuf, "%04x:%04x", vid, pid);//打印出其VID和PID并存在tmpBuf
dir = opendir(USB_MODESWITCH_ETC_DIR);//打开目录/usr/share/usb_modeswitch
if (!dir)
{
printf("can not open %s\n", USB_MODESWITCH_ETC_DIR);
return -1;
}
while((entry = readdir(dir)))//读取目录里面的文件名
{
//以VID和PID进行匹配文件名
//entry->d_name是文件的名字
if (strncasecmp(entry->d_name, tmpBuf, 9) == 0)//匹配文件名(9个字节)
{
break;
}
}
//文件为空
if (!entry)
{
printf("there is cfg file for %04x:%04x\n", vid, pid);
return -1;
}
//找到后
sprintf(tmpBuf, "%s/%s", USB_MODESWITCH_ETC_DIR, entry->d_name);//打印出文件目录和文件名,并吧路径存在tmpBuf里
/* 把配置文件打开读出内容 */
fd = open(tmpBuf, O_RDONLY);//打开文件
if (fd < 0)
{
printf("can not open %s\n", tmpBuf);
return -1;
}
r = fstat(fd, &stat);//获取文件状态,放到stat结构体
if (r == -1)
{
//出错打印信息
printf("can not get stat for %s\n", tmpBuf);
return -1;
}
/* 调用"usb_modeswitch -v VID -p PID -f "文件内容"" */
cmdBuf = malloc(stat.st_size + 1024);//分配大小为文件的大小,1024是用于存储usb_modeswitch -vVID -p PID -f(-v,-p是默认的厂家ID和设备ID,刚接上时以硬盘形式出现的ID)
sprintf(cmdBuf, "usb_modeswitch -v %x -p %x -f \"", vid, pid);//打印用法,"是把文件的内容引进来
cnt = strlen(cmdBuf);//长度是usb_modeswitch -v %x -p %x -f \"的大小
read(fd, cmdBuf+cnt, stat.st_size);//把文件内容读取到buf偏移cnt的地方
cnt += stat.st_size;//cnt增加
cmdBuf[cnt++] = '\"';//存储\",这里\是转义字符,要用引号括起来
cmdBuf[cnt++] = '\0';//存储结束符
printf("Cmd: %s\n", cmdBuf);//打印buf内容
r = system(cmdBuf);//运行buf里面的内容
free(cmdBuf);
close(fd);
return r;
}
/* 进行usb模式切换: 调用usb_modeswitch
* 创建/dev/gsmmodem链接, 指向某个/dev/ttyUSBX
*/
/* 用法:
* 3g_manager switch usbdev1.17
* 3g_manager link ttyUSB1
*/
关于热拔插参考
http://write.blog.csdn.net/postedit/53349521
/*3g_manager.c由mdev.conf调用,当接上3G上网卡*/
int main(int argc, char **argv)
{
if ((argc != 3) || \ //如果输入参数不为3,或者第2个参数既不等于switch也不等于link
//判断是切换还是连接
((strcmp(argv[1], "switch") && strcmp(argv[1], "link"))))
{
printf("Usage:\n"); //出错,打印用法
printf("%s switch <usbdevM.N> : switch 3G Modem\n", argv[0]);//这里argv[0]是3g_manager
printf("%s link <ttyUSBX> : Create Link to /dev/ttyUSBX if it has interrupt endpoint\n", argv[0]);//如果有中断类型端点就创建链接
return -1;
}
if (strcmp(argv[1], "switch") == 0) //如果第二个参数是switch
return do_switch(argc, argv); //调用函数do_switch
else if (strcmp(argv[1], "link") == 0) //如果第二个参数是link
return do_link(argc, argv); //调用函数do_link
return -1;
}
3、实验
修改Makefile,进行编译后拷贝到网络文件系统
执行,查看用法,没有ttyusb设备
但是我们接有usb上网卡,证明还没有切换模式
查看我们的设备,进行命令切换
-f后的内容来自于对应的/usr/share/usb_modeswitch目录下的文件,文件名为12d1:1505
切换成功
想让系统一接上usb 3G上网卡后自动执行模式切换,修改/etc/mdev.conf
下面意思是当接上usb 设备后 ,就会执行3g_manager switch $MDEV,这里 $MDEV代表对应的usb设备
当出现usbdev1.17的时候执行3g_manager switch usbdev1.17
shell 的环境变量 $MDEV 会被设置成设备名
接上另外一个3G上网卡,提示发现usb设备,然后自动切换模式