赞
踩
搞来搞去搞了很久,差点放弃走人的时候,发现竟然是这点事。。。辛酸史如下:
android6.01-----kernel4.4.36-----编译环境ubuntu16.04
内核有4种驱动方式,usb serial、CDC ACM、Gobinet、QMI WWAN,本文选用的是usb serial和QMI WWAN两种驱动。
/kernel/driver/usb/serial/option.c
如果,你添加的是EC20。那么,注释掉以下代码,避免型号冲突。
/kernel/driver/usb/serial/qcserial.c
{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
/kernel/driver/net/usb/qmi_wwan.c
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
此时,在/dev/下可以找到ttyUSB0/ttyUSB1/ttyUSB2/ttyUSB3设备节点
根据 USB 协议的要求, 需要添加在批量输出传输过程中处理零数据包的机制。
/kernel/drivers/usb/serial/usb_wwan.c
当 MCU 进入挂起状态时, 某些 USB 主机控制器/集线器将断电或重置模式, 并且在 MCU 退出挂起/休眠模式后, 它们无法恢复 USB 设备。添加以下语句, 以启用重新安置过程。
/kernel/drivers/usb/serial/option.c
/kernel/drivers/usb/serial/option.c
[*] Device Driver
[*]USB Support
[*]USB Serial Converter support
[*]USB Driver for GSM and CDMA modems
/kernel/drivers/net/usb/qmi_wwan.c
如果添加的是EC20型号,请注释以下代码。
/kernel/drivers/usb/serial/qcserial.c
{USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
/kernel/drivers/net/usb/qmi_wwan.c
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
此时,在/dev/下可以找到qcqmi0设备节点
Ec25仅支持原始 IP 模式 (IP 数据包未封装在以太网帧)。因此, 当数据包发送到模块时, 必须剥离以太网标头, 并且从模块接收数据包时添加。
/kernel/drivers/net/usb/qmi_wwan.c
- #if 1 //Added by Quectel
- #include <linux/etherdevice.h>
- struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
- {
- if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
- return skb;
- // Skip Ethernet header from message
- if (skb_pull(skb, ETH_HLEN))
- return skb;
- else
- dev_err(&dev->intf->dev, "Packet Dropped ");
- // Filter the packet out, release it
- dev_kfree_skb_any(skb);
- return NULL;
- }
- #include <linux/version.h>
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
- static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
- {
- __be16 proto;
- if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
- return 1;
- /* This check is no longer done by usbnet */
- if (skb->len < dev->net->hard_header_len)
- return 0;
- switch (skb->data[0] & 0xf0) {
- case 0x40:
- proto = htons(ETH_P_IP);
- break;
- case 0x60:
- proto = htons(ETH_P_IPV6);
- break;
- case 0x00:
- if (is_multicast_ether_addr(skb->data))
- return 1;
- /* possibly bogus destination - rewrite just in case */
- skb_reset_mac_header(skb);
- goto fix_dest;
- default:
- /* pass along other packets without modifications */
- return 1;
- }
- if (skb_headroom(skb) < ETH_HLEN)
- return 0;
- skb_push(skb, ETH_HLEN);
- skb_reset_mac_header(skb);
- eth_hdr(skb)->h_proto = proto;
- memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
- fix_dest:
- memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
- return 1;
- }
- /* very simplistic detection of IPv4 or IPv6 headers */
- static bool possibly_iphdr(const char *data)
- {
- return (data[0] & 0xd0) == 0x40;
- }
- #endif
- #endif
- ……
- /* if follow function exist, modify it as below */
- static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
- {
- ……
- #if 1 //Added by Quectel
- if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
- dev_info(&intf->dev, "Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96&AG35 work on RawIP mode\n");
- dev->net->flags |= IFF_NOARP;
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
- /* make MAC addr easily distinguishable from an IP header */
- if (possibly_iphdr(dev->net->dev_addr)) {
- dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
- dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
- }
- #endif
- usb_control_msg(
- interface_to_usbdev(intf),
- usb_sndctrlpipe(interface_to_usbdev(intf), 0),
- 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE
- 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
- 1, //active CDC DTR
- intf->cur_altsetting->desc.bInterfaceNumber,
- NULL, 0, 100);
- }
- #endif
- err:
- return status;
- }
-
- /* if follow struct exist, modify it as below */
- static const struct driver_info qmi_wwan_info =
- {
- ……
- #if 1 //Added by Quectel
- .tx_fixup = qmi_wwan_tx_fixup,
- .rx_fixup = qmi_wwan_rx_fixup,
- #endif
- }
-
- /* if follow struct exist, modify it as below */
- static const struct driver_info qmi_wwan_force_int4 = {
- ……
- #if 1 //Added by Quectel
- .tx_fixup = qmi_wwan_tx_fixup,
- .rx_fixup = qmi_wwan_rx_fixup,
- #endif
- };
[*]Device Drivers
[*]Network device support
[*]USB Network Adapters
[*]Multi-purpose USB Networking Framework
<*>QMI WWAN driver for Qualcomm MSM based 3G and LTE modems
[*]Device Driver
[*]Network device support
[*]PPP (point-to-point protocol) support
/kernel/drivers/usb/serial/option.c
- static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) {
- struct usb_wwan_intf_private *data;
- ……
- #if 1 //Added by Quectel
- //For USB Auto Suspend
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) {
- pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
- usb_enable_autosuspend(serial->dev);
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) {
- pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
- usb_enable_autosuspend(serial->dev);
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) {
- pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
- usb_enable_autosuspend(serial->dev);
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
- pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
- usb_enable_autosuspend(serial->dev);
- }
- #endif
- /* Store device id so we can use it during attach. */
- usb_set_serial_data(serial, (void *)id);
- return 0;
- }
/kernel/drivers/usb/serial/option.c
- static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) {
- struct usb_wwan_intf_private *data;
- ……
- #if 1 //Added by Quectel
- //For USB Remote Wakeup
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) {
- device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) {
- device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) {
- device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
- }
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
- device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
- }
- #endif
- /* Store device id so we can use it during attach. */
- usb_set_serial_data(serial, (void *)id);
- return 0;
- }
此时,驱动层相关已经添加完了。
如果是linux系统,再添加quectel-CM的拨号工具就可以了。
放入/hardware/ril/reference-ril/路径下;
android环境,命令udhcpc -h检查版本调用路径:
将default.script脚本放至该路径(或/usr/share/udhcpc/),并注意执行权限。
权限:可在/system/core/libcutils/fs_config.c文件或init.rc文件中的on init中指定
将sudo quectel-CM -s ctnet 命令添加到脚本,并在/etc/init.d/rc中启动脚本。
检查IP/DNS/网关等配置,没问题可以正常启动。
放入/hardware/ril/reference-ril路径
/device/rockchip/rkxx/rkxxxxxx/system.prop
rild.llibpath=/system/lib64/libreference-ril.so
rild.libargs=-d /dev/ttyUSB2 //ttyUSB2是AT口
源码路径:/packages/apps/PhoneCommon
添加编译:/device/rockchip/rk3399/device.mk
PRODUCT_PACKAGES += com.android.phone.common
在/out/target/product/rkxxsdk/system/app/下出现com.android.phone.common
/device/rockchip/rk3399/init.rc
- service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so
- class main
- socket rild stream 660 root radio
- socket rild-debug stream 660 radio system
- user root
- group radio cache inet misc audio sdcard_rw log
(android8及以上)
- service ril-daemon /vendor/bin/hw/rild -l /vendor/lib64/libreference-ril.so
- class main
- user root
- group radio cache inet misc audio sdcard_rw log
/hardware/ril/rild/rild.c
- OpenLib:
- #endif
- //switchUser();
-
- dlHandle = dlopen(rilLibPath, RTLD_NOW);
/device/rockchip/rkxx/rkxx.mk
PRODUT_COPY_FILES:= /vendor/rockchip/common/phone/etc/apns-full-conf.xml:system/etc/qpns-conf.xml
检查该文件中是否包含所使用的运营商APN信息,如果没有,添加上相应的APN信息。
比如:使用MCC/MNC来确认,而MCC/MNC的值是通过模块查询到的IMSI码的前五位来确定的。
/device/rockchip/common/BoardConfig.mk
BOARD_HAVE_DONGLE ?= true
logcat -b radio -v time //查看log
getprop init.svc.ril-daemon //检查ril守护进程Runing
cat init.rc | grep ril-daemon //检查ril-daemon服务是否生效
getenforce //检查SELinux是否开启,<setenforce 0>命令关闭
getprop gsm.version.ril-impl //检查ril版本,出现Quectel_Android_RIL_SR01A41V17,如未出现ril库没有添加上,或者检查phone进程
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。