USB Serial
如果你用的是ec20**********并且需要USB串口的启动,请细度此章否则直接跳过。。。。
1.1 添加VID和PID
VID和PID其实就相当于USB硬件的识别ID系统也是通过他们来找到你的EC20设备的,修改Kernel中文件来添加,方法如下
注意:如果其他的usb设备也用到了这些资源的话就把冲突的地方删掉,比如在[KERNEL]/drivers/usb/serial/qcserial.c中和[KERNEL]/drivers/net/usb/qmi_wwan.c文件中都有对(0x05c6, 0x9215)ID的重复描述,官方文档是让删掉的,我没有删试了没事,想来应该是我的板卡上没有这些设备的原因。
1.2添加 Zero Packet Mechanism
通过USB协议的要求,你需要在bulkout传输添加加工零包的机制(直接翻译过来的照着做就可以了)。
如果你的Linuxkernel版本新于2.6.34,在文件File: [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(0x05C6) && desc->idProduct == cpu_to_le16(0x9090))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x2C7C))
urb->transfer_flags |= URB_ZERO_PACKET;
}
#endif
return urb;
}
如果linux版本在2.6.35以下的和上述操作不一样,现在应该很少有人用了就不说了。
1.3添加Reset Resume回调
这一块是和Linux的设备电源管理相关的,当单片机进入休眠/休眠时,一些USB主机控制器/ USB集线器将失去电源或复位。
模式,当MCU退出挂起/休眠模式时,它们不能恢复USB设备;相反,它们将操作重置恢复。您应该添加以下语句
Linux kernel 版本高于3.4的在File: [KERNEL]/drivers/usb/serial/option.c文件中添加:
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
};
Linux kernel 版本低于3.5的在File: [KERNEL]/drivers/usb/serial/usb-serial.c文件中添加:
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
#if 1 //Added by Quectel
.reset_resume = usb_serial_resume,
#endif
.no_dynamic_id = 1,
.supports_autosuspend = 1,
};
1.4Use GobiNet or QMI WWAN
如果用着两个驱动还需要修改File: [KERNEL]/drivers/usb/serial/option.c文件(kernel高于2.6.30):这里值得注意一下
文档中base的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
//Quectel UC20's interface 4 can be used as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC20's interface 4 can be used as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) &&
serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC25&EC21&EC20 R2.0&EG91&EG95&EG06&EP06&EM06&BG96's interface 4 can be
used as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
#endif
/* Store device id so we can use it during attach. */
usb_set_serial_data(serial, (void *)id);
return 0;
}
我文件中的:
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
.......
#if 1 //Added by Quectel
//Quectel UC20's interface 4 can be used as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6)&&
serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC20's interface 4 can be used as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6)&&
serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
//Quectel EC25&EC21&EC20 R2.0&EG91&EG95&EG06&EP06&EM06&BG96's interface 4 can beused as USB Network device
if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)
&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
return -ENODEV;
#endif
data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->send_setup = option_send_setup;
spin_lock_init(&data->susp_lock);
data->private = (void *)id->driver_info;
return 0;
}
不知道大家用的内核是那一版,看到和描述的不一样仔细看一下就行了 上面添加的都是匹配的逻辑,下面是set的功能,一看便知
不需要看懂。我试过是可以的。
1.5 menuconfig
menuconfig如下图 设置好了保存
1.6试验
启动时有:
编译之后,把kernel跑起来就会发现如图:
dev目录下已经有了ttyUSB*设备了,证明已经完成了 USB Serial的驱动。
二 、GobiNet 驱动
当使用Gobinet驱动移远模块时,Gobinet将会创建一个网络设备(ethX)和一个QMI channel(qcqmiX),
网络设备用于网络传输 QMI channel要用于QMI 的信息交互。
2.1将移远模块提供的源码放入到Kernel中
linux2.6以后的版本将Gobinet驱动的源码放到/[kernel]/drivers/usb/net/中。如果是把gobinet编译到内核中,可以忽略
GoniNet源码中的Makefile,直接将源码中的.c和.h文件拷贝到上述目录中。
2.2 make menuconfig
2.3添加Makefile文件中的目标和依赖
在【KERNEL】/drivers/net/usb/Makefile文件中添加:
obj-y += GobiNet.o
GobiNet-objs := GobiUSBNet.o QMIDevice.o QMI.o
2.4试验
将编译后的Image在板子上跑起来可以看到dev下多了一个qcqmil:
说明GobiNet驱动已经生效了。
三、拨号程序
拨号程序仍然使用移远提供的quectel-CM,这是一个4g连接管理程序,这里没什么说的,直接下载源码交叉编译之
得到可执行bin“quectel-CM”,把这个bin放到板卡上启动后上述一、二驱动没有问题的情况下直接执行该bin就可以
实现拨号:
运行:
# quectel-CM –s ctnet &
[01-01_00:26:45:355] Quectel_ConnectManager_SR01A01V10
[01-01_00:26:45:356] ./quectel-CM profile = ctnet///, pincode =
[01-01_00:26:45:357] Find qmichannel = /dev/qcqmi2
[01-01_00:26:45:358] Find usbnet_adapter = eth2
。。。。。
[01-01_00:26:45:937] udhcpc (v1.20.2) started
[01-01_00:26:45:956] Sending discover...
[01-01_00:26:45:960] Sending select for 10.172.27.151...
[01-01_00:26:45:964] Lease of 10.172.27.151 obtained, lease time 7200
[01-01_00:26:45:984] deleting routers
route: SIOCDELRT: No such process
[01-01_00:26:46:003] adding dns 61.132.163.68
[01-01_00:26:46:003] adding dns 202.102.213.68
[01-01_00:26:45:560] requestGetSIMStatus SIMStatus: SIM_READY
可以ping通外网就说明拨号成功了!