当前位置:   article > 正文

rk3399添加EC25E/EC20...模组_[kernel]/drivers/usb/serial/option.c

[kernel]/drivers/usb/serial/option.c

搞来搞去搞了很久,差点放弃走人的时候,发现竟然是这点事。。。辛酸史如下:

android6.01-----kernel4.4.36-----编译环境ubuntu16.04

一、kernel driver

内核有4种驱动方式,usb serial、CDC ACM、Gobinet、QMI WWAN,本文选用的是usb serial和QMI WWAN两种驱动。

 

1.usb serial

(1)添加模组的PID/VID。

/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设备节点

(2)添加零包机制

根据 USB 协议的要求, 需要添加在批量输出传输过程中处理零数据包的机制。

/kernel/drivers/usb/serial/usb_wwan.c

(3)添加重置回调

当 MCU 进入挂起状态时, 某些 USB 主机控制器/集线器将断电或重置模式, 并且在 MCU 退出挂起/休眠模式后, 它们无法恢复 USB 设备。添加以下语句, 以启用重新安置过程。

/kernel/drivers/usb/serial/option.c

(4)如果使用Gobinet、QMI WWAN驱动

/kernel/drivers/usb/serial/option.c

(5)添加内核模块

[*] Device Driver

   [*]USB Support

      [*]USB Serial Converter support

         [*]USB Driver for GSM and CDMA modems

 

2.QMI WWAN

(1)添加PID/VID

/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设备节点

(2)添加对原始 IP 模式的支持

       Ec25仅支持原始 IP 模式 (IP 数据包未封装在以太网帧)。因此, 当数据包发送到模块时, 必须剥离以太网标头, 并且从模块接收数据包时添加。

/kernel/drivers/net/usb/qmi_wwan.c

  1. #if 1 //Added by Quectel
  2. #include <linux/etherdevice.h>
  3. struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
  4. {
  5. if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
  6. return skb;
  7. // Skip Ethernet header from message
  8. if (skb_pull(skb, ETH_HLEN))
  9. return skb;
  10. else
  11. dev_err(&dev->intf->dev, "Packet Dropped ");
  12. // Filter the packet out, release it
  13. dev_kfree_skb_any(skb);
  14. return NULL;
  15. }
  16. #include <linux/version.h>
  17. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  18. static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  19. {
  20. __be16 proto;
  21. if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C))
  22. return 1;
  23. /* This check is no longer done by usbnet */
  24. if (skb->len < dev->net->hard_header_len)
  25. return 0;
  26. switch (skb->data[0] & 0xf0) {
  27. case 0x40:
  28. proto = htons(ETH_P_IP);
  29. break;
  30. case 0x60:
  31. proto = htons(ETH_P_IPV6);
  32. break;
  33. case 0x00:
  34. if (is_multicast_ether_addr(skb->data))
  35. return 1;
  36. /* possibly bogus destination - rewrite just in case */
  37. skb_reset_mac_header(skb);
  38. goto fix_dest;
  39. default:
  40. /* pass along other packets without modifications */
  41. return 1;
  42. }
  43. if (skb_headroom(skb) < ETH_HLEN)
  44. return 0;
  45. skb_push(skb, ETH_HLEN);
  46. skb_reset_mac_header(skb);
  47. eth_hdr(skb)->h_proto = proto;
  48. memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
  49. fix_dest:
  50. memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
  51. return 1;
  52. }
  53. /* very simplistic detection of IPv4 or IPv6 headers */
  54. static bool possibly_iphdr(const char *data)
  55. {
  56. return (data[0] & 0xd0) == 0x40;
  57. }
  58. #endif
  59. #endif
  60. ……
  61. /* if follow function exist, modify it as below */
  62. static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
  63. {
  64. ……
  65. #if 1 //Added by Quectel
  66. if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
  67. dev_info(&intf->dev, "Quectel EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96&AG35 work on RawIP mode\n");
  68. dev->net->flags |= IFF_NOARP;
  69. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  70. /* make MAC addr easily distinguishable from an IP header */
  71. if (possibly_iphdr(dev->net->dev_addr)) {
  72. dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
  73. dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
  74. }
  75. #endif
  76. usb_control_msg(
  77. interface_to_usbdev(intf),
  78. usb_sndctrlpipe(interface_to_usbdev(intf), 0),
  79. 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE
  80. 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
  81. 1, //active CDC DTR
  82. intf->cur_altsetting->desc.bInterfaceNumber,
  83. NULL, 0, 100);
  84. }
  85. #endif
  86. err:
  87. return status;
  88. }
  89. /* if follow struct exist, modify it as below */
  90. static const struct driver_info qmi_wwan_info =
  91. {
  92. ……
  93. #if 1 //Added by Quectel
  94. .tx_fixup = qmi_wwan_tx_fixup,
  95. .rx_fixup = qmi_wwan_rx_fixup,
  96. #endif
  97. }
  98. /* if follow struct exist, modify it as below */
  99. static const struct driver_info qmi_wwan_force_int4 = {
  100. ……
  101. #if 1 //Added by Quectel
  102. .tx_fixup = qmi_wwan_tx_fixup,
  103. .rx_fixup = qmi_wwan_rx_fixup,
  104. #endif
  105. };

