问题描述:项目需要用ARM板驱动金笛wavecom GSM模块发短信,该GSM模块为USB接口,内部采用PL2303HX芯片转为RS232接口实现AT指令协议。
将GSM模块插入ARM板的USB口,发现没有驱动。
进一步解决步骤:将GSM模块插入PC机的USB口,在Ubuntu 10.04下可以正确的识别为/dev/ttyUSB0。用minicom测试,功能正常。
由于没有ARM Linux驱动,尝试寻找ARM Linux 的内核驱动模块。上网查找资料,PL2303芯片驱动应该已经集成到了Linux的内核源码中,只是ARM Linux 把它剪裁掉了,需要重新编译为内核模块,并加载。
我的ARM环境为AT91SAM9261 CPU,Linux 版本为2.6.27,开发机为ubuntu 10.04。
去ATmel官方网站下载Linux内核源代码:
http://www.at91.com/linux4sam/bin/view/Linux4SAM/LinuxKernel
找到VANILLA Linux Kernel 的源代码包链接并下载: http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.27.tar.bz2 ,解压到home下。在主文件夹中多了一个linux-2.6.27文件夹。
一并下载9261的内核配置文件ftp://www.at91.com/pub/linux/2.6.27-at91/at91sam9261ek_defconfig,下载到linux-2.6.27下,并且命名为.config
cd linux-2.6.27
make ARCH=arm menuconfig
在Device Drivers->USB Support --->USB Serial Converter Support选项,默认是没选中的。在该项中按M键,回车,就可以进入到下级菜单,找到USB Prolific 2303 Single Port Serial Driver项,按M选中,将本级的其它选项的M清空。M的意思是按模块编译,*是编译集成进内核。我们不需要编译整个内核。
设置好之后,保存退出。
在执行以下命令:
make ARCH=arm CROSS_COMPILE=/usr/local/arm/arm-2008q1/bin/arm-linux- modules
编译完成后,在drivers/usb/serial下,生成了pl2303.ko文件。将该文件下载到ARM板上,在ARM命令行执行
insmod pl2303.ko
可以通过dmesg查看驱动模块加载情况:
# dmesg
usbserial: USB Serial support registered for pl2303
usbcore: registered new interface driver pl2303
pl2303: Prolific PL2303 USB to serial adaptor driver
说明驱动已经成功加载,插入GSM模块,会在/dev下出现ttyUSB0设备。
如果在这里出现invalid module format的错误,是因为在 make menuconfig的时候,没有正确配置CPU型号。下载对应的defconfig文件(本文对应的是at91sam9261ek_defconfig)即可解决问题。
至此,驱动安装成功。
在ARM上调试串口,我使用了一个简化版的类似minicom的源代码。下载地址:http://plunk.org/~grantham/serial.cpp
但是,进一步发现,通过ARM上的ttyUSB0与GSM模块无法通讯,表现为数据发不过去,也收不到任何应答。为了确定问题,用另一个PL2303的USB转RS232的转接头接在ARM板上,另一端通过串口数据线连接到PC上,在PC上用串口调试助手调试,居然可以正常的收发数据。
GSM连PC,正常,说明GSM模块没问题,ARM连PC,也正常,说明ARM和驱动也没问题,唯独GSM连ARM不正常。怪哉!于是将GSM模块拆开,用示波器测量PL2303芯片的RS232输出引脚电平,当GSM连PC时,输出电平波形正常,当GSM连ARM时,没有输出电平。也就是说,2303芯片根本就没有向GSM模块输出信号。当然也不会有任何回应。
问题指向了pl2303的linux驱动。
打开drivers/usb/serial/pl2303.c文件,发现以下一段代码:
enum pl2303_type {
type_0, /* don't know the difference between type 0 and */
type_1, /* type 1, until someone from prolific tells us... */
HX, /* HX version of the pl2303 chip */
};
再次在ARM板上,以调试模式加载驱动模块:
insmod pl2303.ko debug=1
dmesg
发现识别为device type = 1,但是在芯片的标签上,明确标明型号为“PL2303HX”。就是说驱动程序把芯片的型号识别错了。
经过仔细阅读代码和反复调试,最终将以下代码
if (serial->dev->descriptor.bDeviceClass == 0x02)
type = type_0;
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
type = HX;
else if (serial->dev->descriptor.bDeviceClass == 0x00)
type = type_1;
else if (serial->dev->descriptor.bDeviceClass == 0xFF)
type = type_1;
if (serial->dev->descriptor.bDeviceClass == 0x02)
type = type_0;
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
type = HX;
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x02)
type = HX;
else if (serial->dev->descriptor.bDeviceClass == 0x00)
type = type_1;
else if (serial->dev->descriptor.bDeviceClass == 0xFF)
type = type_1;