【總結】裝置樹對platform平臺裝置驅動帶來的變化
最初我們學習裝置樹的時候,第一個例子是按鍵中斷,其採用了裝置樹的方式。我們以此為例分析裝置樹引入對platform平臺驅動的改變。
一、改變與不變
(1)platform_driver的入口函式,仍採用platform_driver_register註冊(不變)
static int __init int_demo_init(void) { int ret; ret = platform_driver_register(&int_demo_driver); if (ret) printk(KERN_ERR "int demo: probe failed: %d\n", ret); return ret; } module_init(int_demo_init);
(2)平臺驅動:稍微的變化,多了of_match_table成員
(3)匹配方式的變化:static struct platform_driver int_demo_driver = { .driver = { .name = "interrupt_demo", .of_match_table = of_match_ptr(int_demo_dt_ids), }, .probe = int_demo_probe, .remove = int_demo_remove, };
如果沒有引入裝置樹,還需要定義類似以下檔案來匹配
在Common-smdk.c (linux-3.4.2\arch\arm\mach-s3c24xx)裡static struct resource s3c_int_resource[] = { xxx; }; struct platform_device s3c_device_rtc = { .name = "interrupt_demo", .id = -1, .num_resources = ARRAY_SIZE(s3c_int_resource), .resource = s3c_int_resource, };
static struct platform_device __initdata *smdk_devs[] = {
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
};
//核心初始化時新增相應裝置
platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
沒有引入裝置樹之前,我們採用裝置名字匹配的方式,當platform_driver_register的時候,會去匹配一個名字為"interrupt_demo"的裝置,如果找到同名裝置則呼叫probe函式。由於裝置樹的引入,被硬編碼在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform裝置、resource、i2c_board_info、spi_board_info以及各種硬體的platform_data將不存在。那麼這些裝置資訊在哪裡,什麼時候被add進核心,platform_driver如何匹配platform_device呢?答案是裝置資訊存在裝置樹中,裝置樹載入的時候被轉換成裝置結構體。platform不在像以前那樣匹配裝置名字,而是匹配驅動中的.compatible與裝置樹中相應節點的compatible屬性是否一致,且不區分大小寫。一致則呼叫probe函式。下面我們就來詳細分析為什麼是這樣。
static const struct of_device_id int_demo_dt_ids[] = {
{ .compatible = "tiny4412,interrupt_demo", },
{},
};
MODULE_DEVICE_TABLE(of, int_demo_dt_ids);
static struct platform_driver int_demo_driver = {
.driver = {
.name = "interrupt_demo",
.of_match_table = of_match_ptr(int_demo_dt_ids),
},
.probe = int_demo_probe,
.remove = int_demo_remove,
};
static int __init int_demo_init(void)
{
int ret;
ret = platform_driver_register(&int_demo_driver);
if (ret)
printk(KERN_ERR "int demo: probe failed: %d\n", ret);
return ret;
}
module_init(int_demo_init);
二、詳細分析platform_match的過程
1、函式呼叫流程:
去核心裡檢視,便可發現一層一層是這麼呼叫的。
platform_match-->of_driver_match_device-->of_match_device-->of_match_node-->of_device_is_compatible-->of_get_property/of_compat_cmp-->strcasecmp((s1), (s2))
我們發現最後是在比較字串內容一否一致,所以我們只需要分析這幾個方法的成員列表,看到底比較的是哪兩個字串即可。
2、方法分析
platform_driver_register,首先呼叫到如下匹配函式。
platform_match(device,device_driver)
device:猜測是裝置樹構建的
device_driver:被platform_driver封裝,就是我們的int_demo_driver
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);
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
of_driver_match_device(device,device_driver)
static inline int of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
of_match_device(of_device_id,device)
of_device_id:device_driver>of_match_table=of_match_ptr(int_demo_dt_ids):這個不就是我們在驅動裡面定義的of_match_table成員
device:猜測是裝置樹構建的
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
of_match_node(of_device_id,device_node)
device_node:device->of_node(裝置樹完成了of_node的初始化)繼續:
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
if (!matches)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= node->name
&& !strcmp(matches->name, node->name);
if (matches->type[0])
match &= node->type
&& !strcmp(matches->type, node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(node,
matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
of_device_is_compatible(device_node,char *compat)=of_device_is_compatible(device_node,“tiny4412,interrupt_demo”)
char *compat:of_device_id->compatible=tiny4412,interrupt_demo
到此我們已經可以發現 ,現在是在和驅動裡面定義的of_device_id結構體的compatible成員做對比,那麼是誰和它對比呢?我們繼續看下一個函式:
int of_device_is_compatible(const struct device_node *device,
const char *compat)
{
const char* cp;
int cplen, l;
cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
cp = of_get_property(device_node,"compatible", &cplen)
device_node:device->of_node(裝置樹完成了of_node的初始化)
裝置樹載入的時候構建了device裝置,被初始化了of_node成員,現在我們根據of_node去獲取節點對應的compatible屬性。cp就等於裝置樹裡我們定義的節點的compatible屬性值。如上函式of_device_is_compatible,則對比了裝置樹中節點的compatible與我們定義的是否存在名字一致的裝置。存在則返回1;
const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
of_compat_cmp:忽略大小寫比較字串。#define of_compat_cmp(s1, s2, l)strcasecmp((s1), (s2))
3、相關結構體
(1)device Device.h (linux-3.4.2\include\linux)struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
(2)device_driver Device.h (linux-3.4.2\include\linux)
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
三、總結
到此我們知道了。是在比較驅動中我們定義的of_device_id型別的結構體裡面的compatible名字與裝置樹節點的compatible來決定是否執行probe函式。我們並沒有初始化platform_device,這些是核心載入裝置樹的時候幫我們完成的,並且根據裝置樹節點初始化了of_node成員,我們可以根據of_node找到節點對應的成員屬性。即裝置樹載入之後,核心會自動把裝置樹節點轉換成
platform_device這種格式,同時把名字放到of_node這個地方。
還有一點我們上面用到的結構體是device,和device_driver,為什麼不是我們定義的platform_device和platform_driver呢?其實platform是對device的一層封裝,檢視原始碼我們就可以發現函式呼叫流程:
platform_device--》device platform_device_register --》device_add
platform_driver--》device_driver platform_driver_register--》device_register
所以platform是對struct device和struct device_driver的封裝。
對於device和device_driver我們後面再來分析。
相關推薦
【總結】裝置樹對platform平臺裝置驅動帶來的變化
最初我們學習裝置樹的時候,第一個例子是按鍵中斷,其採用了裝置樹的方式。我們以此為例分析裝置樹引入對platform平臺驅動的改變。 一、改變與不變 (1)platform_driver的入口函式,仍採用platform_driver_register註冊(不變) sta
【總結】 伸展樹Splay
挖坑待補 前言 感覺我在聯賽還差4天的時候學習Splay有點慌,但還是要學一下。 定義 我們先對Splay的陣列進行一些定義: struct node{ int ff,siz,cnt,ch[2],val; //ff表示父親,siz表示子樹大小,ch表示兒子,cnt表示與這個點權值相同
【總結】裝置樹語法及常用API函式
一、DTS編寫語法 二、常用函式 裝置樹函式思路是:uboot啟動時將裝置樹地址傳給核心,核心解析裝置樹,並建立裝置,初始化相關屬性,驅動中通過of_get_XXX函式去獲取裝置樹載入時建立的裝置。
【總結】對異步處理的http接口進行性能測試
調研 內存 雲監控 後端 調優 系統 錯誤 手機 服務器 以前對接口做性能測試,接口都是同步處理的,請求之後等待響應結果就知道處理結果了,這樣只要看這個接口是否異常,如果無異常無報錯記錄這個接口的響應時間、TPS等性能指標進行分析就可以了,最近在工作中遇到了異步處理的接口,
【演算法總結】B+樹的實現
【參考資料】 【B+樹是什麼】 b+樹是b樹的變種。b+樹與b樹最大的不同在於:b+樹的關鍵字數量跟孩子節點數量一致,這與b樹不一樣。並且,b+樹的葉子節點包含有所有關鍵字及其對應資訊,非葉子節點只包含部分關鍵字(這部分關鍵字相當於邊界索引),不含具體資料,下面這幅圖就
【演算法總結】B樹總結
【參考資料】 【B樹解釋】 B樹是一棵樹,不同的是該樹的最多有m個子節點,至少floor(m/2)個子節點(根節點除外,根節點最少可以有兩個子節點。),但是裡面包含關鍵字數量比當前的子節點少1,在沒有子節點的情況下,關鍵字數量在 floor(m/2)-1到m-1之間。
【Java】整理樹的幾種遍歷方式總結
http://www.cnblogs.com/developerY/p/3323264.html BFS和DFS詳解以及java實現 http://sunlujing.iteye.com/blog/1876540 http://www.cnblogs.com/dolphin
P3372 【模板】線段樹 1
load color 求和 整數 數字 amp article http cst 題目描述 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.求出某區間每一個數的和 輸入輸出格式 輸入格式: 第一行包含兩個整數N、M,分別表示該數
【Python】決策樹的python實現
uia bmp say 不知道 times otto outlook lru bgm 【Python】決策樹的python實現 2016-12-08 數據分析師Nieson 1. 決策樹是什麽? 簡單地理解,就是根據一些 feature 進行分類,每個節點提一個問
【bzoj2836】魔法樹 樹鏈剖分+線段樹
urn fin pan online char font -s class efi 題目描述 輸入 輸出 樣例輸入 4 0 1 1 2 2 3 4 Add 1 3 1 Query 0 Query 1 Query 2 樣例輸出
[洛谷3373]【模板】線段樹 2
兩個 cstring tchar int() 維護 string max nbsp 線段 思路: 線段樹。同時維護兩個 lazy tag ,一個維護乘,一個維護加。根據加法結合律,可以得出:當同一個結點進行兩次加操作時,新的標記等於兩次標記之和。根據乘法結合律,可以得出:
【2】JVM-JAVA對象的訪問
lin oar XML nts java棧 article value new string Java中對象的訪問 JAVA是面向對象的語言,那麽在JAVA虛擬機中,存在非常多的對象,對象訪問是無處不在的。即時是最簡單的訪問,也會涉及到JAVA棧、JAVA堆、方法區
P3373 【模板】線段樹 2 區間求和 區間乘 區間加
std 數列 cst printf int img ostream string uil 題目描述 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.將某區間每一個數乘上x 3.求出某區間每一個數的和 輸入輸出格式 輸入格
【bzoj4785】[Zjoi2017]樹狀數組 線段樹套線段樹
奇怪 原因 tdi function 數字 二進制位 操作 接下來 還需 題目描述 漆黑的晚上,九條可憐躺在床上輾轉反側。難以入眠的她想起了若幹年前她的一次悲慘的OI 比賽經歷。那是一道基礎的樹狀數組題。給出一個長度為 n 的數組 A,初始值都為 0,接下來進行 m 次操
【BZOJ4785】[Zjoi2017]樹狀數組 樹套樹(二維線段樹)
這也 現在 ont 平面 nbsp -s mil 比賽 turn 【BZOJ4785】[Zjoi2017]樹狀數組 Description 漆黑的晚上,九條可憐躺在床上輾轉反側。難以入眠的她想起了若幹年前她的一次悲慘的OI 比賽經歷。那是一道基礎的樹狀數組題。給出
Nginx教程(7) 正向代理與反向代理【總結】
資料 用戶訪問 認證 origin 訪問者 發送 -128 負載 行為 1、前言 最近工作中用到反向代理,發現網絡代理的玩法還真不少,網絡背後有很多需要去學習。而在此之前僅僅使用了過代理軟件,曾經為了訪問google,使用了代理軟件,需要在瀏覽器中配置代理的地址。我只知
線段樹區間修改 P3372 【模板】線段樹 1
print alt namespace clu 格式 getch 輸出格式 包含 模板 題目描述 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.求出某區間每一個數的和 輸入輸出格式 輸入格式: 第一行包含兩個整數N、M,分別表示該數
【J2EE】 關於response對象
狀態 nbsp har sta als edi 調用 stat 指定 兩種響應流 1.response.getWriter() //字符流 >默認為iso-8859-1,setCharactorEncoding("utf-8") \ setContent
【原創】洛谷 LUOGU P3373 【模板】線段樹2
取模 file 需要 code ace highlight dig org zh-cn P3373 【模板】線段樹 2 題目描述 如題,已知一個數列,你需要進行下面兩種操作: 1.將某區間每一個數加上x 2.將某區間每一個數乘上x 3.求出
【總結】spark按文本格式和Lzo格式處理Lzo壓縮文件的比較
spark lzotextinputformat1、描述spark中怎麽加載lzo壓縮格式的文件2、比較lzo格式文件以textFile方式和LzoTextInputFormat方式計算數據,Running Tasks個數的影響 a.確保lzo文件所在文件夾中生成lzo.index索引文件 b.以