基于嵌入式Linux的MPC850 USB 驅動程序的實現
更新時間: 2007-05-08 16:02:12來源: 粵嵌教育瀏覽量:1001
摘 要: 本文介紹了嵌入式Linux下設備驅動程序的編寫原理,并闡述了在Linux下MPC850 USB的驅動程序的具體實現。
關鍵詞: 嵌入式Linux;驅動程序;USB;主控制器
Linux驅動程序的基本原理
Linux下開發設備驅動程序的原理較之Windows系統來說結構層次簡單明了。Linux操作系統中定義了三種設備,即字符設備、塊設備和網絡設備。字符設備是指存取時沒有緩存的設備。塊設備的讀寫都有緩存來支持,并且塊設備必須能夠隨機存取,字符設備則沒有這個要求,USB設備主要通過快速串行通信來讀寫數據,一般把它作為字符設備處理。
掛在Linux系統上的每個設備都被描述為設備驅動程序文件,一些與設備有關的設備參數文件被保存在/dev目錄下。用戶自己提供或編寫設備驅動時,也需要在/dev目錄下有一個設備文件。設備驅動程序可以分為三個主要組成部分:一是自動配置和初始化子程序 二是服務于I/O請求的子程序 三是中斷服務子程序。
用戶對設備的訪問主要有如下函數:
open,打開設備,典型的用法如下:open("/dev/xxx", flag); flag指定打開的參數,例如讀寫屬性等;open函數返回一個整數fd句柄,如果fd小于0,表示打開錯誤。
read, write讀寫函數,用法如下:read(int fd, char *buf, char length,..)。
ioctrl設備控制函數,用戶各類設備的特殊控制。
驅動程序的設計就是實現上述四個函數與外加一個設備初始化函數。這些函數在設備驅動程序中可以是dev_init(),dev_open(),dev_read(), dev_write(),dev_ioctrl()等。聲明一個稱之為file operation的結構體將用戶級的open等函數與設備dev_open()等函數聯系起來。例如
static struct file_operations dev-xxx_fops = {
NULL, /* lseek */
dev_read, /* read */
dev_write, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
dev_open,
dev_close,
NULL /* fsync */
};
為了將用戶驅動程序與內核結合起來,首先向內核注冊,請求內核分配主設備號與次設備號;二是注冊中斷,以便外部設備向CPU發出中斷后能夠處理設備中斷函數。這些操作的一半在dev_init()函數內完成。dev_init()函數除了注冊設備與注冊中斷外,還要完成設備特有寄存器初始化等操作。驅動程序與內核結合起來后,為了讓應用程序能夠訪問該設備,還需要做一些額外的工作。前面提到,應用程序對設備的訪問是通過訪問文件的形式實現的,所以要建立一個文件節點與該設備相關聯,使用命令 :
mknod /dev/xxx option major minor
可以實現上述的關聯。該命令的含義是建立一個/dev/xxx的文件節點,并且把特定主設備號與次設備號的設備與該節點關聯。Option選項指定設備的類型,字符型還是塊設備。有了關聯后,應用程序要訪問該設備,只要調用open (“dev/xxx”,...)函數即可。
MPC850 USB
MPC850是Motorola公司生產的32位嵌入式通信處理器,具有強大的通信和網絡協議處理能力,特別適用于嵌入式通信和網絡系統,它提供的功能與MPC860相似,在MPC860系統功能基礎上增加了對USB的支持。
MPC850 USB不提供任何OHCI和UHCI接口,但它有作為主機控制器必須的功能。MPC850 USB沒有與根集線器連接,當不止一個USB設備時需接一個外部集線器。在MPC850中主控制器類似于功能單元(function),它不遵循OHCI和UHCI標準。USB控制器由一個發送模塊、一個接收模塊、兩個協議狀態機構組成。一個協議機構執行功能狀態表,另一個執行主機狀態表。USB控制器可完成一個USB功能端點,一個USB主機和兩種檢測的任務。主控制器的特點如下:
USB驅動程序由主控制驅動程序、USB子系統、USB設備驅動程序。
在Linux系統中存在一個連接USB設備驅動程序和主控制器驅動程序的子系統USBcore,它通過定義一些數據結構、宏和功能函數來抽象所有的硬件設備。USBcore提供了為硬件處理的所有下層接口,包含所有USB設備驅動和主機控制的通用程序,可稱為UpperAPI和LowerAPI。USB子系統提供與設備驅動程序的接口,讀取并解析USB設備描述符,配置描述符,為USB設備分配的地址,使用默認的配置來配置設備,支持基本的USB命令請求,連接設備與相應的驅動程序,轉發設備驅動程序的數據包。
雖然前面講了驅動程序有兩種加載模式,但是,如果 USBcore或主控制器驅動程序是內核模式,USB設備驅動程序就以模塊方式加載。用usb_register和usb_deregister向USBcore子系統注冊和注銷驅動程序。所有USB驅動程序都有一個向子系統注冊的結構。
struct usb_driver{
const char *name; /*模塊名字*/
void *(*probe, struct usb_device*, unsigned int); /*probe 功能入口點*/
void (*disconnect, struct usb_device*, void*); /*disconnect功能入口點*/
struct list_head driver_list; /*子系統內部初始化*/
struct file_operations fops; /對驅動函數文件列表*/
int minor;
}
在高速USB中時序安排是以1幀為基本要素的,每1ms為1幀,在每幀要產生并發送SOF包之外,還需要一個微碼通道。同步傳輸和中斷傳輸占90%的有效帶寬,控制傳輸占10%,剩下的為塊傳輸,如下表所示:
SOF Isochronous Interrupt Control Bulk
控制傳輸完成了設備的配置,設備的輪流檢測是由中斷傳輸完成,大量的數據傳輸由塊傳輸和同步傳輸完成。
MPC850是不支持這樣的時序調度的,我們用1ms的時序器產生一個中斷并在軟件中運行這個調度。每個SOF時序里我們都加入一個SOF包到tx列表中,并監視發送包的列表,包是依據優先權來加入的。在每幀開始時,檢查未處理事務,將符合優先級的隊列元素放到當前幀中。驅動程序跟蹤處理事務的設備,并不再向它發送事務。程序中用一個隊列結構來完成這一調度的。如: 下面是分派隊列元素到發送幀的結構。
struct m8xxhci_qe *
take_from_current_frame(int qtype)
{
struct m8xxhci_private *hp = (struct m8xxhci_private *)m8xxhci_ptr;
unsigned long flags;
struct list_head *list;
struct m8xxhci_qe *qe = NULL;
┋
if (!list_empty(list)) {
┋
qe->on_frame_list = 0;
┋
}
spin_unlock_irqrestore(&framelist_lock, flags);
return qe;
}
MPC850 USB主控制器的有些任務是硬件不支持的,必須由軟件來實現。例如,發生錯誤及錯誤恢復后的重傳、每秒產生和傳輸SOF、CRC5的產生等。這些功能是通過相應的結構體來完成,主控制器驅動向USBcore數據結構注冊它的功能函數,它完成接口硬件的初始化、狀態控制、傳輸差錯控制、發送SOF幀、數據處理。
結構的每一個成員的名字都對應著一個系統調用,剩下的主要是子函數及結構體的編寫,而編寫子函數就很容易了。
結語
嵌入式Linux以及USB設備的應用越來越廣泛。本文分析了MPC850 USB控制器的特點,描述了在嵌入式Linux操作系統下設備驅動程序的實現,對于使用PowerPC 系列CPU的開發人員具有一定的借鑒作用.
參考文獻:
1. ALESSANDRO RUBINI,‘LINUX設備驅動程序’,中國電力出版社,2000
2. 王學龍,‘嵌入式Linux系統設計與應用’,清華大學出版社,2001