日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux Platform Device and Driver

發布時間:2025/4/16 linux 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Platform Device and Driver 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

從?Linux 2.6?起引入了一套新的驅動管理和注冊機制?:Platform_device?和?Platform_driver?。

Linux?中大部分的設備驅動,都可以使用這套機制?,?設備用?Platform_device?表示,驅動用?Platform_driver?進行注冊。

?

Linux platform driver?機制和傳統的?device driver?機制?(?通過?driver_register?函數進行注冊?)?相比,一個十分明顯的優勢在于?platform?機制將設備本身的資源注冊進內核,由內核統一管理,在驅動程序中使用這些資源時通過?platform device?提供的標準接口進行申請并使用。這樣提高了驅動和資源管理的獨立性,并且擁有較好的可移植性和安全性?(?這些標準接口是安全的?)?。

?

Platform?機制的本身使用并不復雜,由兩部分組成:?platform_device?和?platfrom_driver?。

通過?Platform?機制開發發底層驅動的大致流程為?:??定義?platform_device?--->注冊?platform_device--->?定義?platform_driver?--->注冊platform_driver?。

?

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

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

struct platform_device {

??const char * name;

??u32??id;

??struct device dev;

??u32??num_resources;

??struct resource * resource;

};

?

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

struct resource {

??const char *name;

??unsigned long start, end;

??unsigned long flags;

??struct resource *parent, *sibling, *child;

};

?

下面舉?s3c2410?平臺的?i2c?驅動作為例子來說明:

?

/* arch/arm/mach-s3c2410/devs.c */?
/* I2C */?
static?struct?resource s3c_i2c_resource[?]?=?{?
?????????[?0]?=?{?
???????????????????.?start?=?S3C24XX_PA_IIC,?
???????????????????.?end?=?S3C24XX_PA_IIC?+?S3C24XX_SZ_IIC?-?1,?
???????????????????.?flags?=?IORESOURCE_MEM,?
?????????}?,?
?????????[?1]?=?{?
???????????????????.?start?=?IRQ_IIC,?//S3C2410_IRQ(27)?
???????????????????.?end?=?IRQ_IIC,?
???????????????????.?flags?=?IORESOURCE_IRQ,?
?????????}?
}?;

?

這里定義了兩組?resource?,它描述了一個?I2C?設備的資源,第?1?組描述了這個?I2C?設備所占用的總線地址范圍,?IORESOURCE_MEM?表示第?1?組描述的是內存類型的資源信息,第?2?組描述了這個?I2C?設備的中斷號,?IORESOURCE_IRQ?表示第?2?組描述的是中斷資源信息。設備驅動會根據?flags?來獲取相應的資源信息。

?

有了?resource?信息,就可以定義?platform_device?了:

?

?

?

struct?platform_device s3c_device_i2c?=?{?
?????????.?name?=?"s3c2410-i2c"?,?
?????????.?id?=?-?1,?
?????????.?num_resources?=?ARRAY_SIZE(?s3c_i2c_resource)?,?
?????????.?resource?=?s3c_i2c_resource,?
}?;

定義好了?platform_device?結構體后就可以調用函數?platform_add_devices?向系統中添加該設備了,之后可以調用?platform_driver_register()?進行設備注冊。要注意的是,這里的?platform_device?設備的注冊過程必須在相應設備驅動加載之前被調用,即執行?platform_driver_register?之前?,?原因是因為驅動注冊時需要匹配內核中所以已注冊的設備名。

?

s3c2410-i2c?的?platform_device?是在系統啟動時,在?cpu.c?里的?s3c_arch_init()?函數里進行注冊的,這個函數申明為?arch_initcall(s3c_arch_init);會在系統初始化階段被調用。

arch_initcall?的優先級高于?module_init?。所以會在?Platform?驅動注冊之前調用。?(?詳細參考?include/linux/init.h)

?

s3c_arch_init?函數如下:

/* arch/arm/mach-3sc2410/cpu.c */?
static?int?__init s3c_arch_init(?void?)?
{?
????int?ret;?
????……
/* 這里board指針指向在mach-smdk2410.c里的定義的smdk2410_board,里面包含了預先定義的I2C Platform_device等. */?
????if?(?board?!?=?NULL?)?{?
????????struct?platform_device?*?*?ptr?=?board-?>?devices;?
????????int?i;?

????????for?(?i?=?0;?i?<?board-?>?devices_count;?i+?+?,?ptr+?+?)?{?
????????????ret?=?platform_device_register(?*?ptr)?;??????//在這里進行注冊

????????????if?(?ret)?{?
????????????????printk(?KERN_ERR?"s3c24xx: failed to add board device %s (%d) @%p/n"?,?(?*?ptr)?-?>?name,?
ret,?*?ptr)?;?
????????????}?
????????}?
?????????/* mask any error, we may not need all these board
???????? * devices */
?
????????ret?=?0;?
????}?
????return?ret;?
}?

?

同時被注冊還有很多其他平臺的?platform_device?,詳細查看?arch/arm/mach-s3c2410/mach-smdk2410.c?里的?smdk2410_devices?結構體。

?

?

驅動程序需要實現結構體?struct platform_driver?,參考?drivers/i2c/busses

/* device driver for platform bus bits */


static?struct?platform_driver s3c2410_i2c_driver?=?{?
?????????.?probe?=?s3c24xx_i2c_probe,?
?????????.?remove?=?s3c24xx_i2c_remove,?
?????????.?resume?=?s3c24xx_i2c_resume,?
?????????.?driver?=?{?
???????????????????.?owner?=?THIS_MODULE,?
???????????????????.?name?=?"s3c2410-i2c"?,?
?????????}?,?
}?;

