驱动移植
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