(3)添加内核模块

[*]Device Drivers

   [*]Network device support

      [*]USB Network Adapters

         [*]Multi-purpose USB Networking Framework

            <*>QMI WWAN driver for Qualcomm MSM based 3G and LTE modems

 

3.添加内核ppp

[*]Device Driver

   [*]Network device support

      [*]PPP (point-to-point protocol) support

 

4.电源管理

(1)自动挂起

/kernel/drivers/usb/serial/option.c

  1. static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) {
  2. struct usb_wwan_intf_private *data;
  3. ……
  4. #if 1 //Added by Quectel
  5. //For USB Auto Suspend
  6. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) {
  7. pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
  8. usb_enable_autosuspend(serial->dev);
  9. }
  10. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) {
  11. pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
  12. usb_enable_autosuspend(serial->dev);
  13. }
  14. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) {
  15. pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
  16. usb_enable_autosuspend(serial->dev);
  17. }
  18. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
  19. pm_runtime_set_autosuspend_delay(&serial->dev->dev, 3000);
  20. usb_enable_autosuspend(serial->dev);
  21. }
  22. #endif
  23. /* Store device id so we can use it during attach. */
  24. usb_set_serial_data(serial, (void *)id);
  25. return 0;
  26. }

(2)自动唤醒

/kernel/drivers/usb/serial/option.c

  1. static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) {
  2. struct usb_wwan_intf_private *data;
  3. ……
  4. #if 1 //Added by Quectel
  5. //For USB Remote Wakeup
  6. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9090)) {
  7. device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
  8. }
  9. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)) {
  10. device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
  11. }
  12. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)) {
  13. device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
  14. }
  15. if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
  16. device_init_wakeup(&serial->dev->dev, 1); //usb remote wakeup
  17. }
  18. #endif
  19. /* Store device id so we can use it during attach. */
  20. usb_set_serial_data(serial, (void *)id);
  21. return 0;
  22. }

此时,驱动层相关已经添加完了。

如果是linux系统,再添加quectel-CM的拨号工具就可以了。

 

5.quectel-CM拨号

(1)移植quctel-CM源码

放入/hardware/ril/reference-ril/路径下;

(2)添加default.script脚本

android环境,命令udhcpc -h检查版本调用路径:

将default.script脚本放至该路径(或/usr/share/udhcpc/),并注意执行权限。

权限:可在/system/core/libcutils/fs_config.c文件或init.rc文件中的on init中指定

(3)执行quectel-CM

将sudo quectel-CM -s ctnet 命令添加到脚本,并在/etc/init.d/rc中启动脚本。

检查IP/DNS/网关等配置,没问题可以正常启动。

 

 

二.android RIL库

 

1.添加ril源码

(1)移植ril源码

放入/hardware/ril/reference-ril路径

(2)指定rild库路径

/device/rockchip/rkxx/rkxxxxxx/system.prop

rild.llibpath=/system/lib64/libreference-ril.so

rild.libargs=-d /dev/ttyUSB2      //ttyUSB2是AT口

 

2.添加phone进程

源码路径:/packages/apps/PhoneCommon

添加编译:/device/rockchip/rk3399/device.mk

PRODUCT_PACKAGES += com.android.phone.common

在/out/target/product/rkxxsdk/system/app/下出现com.android.phone.common

 

3.android系统设置

(1)添加ril-daemon服务到init.rc

/device/rockchip/rk3399/init.rc

  1. service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so
  2. class main
  3. socket rild stream 660 root radio
  4. socket rild-debug stream 660 radio system
  5. user root
  6. group radio cache inet misc audio sdcard_rw log

(android8及以上)

  1. service ril-daemon /vendor/bin/hw/rild -l /vendor/lib64/libreference-ril.so
  2. class main
  3. user root
  4. group radio cache inet misc audio sdcard_rw log

(2)保证rild的root权限

/hardware/ril/rild/rild.c

  1. OpenLib:
  2. #endif
  3. //switchUser();
  4. dlHandle = dlopen(rilLibPath, RTLD_NOW);

(3)添加APN

/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码的前五位来确定的。

(4)打开dongle功能

/device/rockchip/common/BoardConfig.mk

BOARD_HAVE_DONGLE ?= true

(5)检查

          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进程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/211402
推荐阅读
相关标签
  

闽ICP备14008679号