問題描述:項目需要用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
我的交叉編譯toolchain的路徑是/usr/local/arm/arm-2008q1/,這裡要修改成你自己的路徑。
編譯完成後,在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 */
};
也就是說驅動裡可以識别pl2303晶片有三種類型type_0, type_1和HX。而驅動的作者也不知道幾個類型之間有什麼差別。
再次在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;
重新編譯pl2303驅動,至此,問題全部解決。