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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux platform 驱动模型分析

發布時間:2023/12/20 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux platform 驱动模型分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. 概述
? ? platform設備和驅動與linux設備模型密切相關。platform在linux設備模型中,其實就是一種虛擬總線沒有對應的硬件結構。它的主要作用就是管理系統的外設資源,比如io內存,中斷信號線。現在大多數處理器芯片都是soc,如s3c2440,它包括處理器內核(arm920t)和系統的外設(lcd接口,nandflash接口等)。linux在引入了platform機制之后,內核假設所有的這些外設都掛載在platform虛擬總線上,以便進行統一管理。
二. platform 總線
? ?1. 在系統中platform對應的文件drivers/base/platform.c,它不是作為一個模塊注冊到內核的,關鍵的注冊總線的函數由系統初始化部分,對應/init/main.c中的do_basic_setup函數間接調用。這里可以看出platform非常重要,要在系統其他驅動加載之前注冊。下面分析platform總線注冊函數
[cpp]?view plaincopy
  • int?__init?platform_bus_init(void)??
  • {??
  • ????int?error;??
  • ????early_platform_cleanup();??
  • ????error?=?device_register(&platform_bus);??
  • ????????//總線也是設備,所以也要進行設備的注冊??
  • ????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這個函數由kernel_init調用,所以platform總線是在內核初始化的時候就注冊進了內核。
    ? ?2. platform_bus_type 總線結構與設備結構
    ? ? (1) platform總線 設備結構
    [cpp]?view plaincopy
  • struct?device?platform_bus?=?{??
  • ????.init_name??=?"platform",??
  • };??
  • ? ? platform總線也是一種設備,這里初始化一個device結構,設備名稱platform,因為沒有指定父設備,所以注冊后將會在/sys/device/下出現platform目錄。
    ? ? (2) platform總線 總線結構
    [cpp]?view plaincopy
  • struct?bus_type?platform_bus_type?=?{??
  • ????.name???????=?"platform",??
  • ????.dev_attrs??=?platform_dev_attrs,???
  • ????.match??????=?platform_match,??
  • ????.uevent?????=?platform_uevent,??
  • ????.pm?????=?&platform_dev_pm_ops,??
  • };??
  • ? ? platform_dev_attrs ? ?設備屬性
    ? ? platform_match ? ? ? ?match函數,這個函數在當屬于platform的設備或者驅動注冊到內核時就會調用,完成設備與驅動的匹配工作。
    ? ? platform_uevent ? ? ? 熱插拔操作函數
    三. platform 設備
    ? ?1. platform_device 結構
    [cpp]?view plaincopy
  • struct?platform_device?{??
  • ????const?char??*?name;??
  • ????int?????id;??
  • ????struct?device???dev;??
  • ????u32?????num_resources;??
  • ????struct?resource?*?resource;??
  • ????struct?platform_device_id???*id_entry;??
  • ????/*?arch?specific?additions?*/??
  • ????struct?pdev_archdata????archdata;??
  • };??
  • ? ? (1)platform_device結構體中有一個struct resource結構,是設備占用系統的資源,定義在ioport.h中,如下
    [cpp]?view plaincopy
  • struct?resource?{??
  • ????resource_size_t?start;??
  • ????resource_size_t?end;??
  • ????const?char?*name;??
  • ????unsigned?long?flags;??
  • ????struct?resource?*parent,?*sibling,?*child;??
  • };??
  • ? ? (2) num_resources 占用系統資源的數目,一般設備都占用兩種資源,io內存和中斷信號線。這個為兩種資源的總和。
    ? ?2. 設備注冊函數 platform_device_register
    [cpp]?view plaincopy
  • int?platform_device_register(struct?platform_device?*pdev)??
  • {??
  • ????device_initialize(&pdev->dev);??
  • ????return?platform_device_add(pdev);??
  • }??
  • ? ? 這個函數首先初始化了platform_device的device結構,然后調用platform_device_add,這個是注冊函數的關鍵,下面分析platform_device_add:
    [cpp]?view plaincopy
  • int?platform_device_add(struct?platform_device?*pdev)??
  • {??
  • ????int?i,?ret?=?0;??
  • ??
  • ????if?(!pdev)??
  • ????????return?-EINVAL;??
  • ??
  • ????if?(!pdev->dev.parent)??
  • ????????pdev->dev.parent?=?&platform_bus;??
  • ????????//可以看出,platform設備的父設備一般都是platform_bus,所以注冊后的platform設備都出現在/sys/devices/platform_bus下??
  • ????pdev->dev.bus?=?&platform_bus_type;??
  • ????????//掛到platform總線上??
  • ????if?(pdev->id?!=?-1)??
  • ????????dev_set_name(&pdev->dev,?"%s.%d",?pdev->name,??pdev->id);??
  • ????else??
  • ????????dev_set_name(&pdev->dev,?"%s",?pdev->name);??
  • ????????//設置設備名字,這個名字與/sys/devices/platform_bus下的名字對應??
  • ????for?(i?=?0;?i?<?pdev->num_resources;?i++)?{?//下面操作設備所占用的系統資源??
  • ????????struct?resource?*p,?*r?=?&pdev->resource[i];??
  • ??
  • ????????if?(r->name?==?NULL)??
  • ????????????r->name?=?dev_name(&pdev->dev);??
  • ??
  • ????????p?=?r->parent;??
  • ????????if?(!p)?{??
  • ????????????if?(resource_type(r)?==?IORESOURCE_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?%d\n",??
  • ???????????????????dev_name(&pdev->dev),?i);??
  • ????????????ret?=?-EBUSY;??
  • ????????????goto?failed;??
  • ????????}??
  • ????}??
  • ???????//上面主要是遍歷設備所占用的資源,找到對應的父資源,如果沒有定義,那么根據資源的類型,分別賦予iomem_resource和ioport_resource,然后調用insert_resource插入資源。??
  • ???????//這樣系統的資源就形成了一個樹形的數據結構,便于系統的管理??
  • ????pr_debug("Registering?platform?device?'%s'.?Parent?at?%s\n",??
  • ?????????dev_name(&pdev->dev),?dev_name(pdev->dev.parent));??
  • ??
  • ????ret?=?device_add(&pdev->dev);??
  • ????????//注冊到設備模型中??
  • ????if?(ret?==?0)??
  • ????????return?ret;??
  • ?failed:??
  • ????while?(--i?>=?0)?{??
  • ????????struct?resource?*r?=?&pdev->resource[i];??
  • ????????unsigned?long?type?=?resource_type(r);??
  • ????????if?(type?==?IORESOURCE_MEM?||?type?==?IORESOURCE_IO)??
  • ????????????release_resource(r);??
  • ????}??
  • ????return?ret;??
  • }??
  • ? ?3. mini2440內核注冊platform設備過程
    ? ? 因為一種soc確定之后,其外設模塊就已經確定了,所以注冊platform設備就由板級初始化代碼來完成,在mini2440中是mach-mini2440.c的mini2440_machine_init函數中調用platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices))來完成注冊。這個函數完成mini2440的所有platform設備的注冊:
    ? ? (1) platform_add_devices函數是platform_device_register的簡單封裝,它向內核注冊一組platform設備
    ? ? (2) mini2440_devices是一個platform_device指針數組,定義如下:
    [cpp]?view plaincopy
  • static?struct?platform_device?*mini2440_devices[]?__initdata?=?{??
  • ????&s3c_device_usb,??
  • ????&s3c_device_rtc,??
  • ????&s3c_device_lcd,??
  • ????&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 plaincopy
  • 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??
  • ????}??
  • };??
  • ? ? 可以看出,它占用的資源s3c_lcd_resource,定義如下:
    [cpp]?view plaincopy
  • static?struct?resource?s3c_lcd_resource[]?=?{??
  • ????[0]?=?{??
  • ????????.start?=?S3C24XX_PA_LCD,??
  • ????????.end???=?S3C24XX_PA_LCD?+?S3C24XX_SZ_LCD?-?1,??
  • ????????.flags?=?IORESOURCE_MEM,??
  • ????},??
  • ????[1]?=?{??
  • ????????.start?=?IRQ_LCD,??
  • ????????.end???=?IRQ_LCD,??
  • ????????.flags?=?IORESOURCE_IRQ,??
  • ????}??
  • };??
  • ? ?這是一個數組,有兩個元素,說明lcd占用了系統兩個資源,一個資源類型是IORESOURCE_MEM代表io內存,起使地址S3C24XX_PA_LCD,這個是LCDCON1寄存器的地址。另外一個資源是中斷信號線。
    四. platform設備驅動
    ? ?如果要將所寫的驅動程序注冊成platform驅動,那么所做的工作就是初始化一個platform_driver,然后調用platform_driver_register進行注冊。
    ? ?1. 基本數據機構platform_driver
    [cpp]?view plaincopy
  • struct?platform_driver?{??
  • ????int?(*probe)(struct?platform_device?*);??
  • ????int?(*remove)(struct?platform_device?*);??
  • ????void?(*shutdown)(struct?platform_device?*);??
  • ????int?(*suspend)(struct?platform_device?*,?pm_message_t?state);??
  • ????int?(*resume)(struct?platform_device?*);??
  • ????struct?device_driver?driver;??
  • ????struct?platform_device_id?*id_table;??
  • };??
  • ? ? 這是platform驅動基本的數據結構,在驅動程序中我們要做的就是聲明一個這樣的結構并初始化。下面是lcd驅動程序對它的初始化:
    [cpp]?view plaincopy
  • static?struct?platform_driver?s3c2412fb_driver?=?{??
  • ????.probe??????=?s3c2412fb_probe,??
  • ????.remove?????=?s3c2410fb_remove,??
  • ????.suspend????=?s3c2410fb_suspend,??
  • ????.resume?????=?s3c2410fb_resume,??
  • ????.driver?????=?{??
  • ????????.name???=?"s3c2412-lcd",??
  • ????????.owner??=?THIS_MODULE,??
  • ????},??
  • };??
  • ? ? 上面幾個函數是我們要實現的,它將賦值給device_driver中的相關成員,probe函數是用來查詢特定設備是夠真正存在的函數。當設備從系統刪除的時候調用remove函數。
    ? ?2. 注冊函數platform_driver_register
    [cpp]?view plaincopy
  • int?platform_driver_register(struct?platform_driver?*drv)??
  • {??
  • ????drv->driver.bus?=?&platform_bus_type;??
  • ????if?(drv->probe)??
  • ????????drv->driver.probe?=?platform_drv_probe;??
  • ????if?(drv->remove)??
  • ????????drv->driver.remove?=?platform_drv_remove;????
  • ????if?(drv->shutdown)??
  • ????????drv->driver.shutdown?=?platform_drv_shutdown;??
  • ????return?driver_register(&drv->driver);??
  • }??
  • ? ? 這個函數首先使驅動屬于platform_bus_type總線,將platform_driver結構中的定義的probe,remove,shutdown賦值給device_driver結構中的相應成員,以供linux設備模型核心調用,然后調用driver_regster將設備驅動注冊到linux設備模型核心中。
    五. 各環節的整合
    ? ? 前面提到mini2440板級初始化程序將它所有的platform設備注冊到了linux設備模型核心中,在/sys/devices/platform目錄中都有相應的目錄表示。platform驅動則是由各個驅動程序模塊分別注冊到系統中的。但是他們是如何聯系起來的呢,這就跟linux設備模型核心有關系了。在ldd3中的linux設備模型的各環節的整合中有詳細的論述。這里簡要說明一下platform實現的方法。每當注冊一個platform驅動的時候就會調用driver_register,這個函數的調用會遍歷設備驅動所屬總線上的所有設備,并對每個設備調用總線的match函數。platform驅動是屬于platform_bus_type總線,所以調用platform_match函數。這個函數實現如下:
    [cpp]?view plaincopy
  • 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);??
  • ??
  • ????/*?match?against?the?id?table?first?*/??
  • ????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);??
  • }??
  • ? ? 這個函數將device結構轉換為platform_devcie結構,將device_driver結構轉換為platform_driver結構,并調用platform_match_id對設備與驅動相關信息進行比較。如果沒有比較成功會返回0,以便進行下一個設備的比較,如果比較成功就會返回1,并且將device結構中的driver指針指向這個驅動。然后調用device_driver中的probe函數,在lcd驅動中就是s3c2412fb_probe。這個函數是我們要編寫的函數。這個函數檢測驅動的狀態,并且測試能否真正驅動設備,并且做一些初始化工作。

    總結

    以上是生活随笔為你收集整理的linux platform 驱动模型分析的全部內容,希望文章能夠幫你解決所遇到的問題。

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