谷动谷力

 找回密码
 立即注册
查看: 2516|回复: 1
打印 上一主题 下一主题
收起左侧

OpenWrt下移植EC20R2.0驱动实现4G模块实现qmi拨号上网

[复制链接]
跳转到指定楼层
楼主
发表于 2022-12-3 21:06:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 fannifu 于 2024-4-18 09:22 编辑

OpenWrt下移植EC20R2.0驱动实现4G模块实现qmi拨号上网

1.参考资料

本文档参考资料为Quectel_WCDMA<E_Linux_USB_Driver_User_Guide_V1.6.pdf,
实现QMI拨号,只需要参考下列章节即可
EC20有多个版本,看是否是EC20 R2.0还是普通EC20。


2.修改内核代码

2.1.0. 修改USB串口驱动,增加PID&VID,相关QUECTEL USB产品定义(枚举信息)

修改内核源码文件 File : [KERNEL]/drivers/usb/serial/option.c

  1. staticconst struct usb_device_id option_ids[] = {
  2. #if 1 //Added by Quectel
  3. { USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
  4. { USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */
  5. { USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
  6. { USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
  7. { USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */
  8. #endif
复制代码


2.1.1.  添加零包处理 Add the Zero PacketMechanism

For Linux Kernel Version newer than 2.6.34:
Linux 2.6.34以前的版本
修改内核源码文件 File:[KERNEL]/drivers/usb/serial/usb_wwan.c

  1. static struct urb*usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
  2. int dir, void *ctx, char *buf, int len,void(*callback) (struct urb *))
  3. {
  4. ……
  5. usb_fill_bulk_urb(urb, serial->dev,
  6. usb_sndbulkpipe(serial->dev, endpoint) |dir,
  7. buf, len, callback, ctx);
  8. #if 1 //Added by Quectelfor Zero Packet
  9.         if (dir == USB_DIR_OUT) {
  10.                 struct usb_device_descriptor*desc = &serial->dev->descriptor;
  11.                 if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
  12.                         urb->transfer_flags|= URB_ZERO_PACKET;
  13.                 if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
  14.                         urb->transfer_flags|= URB_ZERO_PACKET;
  15.                 if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
  16.                         urb->transfer_flags|= URB_ZERO_PACKET;
  17.                 if (desc->idVendor ==cpu_to_le16(0x2C7C))
  18.                         urb->transfer_flags|= URB_ZERO_PACKET;
  19. }
  20. #endif
  21. return urb;
  22. }
复制代码


2.1.2. 增加休眠后唤醒接口 Add Reset Resume

修改内核源码文件 File: [KERNEL]/drivers/usb/serial/option.c
  1. static struct usb_serial_driveroption_1port_device = {
  2. ……
  3. #ifdef CONFIG_PM
  4.      .suspend = usb_wwan_suspend,
  5.      .resume = usb_wwan_resume,
  6.      #if 1 //Added by Quectel
  7.     .reset_resume = usb_wwan_resume,
  8.     #endif
  9. #endif
  10. }
复制代码


2.2.5  使用QMI WWAN Use GobiNet or QMI WWAN
File: [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. //Quectel UC20'sinterface 4 can be used as USB Network device
  6. if  (serial->dev->descriptor.idVendor  == cpu_to_le16(0x05C6)  &&
  7. serial->dev->descriptor.idProduct ==cpu_to_le16(0x9003)
  8. &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
  9. return -ENODEV;
  10. //Quectel EC20's interface4 can be used as USB Network device
  11. if  (serial->dev->descriptor.idVendor  == cpu_to_le16(0x05C6)  &&
  12. serial->dev->descriptor.idProduct== cpu_to_le16(0x9215)
  13. &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
  14. return -ENODEV;
  15. //QuectelEC21&EC25&EC20 R2.0's interface 4 can be used as USB Network device
  16. if(serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)
  17. &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
  18. return -ENODEV;
  19. #endif
  20. /* Store device id so we can use it duringattach. */
  21. usb_set_serial_data(serial, (void *)id);
  22. return 0;
  23. }
复制代码



3. 修改内核增加QMI WWAN驱动支持QMI WWAN Driver

3.1.1 增加VID和PID Add VID and PID

修改文件 "[KERNEL]/drivers/net/usb/qmi_wwan.c".

  1. static const struct usb_device_idproducts[] = {
  2. #if 1 //Added by Quectel
  3. #ifndef QMI_FIXED_INTF
  4. /* map QMI/wwan function by a fixed interface number */
  5. #define QMI_FIXED_INTF(vend, prod, num) \
  6. .match_flags  =  USB_DEVICE_ID_MATCH_DEVICE  |
  7. USB_DEVICE_ID_MATCH_INT_INFO, \
  8. .idVendor = vend, \
  9. .idProduct = prod, \
  10. .bInterfaceClass = 0xff, \
  11. .bInterfaceSubClass = 0xff, \
  12. .bInterfaceProtocol = 0xff, \
  13. .driver_info = (unsigned long)&qmi_wwan_force_int##num,
  14. #endif
  15. { QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */
  16. { QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 */
  17. { QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25/EC20R2.0 */
  18. { QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */
  19. #endif
复制代码



3.1.2  增加对Raw IP Mode的支持 Add Support for Raw IP Modefor EC21/EC25/EC20 R2.0

修改文件"[KERNEL]/drivers/net/usb/qmi_wwan.c"
  1. #include <linux/usb/usbnet.h>
  2. #include <linux/usb/cdc-wdm.h>
  3. #if 1 //Added by Quectel
  4. #include <linux/etherdevice.h>
  5. struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, structsk_buff *skb, gfp_t flags)
  6. {
  7. if (dev->udev->descriptor.idVendor !=cpu_to_le16(0x2C7C))
  8. return skb;
  9. // Skip Ethernet header from message
  10. if (skb_pull(skb, ETH_HLEN)) {
  11. return skb;
  12. } else {
  13. dev_err(&dev->intf->dev, "Packet Dropped");
  14. }
  15. // Filter the packet out, release it
  16. dev_kfree_skb_any(skb);
  17. return NULL;
  18. }
  19. #include <linux/version.h>
  20. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  21. static int qmi_wwan_rx_fixup(struct usbnet *dev, structsk_buff *skb)
  22. {
  23. __be16 proto;
  24. if (dev->udev->descriptor.idVendor !=cpu_to_le16(0x2C7C))
  25. return 1;
  26. /* This check is no longer done by usbnet */
  27. if (skb->len < dev->net->hard_header_len)
  28. return 0;
  29. switch (skb->data[0] & 0xf0) {
  30. case 0x40:
  31. proto = htons(ETH_P_IP);
  32. break;
  33. case 0x60:
  34. proto = htons(ETH_P_IPV6);
  35. break;
  36. case 0x00:
  37. if (is_multicast_ether_addr(skb->data))
  38. return 1;
  39. /* possibly bogus destination - rewrite just in case */
  40. skb_reset_mac_header(skb);
  41. goto fix_dest;
  42. default:
  43. /* pass along other packets without modifications */
  44. return 1;
  45. }
  46. if (skb_headroom(skb) < ETH_HLEN)
  47. return 0;
  48. skb_push(skb, ETH_HLEN);
  49. skb_reset_mac_header(skb);
  50. eth_hdr(skb)->h_proto = proto;
  51. memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
  52. fix_dest:
  53. memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr,ETH_ALEN);
  54. return 1;
  55. }

  56. /* very simplistic detection of IPv4or IPv6 headers */
  57. static bool possibly_iphdr(const char*data)
  58. {
  59. return (data[0] & 0xd0) == 0x40;
  60. }
  61. #endif
  62. #endif

  63. /* if follow function exist, modify itas below */
  64. static int qmi_wwan_bind(struct usbnet*dev, struct usb_interface *intf)
  65. {
  66. ……
  67. #if 1 //Added by Quectel
  68.     if(dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
  69.        dev_info(&intf->dev, "Quectel EC21&EC25&EC20 R2.0work on RawIP mode\n");
  70.        dev->net->flags |= IFF_NOARP;
  71. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  72. /* make MAC addr easily distinguishable from an IP header */
  73.     if (possibly_iphdr(dev->net->dev_addr)){
  74.        dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
  75.        dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
  76.     }
  77. #endif
  78.     usb_control_msg(
  79.        interface_to_usbdev(intf),
  80.        usb_sndctrlpipe(interface_to_usbdev(intf), 0),
  81.         0x22,//USB_CDC_REQ_SET_CONTROL_LINE_STATE
  82.         0x21,//USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
  83.         1, //active CDCDTR
  84.        intf->cur_altsetting->desc.bInterfaceNumber,
  85.         NULL, 0, 100);
  86. }
  87. #endif
  88. err:
  89. return status;
  90. }

  91. /* if follow struct exist, modify itas below */
  92. static const struct driver_info  qmi_wwan_info =
  93. {
  94. ……
  95. #if 1 //Added by Quectel
  96. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))
  97.     .tx_fixup =qmi_wwan_tx_fixup,
  98. #endif
  99. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  100.     .rx_fixup =qmi_wwan_rx_fixup,
  101. #endif
  102. #endif
  103. }

  104. /* if follow struct exist, modify itas below */
  105. static const struct driver_infoqmi_wwan_force_int4 = {
  106. ……
  107. #if 1 //Added by Quectel
  108. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))
  109.     .tx_fixup =qmi_wwan_tx_fixup,
  110. #endif
  111. #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
  112.     .rx_fixup =qmi_wwan_rx_fixup,
  113. #endif
  114. #endif
  115. };
复制代码

4. 编译配置

使用图形化菜单配置openwrt, 输入命令:
  1. make menuconfig
复制代码

配置项:
NetWork   >>
        <*> uqmi......................... Control utility for mobile broadband modems
       -*- wwan  .....................GenericOpenWrt 3G/4G proto handler

Kernel modules >>
        USB Support >>
                -*- Kmod -usb-core
                -*-   Kmod -usb-net
                -*-        Kmod-usb-net-cdc-ether
                -*-    Kmod-usb-net-qmi-wwan
                < >  Kmod-usb-ohci   //这个选项一定要勾选,否则可能无法在系统中查看设备
                <*> Kmod-usb-serial
                <*> Kmod-usb-serial-option
                <> Kmod-usb-uhci
                <*> Kmod-usb2

5. 编译


make命令编译:
  1. make -j10
复制代码

编译方法
参考:
【openwrt】OpenWrt编译 – 说明-谷动谷力 (sunsili.com)
【Openwrt】开发环境搭建 编译openwrt源码-谷动谷力 (sunsili.com)
【openwrt学习笔记一】从搭建编译环境到编译openwrt全过程-谷动谷力 (sunsili.com)


6. 调试

6.0. 固件下载到开发板

编译成功过后,固件下载到开发板,使用命令:
  1. scp bin/ramips/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin root@192.168.3.157:/tmp
  2. root@192.168.3.157's password:
  3. Permission denied, please try again.
  4. root@192.168.3.157's password:
  5. openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin                                  100% 8448KB 938.7KB/s   00:09
复制代码


6. 1. 升级固件

在开发板上执行以下命令:
sysupgrade /tmp/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin


查看EC20驱动是否成功
升级固件成功后, 开发板会自动重启,可以看到Openwrt系统启动打印信息:
  1. [    0.220000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[336]
  2. [    0.230000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[350]
  3. [    5.930000] usbcore: registered new interface driver usbfs
  4. [    5.930000] usbcore: registered new interface driver hub
  5. [    5.940000] usbcore: registered new device driver usb
  6. [    6.200000] usb usb1: no of_node; not parsing pinctrl DT
  7. [    6.310000] usb usb2: no of_node; not parsing pinctrl DT
  8. [    6.530000] usb 1-1: new high-speed USB device number 2 using ehci-platform
  9. [    6.690000] usb 1-1: no of_node; not parsing pinctrl DT
  10. [   44.830000] usbcore: registered new interface driver cdc_wdm
  11. [   44.890000] usbcore: registered new interface driver usbserial
  12. [   44.900000] usbcore: registered new interface driver usbserial_generic
  13. [   44.900000] usbserial: USB Serial support registered for generic
  14. [   44.960000] usbcore: registered new interface driver cdc_ether
  15. [   44.970000] usbcore: registered new interface driver cdc_ncm
  16. [   44.980000] usbcore: registered new interface driver cdc_subset
  17. [   45.040000] qmi_wwan 1-1:1.4 wwan0: register 'qmi_wwan' at usb-101c0000.ehci-1, WWAN/QMI device, 2a:d6:d2:f8:d3:30
  18. [   45.050000] usbcore: registered new interface driver qmi_wwan
  19. [   45.060000] usbcore: registered new interface driver rndis_host
  20. [   45.070000] usbcore: registered new interface driver cdc_mbim
  21. [   45.080000] usbcore: registered new interface driver option
  22. [   45.090000] usbserial: USB Serial support registered for GSM modem (1-port)
复制代码

启动后,可以使用命令查看
  1. dmesg | grep usb

  2. [    0.220000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[336]
  3. [    0.230000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[350]
  4. [    5.930000] usbcore: registered new interface driver usbfs
  5. [    5.930000] usbcore: registered new interface driver hub
  6. [    5.940000] usbcore: registered new device driver usb
  7. [    6.200000] usb usb1: no of_node; not parsing pinctrl DT
  8. [    6.310000] usb usb2: no of_node; not parsing pinctrl DT
  9. [    6.530000] usb 1-1: new high-speed USB device number 2 using ehci-platform
  10. [    6.690000] usb 1-1: no of_node; not parsing pinctrl DT
  11. [   44.830000] usbcore: registered new interface driver cdc_wdm
  12. [   44.890000] usbcore: registered new interface driver usbserial
  13. [   44.900000] usbcore: registered new interface driver usbserial_generic
  14. [   44.900000] usbserial: USB Serial support registered for generic
  15. [   44.960000] usbcore: registered new interface driver cdc_ether
  16. [   44.970000] usbcore: registered new interface driver cdc_ncm
  17. [   44.980000] usbcore: registered new interface driver cdc_subset
  18. [   45.040000] qmi_wwan 1-1:1.4 wwan0: register 'qmi_wwan' at usb-101c0000.ehci-1, WWAN/QMI device, 2a:d6:d2:f8:d3:30
  19. [   45.050000] usbcore: registered new interface driver qmi_wwan
  20. [   45.060000] usbcore: registered new interface driver rndis_host
  21. [   45.070000] usbcore: registered new interface driver cdc_mbim
  22. [   45.080000] usbcore: registered new interface driver option
  23. [   45.090000] usbserial: USB Serial support registered for GSM modem (1-port)
复制代码



查看usb枚举信息, 可用命令lsusb
  1. lsusb
  2. Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
  3. Bus 001 Device 002: ID 2c7c:0125
  4. Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
复制代码


查看dev下设备号 ls /dev
  1. ls /dev/tty*
  2. /dev/tty      /dev/ttyS0    /dev/ttyS1    /dev/ttyS2    /dev/ttyUSB0  /dev/ttyUSB1  /dev/ttyUSB2  /dev/ttyUSB3
复制代码


出现以上信息,表示驱动正常,下面可以启动拨号软件进行拨号。
其中 /dev/ttyUSB0  /dev/ttyUSB1  /dev/ttyUSB2  /dev/ttyUSB3为EC20枚举4个串口

6.2. 测试4G上网

参考:OpenWRT EC20 4G网卡自动拔号配置方法 -谷动谷力 (sunsili.com)

6.3. 测试打电话


参考:【linux】Openwert 环境下移远EC20 拔打电话播放文本语音方法...-谷动谷力 (sunsili.com)




+15

最近谁赞过

本帖被以下淘专辑推荐:

回复

使用道具 举报

沙发
发表于 2023-8-11 23:24:58 | 只看该作者
EC20有4种上网模式,可以通过如下指令切换模式。
cat /dev/ttyUSB2 &echo -e "AT+QCFG=\"usbnet\",0\r\n" > /dev/ttyUSB2   #设定模式
0-3echo -e "AT+CFUN=1,1\r\n" >/dev/ttyUSB2             #重启模块
四种模式分别为:
  • 0  RMNET接口,通过QMI工具发的QMI命令,获取公网IP。
  • 1  ECM接口,通过标准的CDC-ECM发起data call,是发送标准的ECM命令,获取局域网ip。
  • 2  MBIM接口,Mobile Broadband Interface Model,正宗的移动宽带接口模型,专门用于3G/4G/5G模块的,只在win8以上的windows上使用。
  • 3  RNDIS接口,基于USB实现RNDIS实际上就是TCP/IP over USB,就是在USB设备上跑TCP/IP,让USB设备看上去像一块网卡获取局域网ip。

在openwrt下能用的主要是013模式,其中Rmnet模式的qmi拨号设置非常繁琐,需要在源码注入多处驱动,还要自编译拨号程序,所以就没有试,网上有相关教程。设置比较简单是ECM、RNDIS模式,这两种模式在设置上没什么区别,都是获取的局域网IP,就是安装的插件不一样。上面建议的插件已经都包含了两种模式所需。
在luci->网络->接口,设置wan接口,在物理设置选项卡里面设置,发现多了一项硬件接口(usb0,或者wwan),选中它,保存并应用设置,过一会儿就会发现路由器wan口获取到了192.168..的局域网IP地址。通过设置wan6口有可能可以获取ipv6,在ec20模块需要设置:
echo -e "AT+CGDCONT=1,\"IPV4V6\",\"3gnet\"\r\n" > /dev/ttyUSB2   #设置上下文
echo -e "AT+CGACT=1,1\r\n" > /dev/ttyUSB2     #激活上下文
echo -e "AT+CFUN=1,1\r\n" >/dev/ttyUSB2

+10
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-27 09:19 , Processed in 0.148442 second(s), 47 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表