1 platfrom的概括
platform總線是區別于實體總線USB、 I2C、SPI 、PIC總線的虛擬總線,一些usb設備選址的話需要通過USB總線來進行尋址,而有些類似于SoC內部外設如led 看門狗 定時器是直接通過內存的尋址空間來進行尋址的,cpu與這些設備通信是不需要總線的,2.6內核以后要對所有設備進行統一管理,通過kset、kobject來建立層次關系,對這些直接通過內存尋址的設備虛擬了一種總線即platform總線,在硬件上實際是沒有這個總線;platform內核純軟件的總線,所有的直接通過內存尋址的設備都映射到這條總線上。設備用platform_device表示,驅動用platform_driver進行注冊。platform由內核進行統一管理,在驅動中使用資源,提高了代碼的安全性和可移植性。更換硬件時只需要修改硬件部分的代碼,其中還一部分代碼是屬于內核中穩定的部分,通用的接口,不用修改。
相對輸入input子系統,platform是對驅動的模型的分離的思想,而input子系統測試分層的思想。
2 平臺總線優點:
(1)可以通過platform總線,可以遍歷所有的platform總線設備;platform本質其實也是kset、kobject,具有kobject的特性
(2)實現設備與驅動的分離,通過platform總線,設備與驅動是分開注冊的,通過platform總線的probe來隨時檢測與設備匹配的驅動,如匹配上即進行這個設備的驅動注冊;
(3)由于上面這個優勢,一個驅動可以供同類的幾個設備使用;
3 platform總線以及platform總線設備驅動的實現流程
platform總線注冊 -->> platform_device注冊 -->> platform_driver注冊 -->> 設備與驅動的匹配 -->> 驅動的注冊
platform總線的工作流程如下圖:
代碼分析
定義位于:driversbaseplatform.c
platform總線的注冊:platform的注冊是linux內核工程師已經設注冊好的;重點是.match = platform_match函數;platform_driver和platform_device就是通過這個函數來匹配的
4 platform_bus
platform是bus的一種,是一種虛擬總線。
1 struct bus_type platform_bus_type = {
2 .name = 'platform',
3 .dev_attrs = platform_dev_attrs,
4 .match = platform_match,
5 .uevent = platform_uevent,
6 .pm = &platform_dev_pm_ops,
7 };
4.1platform_bus_init
1 int __init platform_bus_init(void)
2 {
3 int error;
4 /*清除早期的platform數據和信息(早期的platform建立時sysfs等都沒建立,不完善,所以要這里清掉之前的建立),重新注冊platform*/
5 early_platform_cleanup();
6
7 error = device_register(&platform_bus);//設備的注冊,在sysfs的device下注冊一個位platform的空文件夾
8 if (error)
9 return error;
10 error = bus_register(&platform_bus_type);//bus的注冊,在sysfs的bus下注冊一個platform的文件夾 ,同時使用platform總線注冊的設備的bus都會被賦值為platform_bus_type,即將來所有設備會在bus下的platform里出現
11 if (error)
12 device_unregister(&platform_bus);
13 return error;
14 }
platform_bus的device,定義如下:
struct device platform_bus = {
.init_name = 'platform',
};
4.2 platform_match
platform總線上設備和驅動的匹配規則
1 /**
2 * platform_match - bind platform device to platform driver.
3 * @dev: device.
4 * @drv: driver.
5 *
6 * Platform device IDs are assumed to be encoded like this:
7 * ' 8 * device, like 'pci' or 'floppy', and 9 * instance of the device, like '0' or '42'. Driver IDs are simply 10 * ' 11 * and compare it against the name of the driver. Return whether they match 12 * or not. 13 */ 14 static int platform_match(struct device *dev, struct device_driver *drv) 15 { 16 struct platform_device *pdev = to_platform_device(dev); 17 struct platform_driver *pdrv = to_platform_driver(drv); 18 19 /* Attempt an OF style match first */ 20 if (of_driver_match_device(dev, drv)) 21 return 1; 22 23 /* Then try ACPI style match */ 24 if (acpi_driver_match_device(dev, drv)) 25 return 1; 26 27 /* Then try to match against the id table */ 28 if (pdrv->id_table)//如果driver的id_table存在,則只匹配id_table 29 return platform_match_id(pdrv->id_table, pdev) != NULL; 30 31 /* fall-back to driver name match */ 32 return (strcmp(pdev->name, drv->name) == 0);//如果drv的id_table不存在,則比較name是否相等 33 } 4.3 platform_match_id 1 static const struct platform_device_id *platform_match_id( 2 const struct platform_device_id *id, 3 struct platform_device *pdev) 4 {/*其實id也是匹配name,只不過可能driver要支持多個device,所以有多個名字,就做成一個id_table比較*/ 5 while (id->name[0]) { 6 if (strcmp(pdev->name, id->name) == 0) { 7 pdev->id_entry = id; 8 return id; 9 } 10 id++; 11 } 12 return NULL; 13 } 5 platform_device 5.1 platform_device結構體 1 struct platform_device { 2 const char *name; 3 int id;/*區分使用相同driver的同種設備,從0開始,-1為自動分配*/ 4 bool id_auto; 5 struct device dev;/*具體的設備,無論是何種總線里的設備,都是對dev再次增加信息封裝*/ 6 u32 num_resources;/*多少個資源,為下面準備的*/ 7 struct resource *resource;/*存放資源的地址*/ 8 9 const struct platform_device_id *id_entry;/*區分統一廠家的不同版本設備*/ 10 11 /* MFD cell pointer */ 12 struct mfd_cell *mfd_cell; 13 14 /* arch specific additions */ 15 struct pdev_archdata archdata;/*特殊架構準備,基本不用*/ 16 } 5.2 platform_device_alloc 通常我們自定義一個靜態的platform_device并填充。 當然內核為了絕對的可裁剪性,也提供了通過動態分配的方法。 1 /** 2 * platform_device_alloc - create a platform device 3 * @name: base name of the device we're adding 4 * @id: instance id 5 * 6 * Create a platform device object which can have other objects attached 7 * to it, and which will have attached objects freed when it is released. 8 */ 9 struct platform_device *platform_device_alloc(const char *name, int id) 10 { 11 struct platform_object *pa; 12 13 pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL); 14 if (pa) { 15 strcpy(pa->name, name); 16 pa->pdev.name = pa->name; 17 pa->pdev.id = id; 18 device_initialize(&pa->pdev.dev); 19 pa->pdev.dev.release = platform_device_release;/*release放在dev里面unregister的時候只要device_del(dev)就可以*/ 20 arch_setup_pdev_archdata(&pa->pdev); 21 } 22 23 return pa ? &pa->pdev : NULL; 24 } struct platform_object { struct platform_device pdev; char name[1]; }; 5.2.1 platform_device_release 1 static void platform_device_release(struct device *dev) 2 { 3 struct platform_object *pa = container_of(dev, struct platform_object, 4 pdev.dev); 5 6 of_device_node_put(&pa->pdev.dev); 7 kfree(pa->pdev.dev.platform_data);//這部分由自己具體的設備實現具體的數據結構 8 kfree(pa->pdev.mfd_cell); 9 kfree(pa->pdev.resource);//釋放存放resource的內存 10 kfree(pa);//釋放platform_device_alloc中申請的obj 11 } 5.2.2 platform_device_register 無論是靜態還是2.2中的動態定義的platform_device,都需要platform_device添加進platform_bus。 即使用下面platform_device_register函數就可以了。 1 /** 2 * platform_device_register - add a platform-level device 3 * @pdev: platform device we're adding 4 */ 5 int platform_device_register(struct platform_device *pdev) 6 { 7 device_initialize(&pdev->dev); 8 arch_setup_pdev_archdata(pdev); 9 return platform_device_add(pdev); 10 } 5.2.3 platform_add_devices 系統也提供了可以同時注冊多個device的API,起始就是多次調用上面的。 1 /** 2 * platform_add_devices - add a numbers of platform devices 3 * @devs: array of platform devices to add 4 * @num: number of platform devices in array 5 */ 6 int platform_add_devices(struct platform_device **devs, int num) 7 { 8 int i, ret = 0; 9 10 for (i = 0; i < num; i++) { 11 ret = platform_device_register(devs[i]); 12 if (ret) { 13 while (--i >= 0) 14 platform_device_unregister(devs[i]); 15 break; 16 } 17 } 18 19 return ret; 20 } 5.2.4 platform_device_add 1 /** 2 * platform_device_add - add a platform device to device hierarchy 3 * @pdev: platform device we're adding 4 * 5 * This is part 2 of platform_device_register(), though may be called 6 * separately _iff_ pdev was allocated by platform_device_alloc(). 7 */ 8 int platform_device_add(struct platform_device *pdev) 9 { 10 int i, ret; 11 12 if (!pdev) 13 return -EINVAL; 14 15 if (!pdev->dev.parent)//如果設備沒指定parent的話,默認就是platform(通常都是) 16 pdev->dev.parent = &platform_bus; 17 18 pdev->dev.bus = &platform_bus_type;//綁定總線類型,sysfs體現
上一篇:Android驅動開發5-8章讀書筆記
下一篇:tiny210移植linux內核(3.0.8)雜項
推薦閱讀最新更新時間:2025-04-15 18:06
設計資源 培訓 開發板 精華推薦
- DN380 快速、高效、獨立的 NiMH/NiCd 電池充電參考設計
- 使用 Analog Devices 的 LT1228 的參考設計
- MAXREFDES1036:20.25W離線式反激轉換器
- 使用 ON Semiconductor 的 LM2575-12 的參考設計
- NCV78703R1GEVK:NCV78703 套件
- 使用 Analog Devices 的 AD7944BCP 的參考設計
- TB62757FUG 使用升壓 DC-DC 轉換器的 2 至 6 WLED 驅動器應用電路
- LT3970HMS-3.3 1.8V 降壓轉換器的典型應用
- STM32F4設計作業
- 基于L7980的2A降壓開關演示板