目录
一、Linux USB架构
USB 是一种分层总线结构。 USB 设备与主机之间的数据传输由 USB 控制器控制。 Linux USB 驱动程序架构如下图所示。 Linux USB 主机驱动包括三部分: USB 主机控制器驱动、 USB 核心和 USB 设备驱动。
USB 主机控制器驱动在分层结构的最底层,直接与硬件交互。 USB 核心是整个 USB 主机驱动的核心,用于管理 USB 总线、 USB 总线设备和 USB 总线带宽;它为 USB 设备驱动程序提供接口,应用程序可以通过这些接口访问 USB 系统文件。
USB 设备驱动程序与应用程序交互并提供用于访问特定 USB 设备的接口。
其实这一部分的讲析,在你调试的4g模块文档中也有,在此,不再作过多描述。
以下是我配置4g的原理图:
二、内核配置
A.相关配置文件:
dts文件
configs/rockchip_defconfig
option.c
usb_wwan.c
qmi_wwan_q.c
B.驱动配置
1.dts配置
rk_modem: rk-modem {
compatible="4g-modem-platdata";
4G,vbat-gpio = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; //4g_en
4G,power-gpio = <&gpio3 RK_PC7 GPIO_ACTIVE_LOW>; //4g_disabled
4G,reset-gpio = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>;//4g_rst
pinctrl-0 = <&mobile_4g>;
pinctrl-names = "default";
status = "okay";
};
其实这部分配置貌似不需要配置的很详细,只配置一个4g的供电就行了。这个compatible用到的驱动lte_rm310.c,这部分其实并没有按照驱动认真的跑,这个默认的源文件还是有问题的。
2.添加pid/vid
为了识别模块,需将模块的 VID 和 PID 信息添加到[KERNEL]/drivers/usb/serial/option.c 文件中,对应的 VID 和 PID,如下所示:
static const struct usb_device_id option_ids[] = {
#if 1 //Added by Quectel
{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC20 R2.0/EC20 R2.1/EC25/EG25-G/EM05 */
{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21/EG21-G */
{ USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */
{ USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
{ USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */
{ USB_DEVICE(0x2C7C, 0x0512) }, /* Quectel EG12/EM12/EG18 */
{ USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */
{ USB_DEVICE(0x2C7C, 0x0700) }, /* Quectel BG95/BG77/BG600L-M3/BC69 */
{ USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
{ USB_DEVICE(0x2C7C, 0x0415) }, /* Quectel AG15 */
{ USB_DEVICE(0x2C7C, 0x0452) }, /* Quectel AG520R */
{ USB_DEVICE(0x2C7C, 0x0455) }, /* Quectel AG550R */
{ USB_DEVICE(0x2C7C, 0x0620) }, /* Quectel EG20 */
{ USB_DEVICE(0x2C7C, 0x0800) }, /* Quectel RG500Q/RM500Q/RG510Q/RM510Q */
{ USB_DEVICE(0x2C7C, 0x6002) }, // ec200s/ec200m/ec200n/ec600n/ec600m/ec800m/ec800n
{ USB_DEVICE(0x2C7C, 0x6005) }, // Quectel EC200A
#endif
3.使用USBNET驱动
前面第二点中配置使模块的所有 USB 接口均绑定 USB 转串口 option 驱动程序,导致 USBNet 驱动程序接口无法工作。用户可以添加以下语句来防止 USBNet 驱动程序接口绑定 USB 转串口 option 驱动程序。
高于 2.6.30 的 Linux 内核版本,用户可以在[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
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
/* Store device id so we can use it during attach. */
usb_set_serial_data(serial, (void *)id);
return 0;
}
3.修改内核配置
用户需启用以下配置项。
CONFIG_USB_SERIAL
CONFIG_USB_SERIAL_WWAN
CONFIG_USB_SERIAL_OPTION
4.添加零包机制
根据 USB 协议的要求,通过添加如下语句在 bulk-out 传输过程中添加处理零包的机制:
高于 2.6.34 的 Linux 内核版本,需在[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 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;
}