歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux設備驅動工程師之路——platform按鍵驅動

一 、重要知識點:

1.platform設備模型

從Linux 2.6起引入了一套新的驅動管理和注冊機制,platform_device和platform_driver,Linux中大部分的設備驅動都可以使用這套機制。platform是一條虛擬的總線。設備用platform_device表示,驅動用platform_driver進行注冊,Linux platform driver機制和傳統的device driver機制(通過driver_register進行注冊)相比,一個明顯的優勢在於platform機制將設備本身的資源注冊進內核,由內核統一管理,在驅動中使用這些資源時通過platform device提供的標准結構進行申請並使用。這樣提高了驅動和資源的獨立性,並且具有較好的可移植性和安全性(這些標准接口是安全的)。

    pltform機制本身使用並不復雜,由兩部分組成:platform_device和platform_driver。通過platform機制開發底層驅動的大致流程為:定義platform_deive->注冊platform_device->定義platform_driver->注冊platform_driver。

    首先要確認的就是設備的資源信息,例如設備的地址,中斷號等。

1)platform_device

在 2.6 內核中 platform 設備用結構體 platform_device 來描述,該結構體定義在 kernel/include/linux/platform_device.h 中,

structplatform_device {

 const char * name;

 u32  id;

 struct device dev;

 u32  num_resources;

 struct resource * resource;

};

該結構一個重要的元素是resource ,該元素存入了最為重要的設備資源信息,定義在kernel/include/linux/ioport.h 中,

structresource {

 const char *name;//資源的名稱

 unsigned long start, end;//資源起始的和結束的物理地址

 unsigned long flags;//資源的類型,比如MEM,IO,IRQ類型

 struct resource *parent, *sibling, *child;//資源鏈表的指針

};

structplatform_device的分配使用

structplatform_device *platform_device_alloc(const char *name, int id)

name是設備名,id,設備id,一般為-1,如果是-1,表示同樣名字的設備只有一個

舉個簡單的例子,name/id是“serial/1”則它的bus_id就是serial.1  如果name/id是“serial/0”則它的bus_id就是serial.0 ,如果它的name/id是“serial/-1”則它的bus_id就是serial。

注冊平台設備,使用函數

intplatform_device_add(struct platform_device *pdev)

注銷使用

voidplatform_device_unregister(struct platform_device *pdev)

2)platform_driver

在平台設備驅動中獲取平台設備資源使用

structresource *platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int num)

該函數用於獲取dev設備的第num個類型為type的資源,如果獲取失敗,則返回NULL。例如 platform_get_resource(pdev,IORESOURCE_IRQ, 0)。

平台驅動描述使用

structplatform_driver {

 int (*probe)(struct platform_device *);

 int (*remove)(struct platform_device *);

 void (*shutdown)(struct platform_device *);

 int (*suspend)(struct platform_device *, pm_message_t state);

 int (*suspend_late)(struct platform_device *, pm_message_t state);

 int (*resume_early)(struct platform_device *);

 int (*resume)(struct platform_device *);

 struct device_driver driver;

};

Probe()函數必須驗證指定設備的硬件是否真的存在,probe()可以使用設備的資源,包括時鐘,platform_data等,Platform driver可以通過下面的函數完成對驅動的注冊:

int platform_driver_register(structplatform_driver *drv);一般來說設備是不能被熱插拔的,所以可以將probe()函數放在init段裡面來節省driver運行時候的內存開銷:

int platform_driver_probe(struct platform_driver *drv, int (*probe)(structplatform_device *));

注銷使用void platform_driver_unregister(struct platform_driver *drv)

2.中斷處理

在Linux驅動程序中,為設備實現一個中斷包含 兩個步驟1.向內核注冊(申請中斷)中斷 2.實現中斷處理函數

request_irq用於實現中斷的注冊

intrequest_irq(unsigned in irq, void(*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void*dev_id)

向內核申請中斷號為irq,中斷處理函數為handler指針指向的函數,中斷標志為flag,設備名為devname的中斷。成功返回0,或者返回一個錯誤碼。

當request_irq不用於共享中斷時,dev_id可以為NULL,或者指向驅動程序自己的私有數據。但用於共享中斷時dev_id必須唯一。因為free_irq時也需要dev_id做參數,這樣free_irq才知道要卸載共享中斷上哪個中斷服務處理函數。共享中斷會在後面講到。

在flag參數中,可以選以下參數

IRQF_DISABLED(SA_INTERRUPT)

如果設置該位,表示是一個“快速”中斷處理程序,如果沒有,那麼就是一個“慢速”中斷處理程序。

IRQF_SHARED(SA_SHITQ)

該位表示中斷可以在設備間共享。

快速/慢速中斷

這兩種類型的中斷處理程序的主要區別在於:快速中斷保證中斷處理的原子性(不被打斷),而慢速中斷則不保證。換句話說,也就是開啟中斷標志位在運行快速中斷處理程序時

關閉的,因此在服務該中斷時,不會被其他類型的中斷打斷;而調用慢速中斷處理時,其他類型中斷扔可以得到服務。

    共享中斷

共享中斷就是將不同的設備掛到同一個中斷信號線上。linux對共享的支持主要是位PCI設備服務。

釋放中斷

voidfree_irq(unsigned int irq)

當設備不再需要使用中斷時(通常是設備關閉和驅動卸載時),應該使用該函數把他們返回給內核使用。

禁用中斷

voiddisable_irq(int irq)

當一些代碼中不能使用中斷時(如支持自旋鎖的上下文中)使用該函數禁用中斷。

啟用中斷

voidenable_irq(int irq)

當禁止後可以使用該函數重新啟用。 

Copyright © Linux教程網 All Rights Reserved