驱动移植

​ 4G模块加载 USB 转串口驱动option后会在/dev/下创建ttyUSB0、ttyUSB1 和 ttyUSB2 等设备文件。如果没有出现,需要在drivers/usb/serial/option.c里添加VID(Vendor ID)与PID(Product ID)

USB 转串口驱动修改

通过lsusb可得到


Bus 001 Device 002: ID 1a86:8091
Bus 001 Device 001: ID 1d6b:0002
Bus 002 Device 001: ID 1d6b:0002
Bus 003 Device 001: ID 1d6b:0002
Bus 001 Device 004: ID 2c7c:0904

在drivers/usb/serial/option.c里添加

static const struct usb_device_id option_ids[] = {
	{ USB_DEVICE(0x2C7C, 0x6002) }, /* Quectel EC800M */ 
	{ USB_DEVICE(0x2C7C, 0x0904) }, /* Quectel EC800G */ 
	{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */ 
        ..
}


static int option_probe(struct usb_serial *serial,
			const struct usb_device_id *id)
{
    struct usb_interface_descriptor *iface_desc =
				&serial->interface->cur_altsetting->desc;
	struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
	const struct option_blacklist_info *blacklist;

#if 1 //Added byQuectel
	if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
		__u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct);
		struct usb_interface_descriptor *intf = &serial->interface->cur_altsetting->desc;

		if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass == 0x42) {
			//ECM, RNDIS, NCM, MBIM, ACM, UAC, ADB
			return -ENODEV;
		}

		if ((idProduct&0xF000) == 0x0000) {
			//MDM interface 4 is QMI
			if (intf->bInterfaceNumber == 4 && intf->bNumEndpoints == 3
				&& intf->bInterfaceSubClass == 0xFF && intf->bInterfaceProtocol == 0xFF)
				return -ENODEV;
		}
	}

#endif
	.......
}

添加零包机制

根据 USB 协议的要求,通过添加如下语句在 bulk-out 传输过程中添加处理零包的机制: 高于 2.6.34 的 Linux 内核版本,需在[KERNEL]/drivers/usb/serial/usb_wwan.c 文件中添加以下语句。低于 2.6.35 的 Linux 内核版本,需在[KERNEL]/drivers/usb/serial/option.c 文件中添加。

static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
				      int endpoint,
				      int dir, void *ctx, char *buf, int len,
				      void (*callback) (struct urb *))
{
	struct usb_serial *serial = port->serial;
	struct urb *urb;

	urb = usb_alloc_urb(0, GFP_KERNEL);	/* No ISO */
	if (!urb)
		return NULL;

	usb_fill_bulk_urb(urb, serial->dev,
			  usb_sndbulkpipe(serial->dev, endpoint) | dir,
			  buf, len, callback, ctx);
#if 1 //Added by Quectel for Zero Packet
	if (dir == USB_DIR_OUT) {
	struct usb_device_descriptor *desc = &serial->dev->descriptor;
	if (desc->idVendor == cpu_to_le16(0x2C7C))
	urb->transfer_flags |= URB_ZERO_PACKET;
}
#endif

	return urb;
}

添加 Reset-resume 机制

static struct usb_serial_driver option_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
};

确保内核开启CONFIG_USB_SERIAL = y

常用命令

udhcpc

​ udhcpc是Busybox的非常小的DHCP的客户端,所谓的DHCP(Dynamic Host Configuration Protocol)是一个局域网的网络协议,使用UDP协议进行工作。1:用于给内部网或网络服务供应商自动分配 IP 地址;2:用户用于内部网管理员作为对所有计算机作中央管理的手段

  • -i 指定网卡
  • -s 指定发生dhcp事件时运行的脚本

租约

​ DHCP Server 临时把一个 IP 地址以及相关网络参数 “租” 给客户端使用一段时间。ubs0 使用dhcpc申请地址的时候,4G模块内部的DHCP Server 可能会返回如下内容:

IP:       10.49.93.93
Netmask:  255.255.255.0
Gateway:  10.49.93.1
DNS:      8.8.8.8
Lease:    3600 秒

这个Lease就租约时间,相当于"10.49.93.93 这个 IP 给你用 3600 秒。" 租约到期之前,udhcpc会负责续约,调用脚本

#!/bin/sh
# generated by nvr_test (WanFailover): usb0 lease recorder
case "$1" in
    deconfig)
        ifconfig usb0 0.0.0.0
        rm -f /tmp/usb0.lease
        ;;
    bound|renew)
        NETMASK=""
        [ -n "$subnet" ] && NETMASK="netmask $subnet"
        ifconfig usb0 $ip $NETMASK
        {
            echo "router $router"
            echo "dns $dns"
        } > /tmp/usb0.lease.tmp
        mv /tmp/usb0.lease.tmp /tmp/usb0.lease
        ;;
esac
exit 0
  • bound:第一次成功拿到租约
  • renew:已有租约续租成功
  • deconfig:租约失效,需要把地址撤掉