usb-modeswitch的作用就是转换usb型的设备状态,也是3G 移植中重要的准备工作!
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/39271443
一.Kernel配置:
usb-modeswitch需要kernel中的驱动支持,需要配置serial驱动,到kernel中 make menuconfig 打开serial中的option模块 :
Device Drivers——>USB support——>USB Serial Converter support——>USB driver for GSM and CDMA modems 选中
也可以到 kernel/drivers/usb/serial/Kconfig 中进行手动修改或者直接修改.config。
关于kernel中的模块编译配置可参考:Kernel 编译配置机制
kernel中的option模块已经添加了很多3G模块的ID,包含的ID数组在 kernel/drivers/usb/serial/option.c 中:
- static const struct usb_device_id option_ids[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
- ...
- }
如果需要的移植的3G模块的ID ,上面的数组没包含进去,就手动加进去!
option不能编译成单独module,所以上面选中即可,编译进kernel中。
最后烧录到机器上 目录:/sys/module/option
二.编译:
按照前文的地址下载 usb-modeswitch-2.2.0 以及 usb-modeswitch-data-20140529 这两个压缩包,解压,字面意思可以理解后面的 data包 作为usb-modeswitch 服务用的。
linux 下是需要配置交叉编译器以及libusb的动态库位置的,这里在android源码中编译,照例放到 external中,将data 包中的usb_modeswitch.d 解压到 usb-modeswitch中。
添加Android.mk:
- # jscese add for 3G - usb-modeswitch driver
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LIBUSBDIR := external/libusb/libusb \
- external/lilbusb-compat/libusb
- LOCAL_MODULE := usb_modeswitch
- LOCAL_SRC_FILES := usb_modeswitch.c
- LOCAL_MODULE_TAGS := optional
- LOCAL_C_INCLUDES :=$(LIBUSBDIR)
- LOCAL_SHARED_LIBRARIES := libusb libusb-compat
- include $(BUILD_EXECUTABLE)
- #############cp usb_modeswitch database########
- $(shell cp -rf $(LOCAL_PATH)/usb_modeswitch.d $(TARGET_OUT)/etc)
指定INCLUDES,因为需要libusb的头文件,还需要之前编译的lib,我是直接cp了data包到 etc里面,最后打包进系统!
这里我取巧了,直接用了shell,如果整体初次编译是不行的,正规的做法可参考:Android——编译体系中的【PRODUCT_COPY_FILES】【ALL_PREBUILT】【BUILD_PREBUILT】中的第四部分.
可以看看usb_modeswitch.d包里面的内容,全是 ID 文件,看一款华为的3G 12d1:1446:
- # Huawei, newer modems
- TargetVendor=0x12d1
- TargetProductList="1001,1406,140b,140c,1412,141b,1432,1433,1436,14ac,1506,150c,1511"
- HuaweiNewMode=1
usb-modeswitch 转换的时候就是以上面的为参数。
mmm 编译成android 二进制执行文件,整体make -j* 编译不生成到正确路径的问题可参考:Android——编译安装Module的控制因素
三.使用:
编译烧录进系统之后,可在android文件系统/system/bin 找到 usb_modeswitch ,shell终端输入 usb_modeswitch + 回车:
- shell@android:/ # usb_modeswitch
- Usage: usb_modeswitch [<params>] [-c filename]
- -h, --help this help
- -e, --version print version information and exit
- -j, --find-mbim return config no. with MBIM interface, exit
- -v, --default-vendor NUM vendor ID of original mode (mandatory)
- -p, --default-product NUM product ID of original mode (mandatory)
- -V, --target-vendor NUM target mode vendor ID (optional)
- -P, --target-product NUM target mode product ID (optional)
- -C, --target-class NUM target mode device class (optional)
- -b, --bus-num NUM system bus number of device (for hard ID)
- -g, --device-num NUM system device number (for hard ID)
- -m, --message-endpoint NUM direct the message transfer there (optional)
- -M, --message-content <msg> message to send (hex number as string)
- -2 <msg>, -3 <msg> additional messages to send (-n recommended)
- -n, --need-response read response to the message transfer (CSW)
- -r, --response-endpoint NUM read response from there (optional)
- -K, --std-eject send standard EJECT sequence
- -d, --detach-only detach the active driver, no further action
- -H, --huawei-mode apply a special procedure
- -J, --huawei-new-mode apply a special procedure
- -S, --sierra-mode apply a special procedure
- -O, --sony-mode apply a special procedure
- -G, --gct-mode apply a special procedure
- -N, --sequans-mode apply a special procedure
- -A, --mobileaction-mode apply a special procedure
- -T, --kobil-mode apply a special procedure
- -L, --cisco-mode apply a special procedure
- -B, --qisda-mode apply a special procedure
- -E, --quanta-mode apply a special procedure
- -R, --reset-usb reset the device after all other actions
- -Q, --quiet don't show progress or error messages
- -W, --verbose print all settings and debug output
- -D, --sysmode specific result and syslog message
- -s, --success <seconds> switching result check with timeout
- -I, --inquire retrieve SCSI attributes initially
- -c, --config-file <filename> load long configuration from file
- -t, --stdinput read long configuration from stdin
- -f, --long-config <text> get long configuration from string
- -i, --interface NUM select initial USB interface (default 0)
- -u, --configuration NUM select USB configuration
- -a, --altsetting NUM select alternative USB interface setting
- * usb_modeswitch: handle USB devices with multiple modes
- * Version 2.2.0 (C) Josua Dietze 2014
- * Based on libusb1/libusbx
- ! PLEASE REPORT NEW CONFIGURATIONS !
参数用法全列出来了,想怎么用,看各人爱好了,usb-modeswitch的data包里面 是有 rules 文件的 40-usb_modeswitch.rules
适用于linux的udev,当kernel监测到设备时,交给udev来处理,此时会根据rules 来执行 usb-modeswitch。
android 用vold 取代了 udev,所以一般都是在vold 里面调用 usb-modeswitch了!
关于 androdi 的 vold 机制可参考 我之前的专栏:Android— 4.2 Vold
这里贴出我的做法:
/system/vold/NetlinkHandler.cpp中的 onEvent 函数中添加:
- if (!strcmp(subsys, "usb"))
- {
- if(access("/dev/ttyUSB2",0)==0) //check一下是否已经转了,如果已经调用usb-modeswitch 并且成功了的话是会在/dev/下看到ttyUSB* 字样的设备文件的
- {
- SLOGW("jscese display in NetlinkHandler::onEvent already switch \n");
- return;
- }
- char *productid = (char *)evt->findParam("PRODUCT");//取event中的 设备ID信息,包含厂商ID,产品ID
- SLOGW("jscese display in NetlinkHandler::onEvent productid ==%s \n",productid);
- if(productid ==NULL) //过滤kernel发上来的一些事件
- {
- return;
- }
- handledevice(evt,productid);
- }
- void NetlinkHandler::handledevice(NetlinkEvent *evt,char *str)
- {
- const char *delim = "/";
- char *save_ptr;
- char *idVendor =NULL;
- char *idProduct =NULL;
- if(evt->getAction()==NetlinkEvent::NlActionAdd)
- {
- if (!(idVendor = strtok_r(str, delim, &save_ptr))) {//分割保存
- SLOGE("Error parsing idVendor");
- return;
- }
- if (!(idProduct = strtok_r(NULL, delim, &save_ptr))) {
- SLOGE("Error parsing idProduct");
- return;
- }
- char modeswitch_cmd[1024] = {'\0'};
- sprintf(modeswitch_cmd, "/system/bin/usb_modeswitch -W -v %s -p %s -c /system/etc/usb_modeswitch.d/%s:%s", idVendor,
- idProduct, idVendor, idProduct); // 准备 执行usb-modeswitch的 命令, 用到了前面的data文件
- SLOGW("jscese display modeswitch ==%s \n", modeswitch_cmd);
- if (system(modeswitch_cmd) == 0) //这里就是真正的调用,执行上面的cmd,shell指令成功返回0
- {
- SLOGW("jscese display system modeswitch success \n");
- }else
- {
- SLOGW("jscese display system modeswitch fail \n");
- }
- }
- }
上面的handledevice 为核心函数,不logcat,kernel的打印如下:
- [ 3252.717055] ==11==> hub_port_init 1
- [ 3252.720785] Plug in USB Port1
- [ 3252.905058] usb 4-1: new high speed USB device number 4 using Mstar-ehci-1
- [ 3253.343340] usb 4-1: New USB device found, idVendor=12d1, idProduct=1446
- [ 3253.350139] usb 4-1: New USB device strings: Mfr=3, Product=2, SerialNumber=0
- [ 3253.357428] usb 4-1: Product: HUAWEI Mobile
- [ 3253.361713] usb 4-1: Manufacturer: HUAWEI Technology
- [ 3253.371651] scsi6 : usb-storage 4-1:1.0
- [ 3253.379741] scsi 6:0:0:0: CD-ROM HUAWEI Mass Storage 2.31 PQ: 0 ANSI: 2
- [ 3253.388333] scsi7 : usb-storage 4-1:1.1
- [ 3253.395767] scsi 7:0:0:0: Direct-Access HUAWEI SD Storage 2.31 PQ: 0 ANSI: 2
- [ 3253.410108] sd 7:0:0:0: [sda] Attached SCSI removable disk
- [ 3253.442848] usb 4-1: USB disconnect, device number 4
- [ 3258.683641] root hub reinitial
- [ 3258.692585] Mstar-ehci-1 Mstar-ehci-1.0: force halt; handshake fd204814 0000c000 00000000 -> -110
- [ 3258.969055] ==11==> hub_port_init 1
- [ 3258.972702] Plug in USB Port1
- [ 3259.157042] usb 4-1: new high speed USB device number 5 using Mstar-ehci-1
- [ 3259.595613] usb 4-1: New USB device found, idVendor=12d1, idProduct=1436
- [ 3259.602448] usb 4-1: New USB device strings: Mfr=4, Product=3, SerialNumber=0
- [ 3259.609776] usb 4-1: Product: HUAWEI Mobile
- [ 3259.614050] usb 4-1: Manufacturer: HUAWEI Technology
- [ 3259.629199] option 4-1:1.0: GSM modem (1-port) converter detected
- [ 3259.638958] usb 4-1: GSM modem (1-port) converter now attached to ttyUSB0
- [ 3259.650087] option 4-1:1.3: GSM modem (1-port) converter detected
- [ 3259.658538] usb 4-1: GSM modem (1-port) converter now attached to ttyUSB1
- [ 3259.666610] option 4-1:1.4: GSM modem (1-port) converter detected
- [ 3259.674883] usb 4-1: GSM modem (1-port) converter now attached to ttyUSB2
- [ 3259.683800] scsi10 : usb-storage 4-1:1.5
- [ 3259.690925] scsi11 : usb-storage 4-1:1.6
- [ 3259.695228] scsi 10:0:0:0: CD-ROM HUAWEI Mass Storage 2.31 PQ: 0 ANSI: 2
- [ 3259.706845] scsi 11:0:0:0: Direct-Access HUAWEI SD Storage 2.31 PQ: 0 ANSI: 2
- [ 3259.722956] sd 11:0:0:0: [sda] Attached SCSI removable disk
可以看到 厂商ID 和产品ID 分别为: idVendor=12d1, idProduct=1446
并且生成了 ttyUSB0 ~ttyUSB2 三个设备文件在/dev下
还需要保证这三个设备文件的权限,以备后续使用,设置权限:
关于设备文件的权限设置,android默认是放在 /system/core/rootdir/ueventd.rc中:
添加ttyUSB0 ~ttyUSB2读写权限:
- # jscese add for 3G
- /dev/ttyUSB0 0666 radio radio
- /dev/ttyUSB1 0666 radio radio
- /dev/ttyUSB2 0666 radio radio