歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux下的platform總線驅動

Linux下的platform總線驅動

日期:2017/3/1 10:05:04   编辑:Linux編程

一.Platform設備驅動概念

主要講解平台設備驅動的模型和基本概念,同時因為驅動加載的方式有動態加載和靜態加載兩種方式,這裡我們分別對動態加載和靜態加載兩種情況下,如何使用平台設備和驅動加以敘述。最後使用mini2440開發板,運用Platform和device_attribute機制,編寫按鍵驅動代碼和測試代碼。

我們知道linux內核中常見的的總線有I2C總線,PCI總線,串口總線,SPI總線,PCI總線,CAN總線,單總線等,所以有些設備和驅動就可以掛在這些總線上,然後通過總線上的match進行設備和驅動的匹配。但是有的設備並不屬於這些常見總線,所以我們引入了一種虛擬總線,也就是platform總線的概念,對應的設備叫做platform設備,對應的驅動叫做platform驅動。當然引入platform的概念,可以做的與板子相關的代碼和驅動的代碼分離,使得驅動有更好的可擴展性和跨平台性。

1.Platform總線

struct bus_type platform_bus_type = {

.name = "platform", //名

.dev_attrs = platform_dev_attrs, //屬性

.match = platform_match, //設備和驅動的匹配函數

.uevent = platform_uevent, //卸載處理

.pm = &platform_dev_pm_ops, //電源管理

};

我們看看設備和驅動的匹配函數match

static int platform_match(struct device *dev, struct device_driver *drv)

{

struct platform_device *pdev = to_platform_device(dev); //獲得平台設備

struct platform_driver *pdrv = to_platform_driver(drv); //獲得平台驅動

if (pdrv->id_table) //如果平台驅動有支持項,進入platform_match_id

return platform_match_id(pdrv->id_table, pdev) != NULL;

return (strcmp(pdev->name, drv->name) == 0); //沒有支持項,則老實匹配名字

}

通過上面這個match函數我們知道,如果驅動中定義了驅動支持項,那麼在總線執行match函數中,就會將驅動支持項中每一個名字和設備名字匹配,看看是否匹配成功。如果驅動沒有設置支持項,就會把驅動的名字和設備的名字匹配,如果一樣,則匹配成功。

2.Platform設備

struct platform_device {

const char * name; //名

int id;

struct device dev; //內嵌設備

u32 num_resources; //資源個數

struct resource * resource; //資源結構體

struct platform_device_id *id_entry;

struct pdev_archdata archdata;

};

我們重點來看看platform_device中資源結構體的定義

struct resource {

resource_size_t start; //起始地址

resource_size_t end; //結束地址

const char *name; //名

unsigned long flags; //標號

struct resource *parent, *sibling, *child;

};

對於這個資源結構體中的flags標號可以有IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA四種選擇,重點是申請內存(IORESOURCE_MEM)和申請中斷號(IORESOURCE_IRQ)用的比較多。

2.1Platform設備的靜態加載

所謂的靜態加載,就是把platform設備編譯進內核,對於platform_device的定義常常在BSP中實現,我們這裡拿Mini2440舉例,看看對於的BSP文件mach-smdk2440.c

struct platform_device s3c_device_lcd = {

.name = "s3c2410-lcd",

.id = -1,

.num_resources = ARRAY_SIZE(s3c_lcd_resource),

.resource = s3c_lcd_resource,

.dev = {

.dma_mask = &s3c_device_lcd_dmamask,

.coherent_dma_mask = 0xffffffffUL

}

};

這是基於Mini2440的LCD平台設備在BSP文件中的定義,那麼我們怎麼把它加入內核呢?

static struct platform_device *smdk2440_devices[] __initdata = {

&s3c_device_usb,

&s3c_device_lcd, //添加LCD平台設備

&s3c_device_wdt,

&s3c_device_i2c0,

&s3c_device_iis,

};

嗯,原來我們建立了一個platform_device數組,然後把LCD的platform_device添加到這個數組中,那麼這個platform_device數組怎麼注冊到內核的呢?

static void __init smdk2440_machine_init(void)

{

s3c24xx_fb_set_platdata(&smdk2440_fb_info);

s3c_i2c0_set_platdata(NULL);

platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));//加到內核

smdk_machine_init();

}

看到了吧,在smdk2440_machine_init中,我們調用了platform_add_devices函數來把platform_device注冊到內核,再繼續跟蹤下platform_add_devices

int platform_add_devices(struct platform_device **devs, int num)

{

int i, ret = 0;

for (i = 0; i < num; i++) {

ret = platform_device_register(devs[i]);

if (ret) {

while (--i >= 0)

platform_device_unregister(devs[i]); //注冊設備

break;

}

}

return ret;

}

好了,到此為止,我們已經看到了如果添加platform_device,以及這個platform_device又是如何被注冊到內核的全過程。

Copyright © Linux教程網 All Rights Reserved