本帖最后由 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
- staticconst struct usb_device_id option_ids[] = {
- #if 1 //Added by Quectel
- { USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */
- { USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */
- { USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
- { USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
- { USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */
- #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
- static struct urb*usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
- int dir, void *ctx, char *buf, int len,void(*callback) (struct urb *))
- {
- ……
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) |dir,
- buf, len, callback, ctx);
- #if 1 //Added by Quectelfor Zero Packet
- if (dir == USB_DIR_OUT) {
- struct usb_device_descriptor*desc = &serial->dev->descriptor;
- if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
- urb->transfer_flags|= URB_ZERO_PACKET;
- if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
- urb->transfer_flags|= URB_ZERO_PACKET;
- if (desc->idVendor ==cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
- urb->transfer_flags|= URB_ZERO_PACKET;
- if (desc->idVendor ==cpu_to_le16(0x2C7C))
- urb->transfer_flags|= URB_ZERO_PACKET;
- }
- #endif
- return urb;
- }
复制代码
2.1.2. 增加休眠后唤醒接口 Add Reset Resume
修改内核源码文件 File: [KERNEL]/drivers/usb/serial/option.c - static struct usb_serial_driveroption_1port_device = {
- ……
- #ifdef CONFIG_PM
- .suspend = usb_wwan_suspend,
- .resume = usb_wwan_resume,
- #if 1 //Added by Quectel
- .reset_resume = usb_wwan_resume,
- #endif
- #endif
- }
复制代码
2.2.5 使用QMI WWAN Use GobiNet or QMI WWAN File: [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
- //Quectel UC20'sinterface 4 can be used as USB Network device
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
- serial->dev->descriptor.idProduct ==cpu_to_le16(0x9003)
- &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
- return -ENODEV;
- //Quectel EC20's interface4 can be used as USB Network device
- if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
- serial->dev->descriptor.idProduct== cpu_to_le16(0x9215)
- &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
- return -ENODEV;
- //QuectelEC21&EC25&EC20 R2.0's interface 4 can be used as USB Network device
- if(serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)
- &&serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
- return -ENODEV;
- #endif
- /* Store device id so we can use it duringattach. */
- usb_set_serial_data(serial, (void *)id);
- return 0;
- }
复制代码
3. 修改内核增加QMI WWAN驱动支持QMI WWAN Driver
3.1.1 增加VID和PID Add VID and PID
修改文件 "[KERNEL]/drivers/net/usb/qmi_wwan.c".
- static const struct usb_device_idproducts[] = {
- #if 1 //Added by Quectel
- #ifndef QMI_FIXED_INTF
- /* map QMI/wwan function by a fixed interface number */
- #define QMI_FIXED_INTF(vend, prod, num) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_INFO, \
- .idVendor = vend, \
- .idProduct = prod, \
- .bInterfaceClass = 0xff, \
- .bInterfaceSubClass = 0xff, \
- .bInterfaceProtocol = 0xff, \
- .driver_info = (unsigned long)&qmi_wwan_force_int##num,
- #endif
- { QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */
- { QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 */
- { QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25/EC20R2.0 */
- { QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */
- #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" - #include <linux/usb/usbnet.h>
- #include <linux/usb/cdc-wdm.h>
- #if 1 //Added by Quectel
- #include <linux/etherdevice.h>
- struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, structsk_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, structsk_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 IPv4or IPv6 headers */
- static bool possibly_iphdr(const char*data)
- {
- return (data[0] & 0xd0) == 0x40;
- }
- #endif
- #endif
- /* if follow function exist, modify itas 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 EC21&EC25&EC20 R2.0work 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 CDCDTR
- intf->cur_altsetting->desc.bInterfaceNumber,
- NULL, 0, 100);
- }
- #endif
- err:
- return status;
- }
- /* if follow struct exist, modify itas below */
- static const struct driver_info qmi_wwan_info =
- {
- ……
- #if 1 //Added by Quectel
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))
- .tx_fixup =qmi_wwan_tx_fixup,
- #endif
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
- .rx_fixup =qmi_wwan_rx_fixup,
- #endif
- #endif
- }
- /* if follow struct exist, modify itas below */
- static const struct driver_infoqmi_wwan_force_int4 = {
- ……
- #if 1 //Added by Quectel
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))
- .tx_fixup =qmi_wwan_tx_fixup,
- #endif
- #if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))
- .rx_fixup =qmi_wwan_rx_fixup,
- #endif
- #endif
- };
复制代码
4. 编译配置
使用图形化菜单配置openwrt, 输入命令:
配置项:
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命令编译:
编译方法
参考:
【openwrt】OpenWrt编译 – 说明-谷动谷力 (sunsili.com)
【Openwrt】开发环境搭建 编译openwrt源码-谷动谷力 (sunsili.com)
【openwrt学习笔记一】从搭建编译环境到编译openwrt全过程-谷动谷力 (sunsili.com)
6. 调试
6.0. 固件下载到开发板
编译成功过后,固件下载到开发板,使用命令: - scp bin/ramips/openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin root@192.168.3.157:/tmp
- root@192.168.3.157's password:
- Permission denied, please try again.
- root@192.168.3.157's password:
- 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系统启动打印信息: - [ 0.220000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[336]
- [ 0.230000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[350]
- [ 5.930000] usbcore: registered new interface driver usbfs
- [ 5.930000] usbcore: registered new interface driver hub
- [ 5.940000] usbcore: registered new device driver usb
- [ 6.200000] usb usb1: no of_node; not parsing pinctrl DT
- [ 6.310000] usb usb2: no of_node; not parsing pinctrl DT
- [ 6.530000] usb 1-1: new high-speed USB device number 2 using ehci-platform
- [ 6.690000] usb 1-1: no of_node; not parsing pinctrl DT
- [ 44.830000] usbcore: registered new interface driver cdc_wdm
- [ 44.890000] usbcore: registered new interface driver usbserial
- [ 44.900000] usbcore: registered new interface driver usbserial_generic
- [ 44.900000] usbserial: USB Serial support registered for generic
- [ 44.960000] usbcore: registered new interface driver cdc_ether
- [ 44.970000] usbcore: registered new interface driver cdc_ncm
- [ 44.980000] usbcore: registered new interface driver cdc_subset
- [ 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
- [ 45.050000] usbcore: registered new interface driver qmi_wwan
- [ 45.060000] usbcore: registered new interface driver rndis_host
- [ 45.070000] usbcore: registered new interface driver cdc_mbim
- [ 45.080000] usbcore: registered new interface driver option
- [ 45.090000] usbserial: USB Serial support registered for GSM modem (1-port)
复制代码
启动后,可以使用命令查看
- dmesg | grep usb
- [ 0.220000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[336]
- [ 0.230000] drivers/phy/phy-ralink-usb.c:ralink_usb_phy_probe[350]
- [ 5.930000] usbcore: registered new interface driver usbfs
- [ 5.930000] usbcore: registered new interface driver hub
- [ 5.940000] usbcore: registered new device driver usb
- [ 6.200000] usb usb1: no of_node; not parsing pinctrl DT
- [ 6.310000] usb usb2: no of_node; not parsing pinctrl DT
- [ 6.530000] usb 1-1: new high-speed USB device number 2 using ehci-platform
- [ 6.690000] usb 1-1: no of_node; not parsing pinctrl DT
- [ 44.830000] usbcore: registered new interface driver cdc_wdm
- [ 44.890000] usbcore: registered new interface driver usbserial
- [ 44.900000] usbcore: registered new interface driver usbserial_generic
- [ 44.900000] usbserial: USB Serial support registered for generic
- [ 44.960000] usbcore: registered new interface driver cdc_ether
- [ 44.970000] usbcore: registered new interface driver cdc_ncm
- [ 44.980000] usbcore: registered new interface driver cdc_subset
- [ 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
- [ 45.050000] usbcore: registered new interface driver qmi_wwan
- [ 45.060000] usbcore: registered new interface driver rndis_host
- [ 45.070000] usbcore: registered new interface driver cdc_mbim
- [ 45.080000] usbcore: registered new interface driver option
- [ 45.090000] usbserial: USB Serial support registered for GSM modem (1-port)
复制代码
查看usb枚举信息, 可用命令lsusb - lsusb
- Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
- Bus 001 Device 002: ID 2c7c:0125
- Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
复制代码
查看dev下设备号 ls /dev - ls /dev/tty*
- /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)
|