在linux2.6以后的內核驅動模型中,關心總線、設備、驅動這三塊。 總線是連接設備和驅動的,一個設備注冊后會通過總線去找驅動,而驅動注冊后也會通過總線去找對應的設備。 這種設備模型就需要設備和驅動掛接在一個總線上面,對有實際總線的設備和驅動那是沒問題的,但有一些掛接在soc內存空間的外設,則沒有對應的總線來掛接,由此引入了platform總線的概念, 即虛擬總線。
platform總線上面的設備和驅動分別是platform_device 和platform_dirver。設備和驅動通過一些特殊的方式進行匹配,下面進行具體代碼分析。
描述設備信息的通常有三種方法:平臺文件、模塊和設備樹,這里以模塊方式加載設備信息。 關于設備信息結構體描述在platform_device.h文件中
struct platform_device { /*一般都是通過名字來匹配的*/ const char *name; /*ID是-1的話,則通過過名字來匹配*/ int id; bool id_auto; /*設備信息*/ struct device dev; /*資源信息的大小*/ u32 num_resources; /*這個結構體里面填充相應的設備資源信息,是一個結構體數組*/ struct resource *resource; const struct platform_device_id *id_entry; char *driver_override; /* Driver name to force a match */ /* MFD cell pointer */ struct mfd_cell *mfd_cell; /* arch specific additions */ struct pdev_archdata archdata;};resource結構體填充—>下面只是舉的一個例子
struct resource res[]={ [0]={ .start = 0x11, .end = 0x22, .flags = IORESOURCE_MEM, /*寄存器信息*/ }, [1]={ .start = 0x33, .end = 0x44, .flags = IORESOURCE_MEM, }, [2]={ .start = 25, .end = 25, .flags = IORESOURCE_IRQ, /*中斷信息*/ },};一般驅動幾個步驟,定義,初始化,注冊和釋放。上面將設備信息模塊的定義與初始化講完了。 下面說說設備信息模塊的注冊與釋放,同樣他們也在platform_device.h文件中。 注冊
extern int platform_device_register(struct platform_device *);釋放
extern void platform_device_unregister(struct platform_device *);無論設備信息用何種方式描述,驅動方法都是使用同樣的一種套路。驅動方法一般都是以模塊的方式加載進內核當中的。 同樣驅動方法的編寫離不開四大步:定義,初始化,注冊和釋放。 驅動方法所使用的函數和結構體都在platform_device.h當中。
定義結構體
struct platform_driver { /*設備的注冊和相應的操作在PRobe中完成*/ int (*probe)(struct platform_device *); /*設備的注銷在remove中完成*/ int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); /*這個結構體重描述設備信息,如名字什么的,總線通過driver結構體的內容進行匹配*/ struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe;};當驅動信息對應字符設備時,字符設備的獲取設備號及注冊的工作在probe里面完成,字符設備的注銷在remove里面完成。而相應的模塊的注冊和模塊的注銷則還是在init和exit函數中完成。
獲取資源 一旦匹配成功,程序就會進入probe當中,在probe中通過獲取資源的一些函數操作可以得到相應的設備信息中的內容。
extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);舉一個實例,對應上面的device中的設備信息
struct resource * res =NULL; res = platform_get_resource(dev,IORESOURCE_MEM, 0); printk("res->start = %#x/n",res->start); printk("res->end = %#x/n",res->end); printk("res->flags = %#x/n",res->flags); /*這里是得到reg信息,然后打印出來*/注冊及注銷模塊
platform_driver_register(drv)extern void platform_driver_unregister(struct platform_driver *);以上也只是platform總線的最基礎模塊的編寫,如果在實際工作中還需要編寫對下硬件的操作,對上層提供函數接口的工作。
新聞熱點
疑難解答