本文讲述了如何移植4G模块到rk3568开发板并实现上网功能
先将开发板上电,输入命令lsusb
,看有没有出现,如果出现了Bus 001 Device 003: ID 2c7c:6005
,则设备树大概率是没问题的。如果没有,则表明4G模块没有被识别到。本文仅针对驱动进行讲解,不涉及设备树方面。
1 USB转串口驱动
1.1 添加VID和PID
为了识别模块,需将模块的 VID 和 PID 信息添加到kernel/drivers/usb/serial/option.c 文件中,该4G模块使用的是移远的EC200A-CN,我们可以查询到其 VID为0x2c7c 和 PID为0x6005。
static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(0x1286, 0x4e3c) },
#if 1 //此处为添加的代码,到endif结束。
{ USB_DEVICE(0x2C7C, 0x6005) },
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR, .idVendor = 0x2C7C },
#endif
1.2 使用USBNet驱动
在1.1添加VID和PID中,配置会使模块的所有 USB 接口均绑定 USB 转串口 option 驱动程序,导致 USBNet 驱动程序接口无法工作。我们需要添加以下语句以防止 USBNet 驱动程序接口绑定 USB 转串口 option 驱动程序。
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;
unsigned long device_flags = id->driver_info;
#if 1 //此处为添加的代码,到endif结束。
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
__u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct);
//printk("aaaaaaaaaaaaaaaaaaddfasdf");
//print("Detected device with Product ID: 0x%04X\n", 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
/* Never bind to the CD-Rom emulation interface */
if (iface_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE)
return -ENODEV;
1.3 修改内核配置
我们需要检查kernel的“.config”文件,查看是否启用以下配置项:
CONFIG_USB_SERIAL;
CONFIG_USB_SERIAL_WWAN;
CONFIG_USB_SERIAL_OPTION;
如果没有启用,则需要进行添加配置项,使用命令“make menuconfig ARCH=arm64”进行配置。
1.4 添加零包机制
根据 USB 协议的要求,通过在kernel/drivers/usb/serial/usb_wwan.c文件中添加如下语句在 bulk-out 传输过程中添加处理零包的机制。
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;
……
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
#if 1 //此处为添加的代码,到endif结束。
if (dir == USB_DIR_OUT) {
//struct usb_device_descriptor *desc = &serial->dev->descriptor;
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C))
urb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
if (intfdata->use_zlp && dir == USB_DIR_OUT)
urb->transfer_flags |= URB_ZERO_PACKET;
1.5 添加Reset-resume机制
部分 USB 主机控制器或 USB hub 在 MCU 进入 Suspend/Sleep(挂起/睡眠)模式时会发生掉电或复位,并且在 MCU 退出Suspend/Sleep模式后不能使模块恢复。需要通过在kernel/drivers/usb/serial/option.c文件中添加以下语句来启用reset-resume机制。
static struct usb_serial_driver option_1port_device = {
……
#ifdef CONFIG_PM
.suspend = usb_wwan_suspend,
.resume = usb_wwan_resume,
#if 1 //此处为添加的代码,到endif结束。
.reset_resume = usb_wwan_resume,
#endif
#endif
};
2 USB转串口结果验证
先看模块是否成功连接开发板。成功连接开发板的日志信息如下图所示。
使用命令busybox microcom /dev/ttyUSB1 -s 115200
回车,输入AT命令进行验证4G模块和SIM卡是否都能被检测到。
输入AT返回ok,则表示AT命令可用。
AT
输入AT+CPIN?,返回READY,表示检测到SIM卡。
AT+CPIN?
其余AT命令可以参照移远给出的AT命令手册。
3 联网
该4G模块是可以通过ECM驱动的方式进行上网的。
需要开启以下配置项。
CONFIG_USB_NET_DRIVERS
CONFIG_USB_USBNET
CONFIG_USB_NET_CDCETHER
ECM驱动上网前需要进行网卡绑定。步骤如下:
在控制台输入命令
busybox microcom /dev/ttyUSB1 -s 115200
输入命令进行测试。
at+qnetdevctl=?
输入命令进行联网
at+qnetdevctl=1,1,1
结果如下所示
本文参考了移远给出的用户手册以及AT命令。如有侵权,请联系作者进行删除。