?

在驅動初始化函數中調用函數?platform_driver_register()?注冊?platform_driver?,需要注意的是?s3c_device_i2c?結構中?name?元素和s3c2410_i2c_driver?結構中?driver.name?必須是相同的,這樣在?platform_driver_register()?注冊時會對所有已注冊的所有?platform_device?中的?name和當前注冊的?platform_driver?的?driver.name?進行比較,只有找到相同的名稱的?platfomr_device?才能注冊成功,當注冊成功時會調用?platform_driver結構元素?probe?函數指針,這里就是?s3c24xx_i2c_probe,?當進入?probe?函數后,需要獲取設備的資源信息,常用獲取資源的函數主要是:

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

根據參數?type?所指定類型,例如?IORESOURCE_MEM?,來獲取指定的資源。

?

struct int platform_get_irq(struct platform_device *dev, unsigned int num);

獲取資源中的中斷號。

?

?

?

下面舉?s3c24xx_i2c_probe?函數分析?,?看看這些接口是怎么用的。

前面已經講了,?s3c2410_i2c_driver?注冊成功后會調用?s3c24xx_i2c_probe?執行,下面看代碼:

?

?

/* drivers/i2c/busses/i2c-s3c2410.c */?

static?int?s3c24xx_i2c_probe(?struct?platform_device?*?pdev)?
{?
????struct?s3c24xx_i2c?*?i2c?=?&?s3c24xx_i2c;?
????struct?resource?*?res;?
????int?ret;?
?
????/* find the clock and enable it */?
?
????i2c-?>?dev?=?&?pdev-?>?dev;?
????i2c-?>?clk?=?clk_get(?&?pdev-?>?dev,?"i2c"?)?;?
????if?(?IS_ERR(?i2c-?>?clk)?)?{?
???? dev_err(?&?pdev-?>?dev,?"cannot get clock/n"?)?;?
???? ret?=?-?ENOENT;?
?????goto?out;?
????}?

????dev_dbg(?&?pdev-?>?dev,?"clock source %p/n"?,?i2c-?>?clk)?;?
????clk_enable(?i2c-?>?clk)?;


????/* map the registers */?
????res?=?platform_get_resource(?pdev,?IORESOURCE_MEM,?0)?;?/* 獲取設備的IO資源地址 */?
????if?(?res?=?=?NULL?)?{?
???? dev_err(?&?pdev-?>?dev,?"cannot find IO resource/n"?)?;?
???? ret?=?-?ENOENT;?
?????goto?out;?
????}?
????
????i2c-?>?ioarea?=?request_mem_region(?res-?>?start,?(?res-?>?end-?res-?>?start)?+?1,?pdev-?>?name)?;?/* 申請這塊IO Region */
????
????if?(?i2c-?>?ioarea?=?=?NULL?)?{?
???? dev_err(?&?pdev-?>?dev,?"cannot request IO/n"?)?;?
???? ret?=?-?ENXIO;?
?????goto?out;?
????}?
????
????i2c-?>?regs?=?ioremap(?res-?>?start,?(?res-?>?end-?res-?>?start)?+?1)?;?/* 映射至內核虛擬空間 */?
????
????if?(?i2c-?>?regs?=?=?NULL?)?{?
???? dev_err(?&?pdev-?>?dev,?"cannot map IO/n"?)?;?
???? ret?=?-?ENXIO;?
?????goto?out;?
????}?
????
????dev_dbg(?&?pdev-?>?dev,?"registers %p (%p, %p)/n"?,?i2c-?>?regs,?i2c-?>?ioarea,?res)?;?
????
????/* setup info block for the i2c core */?
????i2c-?>?adap.?algo_data?=?i2c;?
????i2c-?>?adap.?dev.?parent?=?&?pdev-?>?dev;?
????
????/* initialise the i2c controller */?
????ret?=?s3c24xx_i2c_init(?i2c)?;?
????if?(?ret?!?=?0)?
?????goto?out;?

????/* find the IRQ for this unit (note, this relies on the init call to ensure no current IRQs pending?*/?
????
????res?=?platform_get_resource(?pdev,?IORESOURCE_IRQ,?0)?;?/* 獲取設備IRQ中斷號 */?

????if?(?res?=?=?NULL?)?{?
???? dev_err(?&?pdev-?>?dev,?"cannot find IRQ/n"?)?;?
???? ret?=?-?ENOENT;?
?????goto?out;?
????}?
????
????ret?=?request_irq(?res-?>?start,?s3c24xx_i2c_irq,?IRQF_DISABLED,?/* 申請IRQ */?
???? pdev-?>?name,?i2c)?;?
????
????……

????return?ret;?
????
}

?

小思考:

那什么情況可以使用?platform driver?機制編寫驅動呢?

我的理解是只要和內核本身運行依賴性不大的外圍設備?(?換句話說只要不在內核運行所需的一個最小系統之內的設備?),?相對獨立的?,?擁有各自獨自的資源(addresses and IRQs)?,?都可以用?platform_driver?實現。如:?lcd,usb,uart?等,都可以用?platfrom_driver?寫,而?timer,irq?等最小系統之內的設備則最好不用?platfrom_driver?機制,實際上內核實現也是這樣的。

總結

以上是生活随笔為你收集整理的Linux Platform Device and Driver的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。