驱动移植

​ 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