




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、總線設備驅動模型主要包含總線、設備、驅動三個部分,總線可以是一條真實存在的總 線,例如USB、I2C等典型的設備。但是對于一些設備(內部的設備)可能沒有現成的總線。 Linux 2.6內核中引入了總線設備驅動模型??偩€設備驅動模型與之前的三類驅動(字符、塊 設備、網絡設備)沒有必然的聯(lián)系。設備只是搭載到了總線中。在linux內核中假設存在一 條虛擬總線,稱之為platform總線。platform總線相比與常規(guī)的總線模型其優(yōu)勢主要是 platform總線是由內核實現的,而不用自己定義總線類型,總線設備來加載總線。platform 總線是內核已經實現好的。只需要添加相應的platform dev
2、ice和platform driver。具體的實 現過程主要包括如下的過程:兩者的工作順序是先定義platform_device -注冊platform_device-,再定義 platform_driver- 注冊 platform_driver。整體而言只需要完成兩個步驟,也就是設備的實現和驅動的實現,每一個實現都包括相 關結構體的定義和注冊。platform_device 注冊需要注意的是platform_device實質上是經過處理過的設備,在platform_device結構體 中存在一個設備結構體,與之前的設備存在差別的是引入了設備資源。這些設備資源就能實 現對設備寄存器,中斷等資
3、源的訪問。平臺設備的基本結構體如下: struct platform_device /*設備名*/const char * name;/*設備ID號*/int id;/*結構體包含一個具體的device結構體*/struct device dev;/*資源的數量*/u32num_resources;/*資源結構體,用來保存硬件的資源*/struct resource * resource;/*平臺設備的ID*/struct platform_device_id *id_entry;其中struct device和struct resource是重要的結構體。struct device在總線設備
4、驅動模型中 已經提到了。這次討論一下struct resource0 struct resource /*資源的起始值,如果是地址,那么是物理地址,不是虛擬地址*/resource_size_t start;/*資源的結束值,如果是地址,那么是物理地址,不是虛擬地址7resource_size_t end;/*資源名*/const char *name;/*資源的標示,用來識別不同的資源*/unsigned long flags;/*資源指針,可以構成鏈表*/struct resource *parent, *sibling, *child; platform_device的注冊很簡單,只需要
5、在設備的初始化函數中首先定義相應的設備,通常 采用函數 platform_device *platform_device_alloc(const char *name, int id)動態(tài)申請,通常 name就是需要申請的設備名,而id為-1。然后采用int platform_device_add(struct platform_device *pdev)或者int platform_device_register(struct platform_device *pdev)注冊定義好的設備即可。同樣在退出函數中釋放注冊好的設備即可,可以采用函數:void platform_device_unr
6、egister(struct platform_device *pdev。然后一個平臺設備就完成了,不需要像自己實現模型時定義相關的文件屬性等。設備資源可以通過相關函數得到:struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)中斷資源也可以通過:int platform_get_irq(struct platform_device *dev, unsigned int num)資源的使用主要是驅動實現過程中需要使用到的,但是后期的使用一般需要
7、在驅動的probe 函數中實現申請中斷或者IO內存才能使用,而不能直接使用。特別是資源中的地址通常是 物理地址,需要通過申請IO內存和映射完成物理到虛擬地址的轉換,便于進程的訪問。platform_driver 注冊平臺驅動結構體platform_driver實現如下:struct platform_driver /*平臺驅動需要實現的相關函數操作,其中的前4個函數與最后一個函數與device_driver中的函數是相同的本質是實現對device_driver中相關函數的賦值。*/int (*probe)(struct platform_device *);int (*remove)(stru
8、ct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*suspend_late)(struct platform_device *, pm_message_t state);int (*resume_early)(struct platform_device *);int (*resume)(struct platform_device *);/*內嵌了一個設備驅動結構體*/struct
9、 device_driver driver;/*平臺設備 ID,這與 platform_device 中的 struct platform_device_id *id_entry 是相同的主要是完成總線的匹配操作,platform總線的匹配操作第一匹配要素就是該元素。而 不再是簡單的name選項。*/struct platform_device_id *id_table;通常驅動的入口函數:int (*probe)(struct platform_device *);當總線完成了設備的match操作以后就會進入驅動中該函數的運行??偩€函數的匹配操作如下:static int platform_
10、match(struct device *dev, struct device_driver *drv)/*得到平臺設備的指針*/struct platform_device *pdev = to_platform_device(dev);/*得到平臺驅動指針*/struct platform_driver *pdrv = to_platform_driver(drv);/* match against the id table first */*從定義上分析,id_table是首先匹配的對象,然后才是name的匹配,當ID匹配完成 時就說明匹配好了*/if (pdrv-id_table)re
11、turn platform_match_id(pdrv-id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev-name, drv-name) = 0);從上面的定義可以知道platform總線的匹配函數手下是比較id_table是匹配的首選項。probe函數稱之為探針函數,用于檢測總線上有該驅動能夠處理的設備,而remove函數則 是為了說明總線上該驅動能夠處理的設備被移除。因此這兩個函數是在平臺設備中一定要被實現的函數。其他的函數則不一樣要求實現。平臺驅動的設計主要是完成平臺驅動結構體的
12、填充和注冊。通常的平臺驅動結構體實現如下:static struct platform_driver my_driver =/*平臺驅動的probe函數實現*/.probe = my_probe,/*平臺驅動的remove函數實現*/.remove = my_remove,/*實現設備驅動的name和owner變量*/.driver =/*該參數主要實現總線中的匹配函數調用*/.name = my_dev,/*該函數表示模塊的擁有者*/.owner = THIS_MODULE,;其中的 my_probe和 my_remove是自己定義的probe和remove函數。最主要的是內嵌設備驅動結構體
13、的填充,主要的填充包括name和owner兩個,當然也可以 包括其他的。由于沒有填充id_table,那么name就是總線匹配操作的第一選擇。因此如果沒 有填充好id_table,那么name元素是一定要實現的,不然不能完成相應的設備驅動匹配操作。完成platform_driver結構體的填充過后就是完成驅動的在初始化階段的注冊以及退出階段 的釋放操作,基本的實現函數為:注冊函數,通常在驅動初始化函數中調用:int platform_driver_register(struct platform_driver *drv)釋放函數,通常在驅動退出函數調用:void platform_driver
14、_unregister(struct platform_driver *drv)完成相關的注冊以后總線、設備、驅動的大概框架就完成啦。但是這只是常用的框架,還不能在應用程序中使用。基于平臺驅動的設備驅動都是基于總線架構的,基本的實現過程與之前的簡單字符設備存在 較大的差別,主要的區(qū)別在驅動的初始化不在是平臺設備驅動的初始化函數中實現,而是在 probe函數中實現。而驅動的卸載函數則是在remove函數中實現。probe函數是平臺總線實 現匹配以后首先被調用的函數,因此在其中實現字符設備、塊設備、網絡設備驅動的初始化 是有意義的,這樣的設備驅動就是基于平臺總線的設備驅動,便于維護。平臺總線驅動的
15、注冊過程分析:int platform_driver_register(struct platform_driver *drv)/*第一步,仍然是完成結構體的填充操作*/*驅動的總線類型*/drv-driver.bus = &platform_bus_type;/*將自己定義的probe函數賦值給平臺驅動中設備驅動的probe函數,其他函數類似*/if (drv-probe)drv-be = platform_drv_probe;if (drv-remove)drv-driver.remove = platform_drv_remove;if (drv-shutdown)drv-driver.
16、shutdown = platform_drv_shutdown;if (drv-suspend)drv-driver.suspend = platform_drv_suspend;if (drv-resume)drv-driver.resume = platform_drv_resume;/*第二步,仍然是完成一般設備驅動的注冊操作*/*然手就是一般驅動的注冊,這樣就完成了設備的注冊*/return driver_register(&drv-driver);/*設備驅動的probe函數的賦值過程*/static int platform_drv_probe(struct device *_d
17、ev)/*得到設備對應的平臺驅動*/struct platform_driver *drv = to_platform_driver(_dev-driver);/*得到設備的平臺設備*/struct platform_device *dev = to_platform_device(_dev);/*下面的probe是自己實現的probe函數。具體的實現思路:根據一般設備找對應的平臺設備,同時根據設備的驅動找到平臺驅動。然后返回平臺驅動的probe函數(自己實現通常是初始化操作)地址。*/return drv-probe(dev);實現的總線平臺驅動模型的最簡單源碼:平臺設備的實現:device
18、.c#include#include#include#include#include#include/*平臺模型驅動的平臺設備對象*/static struct platform_device *my_device;/*初始化函數*/static int _init my_device_init(void)int ret = 0;/*采用 platform_device_alloc 分配一個 platform_device 對象 參數分別為 platform_device 的 name,和 id。*/my_device = platform_device_alloc(my_dev,-1);/*
19、注冊設備,注意不是platform_device_register,將平臺設備注冊到內核中*/ ret = platform_device_add(my_device);/*如果出錯釋放相關的內存單元*/if(ret)platform_device_put(my_device);return ret;/*卸載處理函數*/static void _exit my_device_exit(void)platform_device_unregister(my_device);module_init(my_device_init);module_exit(my_device_exit);MODULE_
20、LICENSE(GPL);MODULE_AUTHOR(GP-);平臺驅動的實現:driver.c#include#include#include#include#include/*平臺驅動中的probe和remove函數是必須實現的函數*/*設備驅動的探測函數,主要實現檢測總線上是否有該驅動對應的設備*/static my_probe(struct device *dev)/*如果添加實際的設備到該平臺總線設備驅動模型中,則可以在該函數 中實現具體的設備驅動函數的初始化操作,包括設備號的申請,設備 的初始化,添加。自動設備文件創(chuàng)建函數的添加等操作。或者是混雜字符設備的相關初始化操作。當然結構體
21、的相關處理仍 然采取全局變量的形式。*/printk(Driver found devices which this driver can be handlen);return 0;/*設備驅動的移除函數,主要檢測該驅動支持設備的移除活動檢測*/static my_remove(struct device *dev)/*如果添加實際的設備到該平臺總線設備驅動模型中,則可以在該函數 中實現具體的設備的釋放,包括設備的刪除,設備號的注銷等操作。*/printk(Driver found device unpludedn);return 0;static struct platform_driver
22、 my_driver =/*平臺驅動的probe函數實現*/.probe = my_probe,/*平臺驅動的remove函數實現*/.remove = my_remove,/*實現設備驅動的name和owner變量*/.driver =/*該參數主要實現總線中的匹配函數調用*/.name = my_dev,/*該函數表示模塊的擁有者*/.owner = THIS_MODULE,;/*初始化函數*/static int _init my_driver_init(void)/*注冊平臺驅動*/return platform_driver_register(&my_driver);/*退出函數*/
23、static void _exit my_driver_exit(void)/*注銷平臺驅動*/return platform_driver_unregister(&my_driver);/*加載和卸載*/module_init(my_driver_init);module_exit(my_driver_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(GP-);將一般設備驅動加入到總線設備模型中的相關操作是后期總結和學習的內容。設備驅動實現 的實現原理還是之前的那些操作,但是初始化和推出函數發(fā)生了改變??偨Y:platform總線的驅動模型只是在一般總線模型的基礎
24、上做了相關的延伸,實質上只要 弄清除總線模型的一般原理,學習platform總線也就簡單不少。但是畢竟還是學習階段。概述platform設備和驅動與linux設備模型密切相關。platform在linux設備模型中,其實就 是一種虛擬總線沒有對應的硬件結構。它的主要作用就是管理系統(tǒng)的外設資源,比如io內 存,中斷信號線?,F在大多數處理器芯片都是soc,如s3c2440,它包括處理器內核(arm920t) 和系統(tǒng)的外設(lcd接口,nandflash接口等)。linux在引入了 platform機制之后,內核假 設所有的這些外設都掛載在platform虛擬總線上,以便進行統(tǒng)一管理。platfor
25、m 總線1.在系統(tǒng)中platform對應的文件drivers/base/platform.c,它不是作為一個模塊注冊到內 核的,關鍵的注冊總線的函數由系統(tǒng)初始化部分,對應/init/main.c中的do_basic_setup函 數間接調用。這里可以看出platform非常重要,要在系統(tǒng)其他驅動加載之前注冊。下面分 析platform總線注冊函數cpp view plaincopyint _init platform_bus_init(void)int error;early_platform_cleanup();error = device_register(&platform_bus);/
26、總線也是設備,所以也要進行設備的注冊if (error)return error;error = bus_register(&platform_bus_type);/注冊 platform_bus_type 總線到內核if (error)device_unregister(&platform_bus);return error;這個函數向內核注冊了一種總線。他首先由/drivers/base/init.c中的driver_init函數調用, driver_init 函數由/init/main.c 中的 do_basic_setup 函數調用,do_basic_setup 這個函數由 kerne
27、l_init調用,所以platform總線是在內核初始化的時候就注冊進了內核。2. platform_bus_type總線結構與設備結構(1)platform總線 設備結構cpp view plaincopystruct device platform_bus = .init_name = platform,;platform總線也是一種設備,這里初始化一個device結構,設備名稱platform,因為沒 有指定父設備,所以注冊后將會在/sys/device/T出現platform目錄。(2) platform總線總線結構cpp view plaincopystruct bus_type p
28、latform_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. ;platform_dev_attrs設備屬性platform_matchmatch函數,這個函數在當屬于platform的設備或者驅動注冊到內核時就會調用,完成設備與驅動的匹配工作。platform_uevent熱插拔操作函數三.platform設備platform_device 結構cpp view plai
29、ncopy1.struct platform_device 2.const char * name;3.intid;4.struct device dev;5.u32num_resources;6.struct resource * resource;7.struct platform_device_id *id_entry8./* arch specific additions */9.struct pdev_archdata archdata;10.;(1)platform_device結構體中有一個struct resource結構,是設備占用系統(tǒng)的資源, 定義在ioport.h中,如下
30、cpp view plaincopystruct resource resource_size_t start;resource_size_t end;const char *name;unsigned long flags;struct resource *parent, *sibling, *child;(2) num_resources占用系統(tǒng)資源的數目,一般設備都占用兩種資源,io內存和中斷 信號線。這個為兩種資源的總和。設備注冊函數 platform_device_registercpp view plaincopyint platform_device_register(struc
31、t platform_device *pdev)device_initialize(&pdev-dev);return platform_device_add(pdev);這個函數首先初始化了 platform_device的device結構,然后調用platform_device_add, 這個是注冊函數的關鍵,下面分析platform_device_add:cpp view plaincopyint platform_device_add(struct platform_device *pdev)int i, ret = 0;4.if (!pdev)return -EINVAL;7.if
32、(!pdev-dev.parent)pdev-dev.parent = &platform_bus;/可以看出,platform設備的父設備一般都是platform_bus,所以注冊后的 platform 設備都出現在/sys/devices/platform_bus 下7.18.源4.35.pdev-dev.bus = &platform_bus_type;/掛到platform總線上if (pdev-id != -1)dev_set_name(&pdev-dev
33、, %s.%d, pdev-name, pdev-id);elsedev_set_name(&pdev-dev, %s, pdev-name);/設置設備名字,這個名字與/sys/devices/platform_bus下的名字對應 for (i = 0; i num_resources; i+) 下面操作設備所占用的系統(tǒng)資struct resource *p, *r = &pdev-resourcei;if (r-name = NULL)r-name = dev_name(&pdev-dev);p = r-parent;if (!p) if (resource_type(r) = IORES
34、OURCE_MEM) p = &iomem_resource;else if (resource_type(r) = IORESOURCE_IO) p = &ioport_resource;if (p & insert_resource(p, r) printk(KERN_ERR%s: failed to claim resource %dn, dev_name(&pdev-dev), i);9.40.ret = -EBUSY;goto failed;/上面主要是遍歷設備所占用的資源,找到對應的父資源,如果沒有定義,那么根據資源的類型,分別賦予 iomem_resource
35、 和 ioport_resource,然后調用 insert_resource 插入 資源。這樣系統(tǒng)的資源就形成了一個樹形的數據結構,便于系統(tǒng)的管理pr_debug(Registering platform device %s. Parent at %sn,dev_name(&pdev-dev), dev_name(pdev-dev.parent);44.ret = device_add(&pdev-dev);/注冊到設備模型中if (ret = 0)return ret;failed:while (-i = 0) struct resource *r = &pdev-resourcei;un
36、signed long type = resource_type(r);if(type= IORESOURCE_MEM | type =IORESOURCE_IO)release_resource(r);returnret;mini2440內核注冊platform設備過程因為一種soc確定之后,其外設模塊就已經確定了,所以注冊platform設備就由板級初 始化代碼來完成,在mini2440中是mach-mini2440.c的mini2440_machine_init函數中調 用 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini244
37、0_devices)來完成注 冊。這個函數完成mini2440的所有platform設備的注冊:(1)platform_add_devices 函數是 platform_device_register 的簡單封裝,它向內核 注冊一組platform設備(2)mini2440_devices 是一個 platform_device 指針數組,定義如下:cpp view plaincopystatic struct platform_device *mini2440_devices _initdata = &s3c_device_usb,&s3c_device_rtc,&s3c_device_lc
38、d,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis,&mini2440_device_eth,&s3c24xx_uda134x,&s3c_device_nand,&s3c_device_sdi,&s3c_device_usbgadget,;這個就是mini2440的所有外設資源了,每個外設的具體定義在/arch/arm/plat-s3c24xx/devs.c,下面以 s3c_device_lcd 為例說明,其他的類似。 s3c_device_lcd 在 devs.c 中它定義為:cpp view plaincopystruct platform
39、_device s3c_device_lcd = .name= s3c2410-lcd,.id = -1,.num_resources= ARRAY_SIZE(s3c_lcd_resource),.resource= s3c_lcd_resource, TOC o 1-5 h z .dev= .dma_mask = &s3c_device_lcd_dmamask,.coherent_dma_mask = 0 xffffffffUL;可以看出,它占用的資源s3c_lcd_resource,定義如下:cpp view plaincopystatic struct resource s3c_lcd_
40、resource = 0 = .start=S3C24XX_PA_LCD,.end=S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,.flags=IORESOURCE_MEM, TOC o 1-5 h z ,1= .start=IRQ_LCD,.end=IRQ_LCD,.flags=IORESOURCE_IRQ,;這是一個數組,有兩個元素,說明lcd占用了系統(tǒng)兩個資源,一個資源類型是IORESOURCE_MEM 代表 io 內存,起使地址 S3C24XX_PA_LCD,這個是 LCDCON1 寄 存器的地址。另外一個資源是中斷信號線。四.platform設備驅動如果要將
41、所寫的驅動程序注冊成platform驅動,那么所做的工作就是初始化一個 platform_driver,然后調用 platform_driver_register 進行注冊?;緮祿C構platform_drivercpp view plaincopystruct platform_driver int (*probe)(struct platform_device *);int ( *remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platfo
42、rm_device*, pm_message_t state);int ( *resume)(struct platform_device*);struct device_driver driver;struct platform_device_id *id_table;這是platform驅動基本的數據結構,在驅動程序中我們要做的就是聲明一個這樣的結構 并初始化。下面是led驅動程序對它的初始化:cpp view plaincopy1.static struct platform_driver s3c2412fb_driver = 2.probe= s3c2412fb_probe,3.rem
43、ove= s3c2410fb_remove,4.suspend = s3c2410fb_suspend,5.resume= s3c2410fb_resume,6.driver= 7.name = s3c2412-lcd,8.9.10.owner = THIS_MODULE, ,;上面幾個函數是我們要實現的,它將賦值給deviee_driver中的相關成員,probe函數是 用來查詢特定設備是夠真正存在的函數。當設備從系統(tǒng)刪除的時候調用remove函數。注冊函數 platform_driver_registercpp view plaincopyint platform_driver_register(struct platf
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 產品組合管理
- 幼小銜接培訓老師
- 醫(yī)院冬季消防法律培訓
- 銷售月度工作總結及計劃
- 兒童哮喘護理
- 表單填寫說明培訓
- 有效溝通機制培訓
- 職業(yè)教育管理學理論與實踐
- 肢體無力護理查房
- 子宮頸癌護理診斷
- 2024年重新寫撫養(yǎng)協(xié)議書模板
- 專題6.6射影定理專項提升訓練(重難點培優(yōu))-2022-2023學年九年級數學下冊尖子生培優(yōu)題典(原卷版)
- 中華詩詞之美學習通超星期末考試答案章節(jié)答案2024年
- 蚊蠅蟲鼠害防治管理制度
- DL∕T 1811-2018 電力變壓器用天然酯絕緣油選用導則
- 水泵檢修工(高級)技能鑒定考試題庫(含答案)
- AQ/T 9009-2015 生產安全事故應急演練評估規(guī)范(正式版)
- 瀘州老窖“濃香文釀杯”企業(yè)文化知識競賽考試題庫大全-下(多選、填空題)
- 酒店運營管理 智慧樹知到期末考試答案章節(jié)答案2024年山東青年政治學院
- 幼兒園課程故事開展培訓
- 佐藤大用設計解決問題
評論
0/150
提交評論