1.3 定義platform_driver
與平臺設(shè)備對應(yīng)的平臺設(shè)備驅(qū)動程序由struct platform_driver 描述:
struct platform_driver {
int (*probe)(struct platform_device *); //探測
int (*remove)(struct platform_device *); //移除
void (*shutdown)(struct platform_device *);//關(guān)閉
int (*suspend)(struct platform_device *, pm_
message_t state); //掛起
int (*resume)(struct platform_device *); //恢復
struct device_driver driver;
};
GPIO 的驅(qū)動程序中結(jié)構(gòu)體struct platform_driver主要實現(xiàn)了xgpio_driver 的探測和移除函數(shù)。代碼如下:
static struct platform_driver xgpio_driver = {
.probe = xgpio_probe,
.remove = xgpio_remove,
.driver = {
.name = xilinx_gpio,
.bus = &platform_bus_type,
.owner = THIS_MODULE,
}
1.4 注冊platform_driver
最后需要調(diào)用platform_driver_register()函數(shù)注冊平臺設(shè)備驅(qū)動,在注冊成功后會調(diào)用platform_driver結(jié)構(gòu)元素probe 函數(shù)指針,進入probe 函數(shù)后,需要獲取設(shè)備的資源信息。注冊平臺設(shè)備驅(qū)動的實現(xiàn)函數(shù)如下:
static int __init xgpio_init(void)
{
return platform_driver_register (&xgpio_
driver);
}
2 GPIO控制器設(shè)備驅(qū)動
Linux 是保護模式的操作系統(tǒng),內(nèi)核和應(yīng)用程序分別運行在完全分離的虛擬地址空間,用戶空間的進程一般不能直接訪問硬件。設(shè)備驅(qū)動充當了硬件和應(yīng)用軟件之間的紐帶,它與底層硬件直接打交道,按照硬件設(shè)備的具體工作方式讀寫設(shè)備寄存器,完成設(shè)備的輪詢、中斷處理、DMA 通信,進行物理內(nèi)存向虛擬內(nèi)存的映射,最終使通信設(shè)備能收發(fā)數(shù)據(jù),使顯示設(shè)備能否顯示文字和畫面,使存儲設(shè)備能夠記錄文件和數(shù)據(jù)[1]。
2.1 GPIO 控制器的平臺設(shè)備驅(qū)動函數(shù)實現(xiàn)
使用platform_driver_register(&xgpio_driver)注冊GPIO 設(shè)備驅(qū)動成功后,利用系統(tǒng)探測函數(shù)probe(),獲取設(shè)備需要的資源信息。在探測函數(shù)中,需要通過platform_get_resource()函數(shù)分別獲得GPIO內(nèi)存和IRQ資源:
struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
根據(jù)參數(shù)type 所指定的類型,IORESOURCE_MEM 和IORESOURCE_IRQ 來獲取指定的資源。
驅(qū)動程序中相應(yīng)代碼為:
regs_res = platform_get_resource(pdev,IORESOURCE_MEM, 0);
irq_res = platform_get_resource(pdev,IORESOURCE_IRQ, 0);
在獲取資源成功后,驅(qū)動程序會申請內(nèi)核空間和I/O 空間,將物理地址映射到虛擬地址以及申請中斷
等。在Linux 內(nèi)核空間申請內(nèi)存的主要函數(shù)是kmalloc()、kzalloc()。由這兩個函數(shù)申請的內(nèi)存位于物理內(nèi)存映射區(qū)域,在物理上也是連續(xù)的。它們與真實的物理地址只有一個固定的偏移,存在較簡單的轉(zhuǎn)換關(guān)系。
驅(qū)動程序中與內(nèi)存申請有關(guān)的程序代碼:
xgpio_inst = kmalloc(sizeof(struct xgpio_instance),GFP_KERNEL);
miscdev = kmalloc(sizeof(struct miscdevice),GFP_KERNEL);
第一個參數(shù)是分配的空間大小,第二個標志表示是在內(nèi)核空間的進程中申請內(nèi)存。GFP_KERNEL 標志申請內(nèi)存時,若暫時不能滿足,則進程會睡眠引起阻塞。使用kmalloc()、kzalloc()申請的內(nèi)存要用kfree()釋放。
2.1.1 申請I/O 內(nèi)存空間和映射物理內(nèi)存:
GPIO 設(shè)備控制器有一組寄存器用于讀寫設(shè)備和獲取設(shè)備狀態(tài),即控制寄存器、狀態(tài)寄存器和數(shù)據(jù)寄
存器。這些寄存器位于I/O 內(nèi)存空間[3]。首先需要調(diào)用request_mem_region()申請資源,接著將寄存器地址通過ioremap()將物理地址映射到內(nèi)核空間虛擬地址,之后才可以調(diào)用編程接口訪問這些設(shè)備的寄存器。訪問完成后用iounmap()對申請的內(nèi)核虛擬地址進行釋放,并釋放申請的I/O 內(nèi)存資源。GPIO 控制器驅(qū)動程序的相關(guān)代碼如下:
/*申請I/O 內(nèi)存資源 */
request_mem_region(regs_res->start, remap_size,DRIVER_NAME);
ioremap(regs_res->start, remap_size);
/*映射物理地知道虛擬地址*/
2.1.2 申請中斷:
request_irq(irq_res->start,xgpio_interrupt,0,"XGPIO", xgpio_inst)
irq_res->start 是要申請的硬件中斷號;xgpio_interrupt 是向系統(tǒng)登記的中斷處理函數(shù),是一個
回調(diào)函數(shù),中斷發(fā)生時,系統(tǒng)調(diào)用這個函數(shù),dev_id參數(shù)(即xgpio_inst)將被傳遞。
2.1.3 釋放虛擬地址和內(nèi)存資源
static int xgpio_remove(struct platform_device*pdev) { iounmap(xgpio_inst->base_address);
release_mem_region(xgpio_inst->phys_addr,xgpio_inst->remap_size);
kfree(xgpio_inst);
return 0; /*success*/}
2.2 GPIO 控制器的字符型設(shè)備接口實現(xiàn)
在Linux 的文件操作系統(tǒng)調(diào)用中,字符型設(shè)備一般涉及到打開,讀寫和關(guān)閉文件等操作。在控制器驅(qū)動程序中要給內(nèi)核提供file_operations 結(jié)構(gòu),才能為設(shè)備驅(qū)動提供用戶調(diào)用的接口,定義如下:
static struct file_operations xgpio_fops = {
.owner = THIS_MODULE,
.read = xgpio_read,
.open = xgpio_open,
.release = xgpio_release,};
當系統(tǒng)啟動后,GPIO 控制器被初始化,申請資源和內(nèi)核I/O 內(nèi)存空間。用戶調(diào)用open 函數(shù)打開GPIO設(shè)備時,系統(tǒng)調(diào)用了xgpio_open()函數(shù),主要完成使能中斷等功能。在打開設(shè)備后,返回一個文件指針,可以用這個文件指針對設(shè)備進行一系列操作。當用戶調(diào)用read()函數(shù)對控制器進行讀取的時候,系統(tǒng)調(diào)用了xgpio_read()函數(shù),讀取GPIO 設(shè)備數(shù)據(jù)寄存器的值。當用戶調(diào)用close()函數(shù)關(guān)閉GPIO 設(shè)備時,系統(tǒng)調(diào)了用xgpio_release()函數(shù),禁止中斷。
2.2.1 GPIO 控制器open()函數(shù)的實現(xiàn)
在打開GPIO 控制器后,依據(jù)GPIO 數(shù)據(jù)文檔,向GPIO 全局中斷使能寄存器GIER 寫入0x80000000,向中斷使能寄存器IER 寫入0x00000003 來使能中斷:xgpio_open()函數(shù)實現(xiàn)代碼如下
static int xgpio_open(struct inode *inode, struct file*file)
{
XIo_Out32((int) xgpioinst->v_addr +
XGPIO_GIER_OFFSET, 0x80000000); /* 全局中斷使能 */
XIo_Out32((int) xgpioinst->v_addr +
XGPIO_IER_OFFSET, 0x00000003); /* 使能GPIO中斷 */
return 0;
}
評論
查看更多