国产无码免费,人妻口爆,国产V在线,99中文精品7,国产成人无码AA精品一,制度丝袜诱惑av,久久99免费麻辣视频,蜜臀久久99精品久久久久久酒店
        訂閱
        糾錯
        加入自媒體

        一文教你Linux驅動-platform總線詳解

        2021-02-04 14:37
        一口Linux
        關注

        platform總線是學習linux驅動必須要掌握的一個知識點。

        本文參考已發布:Linux 3.14內核

        一、概念

        嵌入式系統中有很多的物理總線:I2c、SPI、USB、uart、PCIE、APB、AHB

        linux從2.6起就加入了一套新的驅動管理和注冊的機制platform平臺總線,是一條虛擬的總線,并不是一個物理的總線。

        相比 PCI、USB,它主要用于描述SOC上的片上資源。platform 所描述的資源有一個共同點:在CPU 的總線上直接取址。

        平臺設備會分到一個名稱(用在驅動綁定中)以及一系列諸如地址和中斷請求號(IRQ)之類的資源。

        設備用platform_device表示,驅動用platform_driver進行注冊。

        與傳統的bus/device/driver機制相比,platform由內核進行統一管理,在驅動中使用資源,提高了代碼的安全性和可移植性。

        二、platform1. platform總線兩個最重要的結構體

        platform維護的所有的驅動都必須要用該結構體定義:

        platform_driverstruct 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;
        const struct platform_device_id *id_table;
        bool prevent_deferred_probe;
        };

        該結構體,用于注冊驅動到platform總線,

        成員含義probe當驅動和硬件信息匹配成功之后,就會調用probe函數,驅動所有的資源的注冊和初始化全部放在probe函數中remove硬件信息被移除了,或者驅動被卸載了,全部要釋放,釋放資源的操作就放在該函數中struct device_driver driver內核維護的所有的驅動必須包含該成員,通常driver->name用于和設備進行匹配const struct platform_device_id *id_table往往一個驅動可能能同時支持多個硬件,這些硬件的名字都放在該結構體數組中

        我們編寫驅動的時候往往需要填充以上幾個成員

        platform_device

        platform總線用于描述設備硬件信息的結構體,包括該硬件的所有資源(io,memory、中斷、DMA等等)。

        struct platform_device {
        const char *name;
        int  id;
        bool  id_auto;
        struct device dev;
        u32  num_resources;
        struct resource *resource;
        const struct platform_device_id *id_entry;
         MFD cell pointer
        struct mfd_cell *mfd_cell;
         arch specific additions
        struct pdev_archdata archdata;
        };
        成員含義const char *name設備的名字,用于和驅動進行匹配的struct device dev內核中維護的所有的設備必須包含該成員,u32 num_resources資源個數struct resource *resource描述資源

        struct device dev->release()必須實現,

        其中描述硬件信息的成員struct resource

        0x139d0000

        struct resource {
        resource_size_t start;  //表示資源的起始值,          
        resource_size_t end;    //表示資源的最后一個字節的地址, 如果是中斷,end和satrt相同
        const char *name;   // 可不寫  
        unsigned long flags; //資源的類型
        struct resource *parent, *sibling, *child;
        };
        flags的類型說明
        #define IORESOURCE_MEM  0x00000200    //內存
        #define IORESOURCE_IRQ  0x00000400    //中斷

        內核管理的所有的驅動,都必須包含一個叫struct device_driver成員,  //男性描述的硬件,必須包含struct device結構體成員。                                  //女性

        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;
        const struct acpi_device_id *acpi_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;
        };

        其中:

        const char  *name;

        用于和硬件進行匹配。

        內核描述硬件,必須包含struct device結構體成員:

        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_PINCTRL
        struct dev_pin_info *pins;
        #endif
        #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
        #ifdef CONFIG_DMA_CMA
        struct cma *cma_area;   contiguous memory area for dma
               allocations
        #endif
         arch specific additions
        struct dev_archdata archdata;
        struct device_node *of_node;  associated device tree node
        struct acpi_dev_node acpi_node;  associated ACPI device 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);
        struct iommu_group *iommu_group;
        bool   offline_disabled:1;
        bool   offline:1;
        };

        其中:

        void (*release)(struct device *dev);

        不能為空。

        2. 如何注冊

        要用注冊一個platform驅動的步驟

        1)注冊驅動platform_device_register

        *
        * platform_device_register - add a platform-level device
        * @pdev: platform device we're adding

        int platform_device_register(struct platform_device *pdev)
        {
        device_initialize(&pdev->dev);
        arch_setup_pdev_archdata(pdev);
        return platform_device_add(pdev);
        }

        2) 注冊設備platform_driver_register

        #define platform_driver_register(drv)
        __platform_driver_register(drv, THIS_MODULE)

        三、舉例

        1. 開發步驟

        platform 總線下驅動的開發步驟是:

        設備

        需要實現的結構體是:platform_device 。

        1)初始化 resource 結構變量

        2)初始化 platform_device 結構變量

        3)向系統注冊設備:platform_device_register。

        以上三步,必須在設備驅動加載前完成,即執行platform_driver_register()之前,原因是驅動注冊時需要匹配內核中所有已注冊的設備名。

        platform_driver_register()中添加device到內核最終還是調用的device_add函數。

        Platform_device_add和device_add最主要的區別是多了一步insert_resource(p, r),即將platform資源(resource)添加進內核,由內核統一管理。

        驅動

        驅動注冊中,需要實現的結構體是:platform_driver 。

        在驅動程序的初始化函數中,調用了platform_driver_register()注冊 platform_driver 。

        需要注意的是:platform_driver 和 platform_device 中的 name 變量的值必須是相同的【在不考慮設備樹情況下,關于設備樹,后面會寫新的文章詳細講述】 。

        這樣在 platform_driver_register() 注冊時,會將當前注冊的 platform_driver 中的 name 變量的值和已注冊的所有 platform_device 中的 name 變量的值進行比較,只有找到具有相同名稱的 platform_device 才能注冊成功。

        當注冊成功時,會調用 platform_driver 結構元素 probe 函數指針。

        實例1

        本例比較簡單,只用于測試platform_driver 和platform_device是否可以匹配成功。

        左邊是platform_device結構體注冊的代碼,右邊是platform_driver結構體注冊的代碼。

        platform_driver 定義和注冊:

        1 #include

        platform_device定義和注冊:

         1 #include

        該程序只用于測試platform框架是否可以成功匹配,struct platform_device hello_device 并沒有設置任何硬件信息。

        Makfile

         1 ifneq ($(KERNELRELEASE),)                                                                                                                                                      
         2 obj-m:=device.o driver.o
         3 else
         4 KDIR :=/lib/modules/$(shell uname -r)/build
         5 PWD  :=$(shell pwd)
         6 all:
         7     make -C $(KDIR) M=$(PWD) modules
         8 clean:
         9     rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
        10 endif

        該makefile可以同時將兩個C文件編譯成ko文件。

        編譯:

        編譯

        編譯生成的文件:

        在這里插入圖片描述

        加載模塊

        清空log信息
        sudo dmesg -c

        匹配成功實例2

        給結構體platform_device 增加硬件信息,并在內核中能夠讀取出來。本例向結構體hello_device 增加信息如下:

        基址寄存器地址0x139d0000,該地址的空間是0x4中斷號199【注意】實際的內核中會把外設的中斷號根據HW id(通常soc廠商設備soc的時候會給每一個中斷源定義好唯一的ID)計算出一個新的中斷號,該中斷號會被cpu所識別。

        device.c

        struct resource res[]={
        [0] ={
         .start = 0x139d0000,
         .end  = 0x139d0000 + 0x3,
         .flags = IORESOURCE_MEM,
        },
        [1] ={
         .start = 199,
         .end  = 199,
         .flags = IORESOURCE_IRQ,
        },
        };
        static struct platform_device hello_device =
        {
        .name = "duang",
        .id = -1,
        .dev.release = hello_release,
        .num_resources = ARRAY_SIZE(res),
        .resource = res,
        };

        driver.c

        static int hello_probe(struct platform_device *pdev)
        {
        printk("match ok ");
        printk("mem = %x ",pdev->resource[0].start);
        printk("irq = %d ",pdev->resource[1].start);
        //注冊中斷、申請內存
        return 0;
        }

        重新編譯,卸載第一個例子的模塊,并清除log:

        make
        sudo rmmod device
        sudo rmmod driver
        sudo dmesg -c

        執行

        由結果可知,probe函數正確讀取到了硬件信息。

        四、platform_device是如何管理的?1. 沒有設備樹

        在沒有設備樹的時候,以三星Cortex-A8  s5pc100為例,硬件信息放在以下位置

        archrmmach-s5pc100Mach-smdkc100.c
        archrmplat-samsung

        注冊platform_device

        platform_device定義

        該數組存放了,內核啟動需要初始化的硬件的信息。

        2. 如果有設備樹

        內核會有設備初始化的完整代碼,會在內核啟動的時候把設備樹信息解析初始化,把硬件信息初始化到對應的鏈表中。在總線匹配成功后,會把硬件的信息傳遞給probe()函數。

        四、總線相關的其他的知識點

        1. 內核總線相關結構體變量

        內核維護的所有的總線都需要用以下結構體注冊一個變量。

        struct bus_type {
        const char  *name;
        const char  *dev_name;
        struct device  *dev_root;
        struct device_attribute *dev_attrs;  use dev_groups instead
        const struct attribute_group **bus_groups;
        const struct attribute_group **dev_groups;
        const struct attribute_group **drv_groups;
        int (*match)(struct device *dev, struct device_driver *drv);
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        int (*probe)(struct device *dev);  
        int (*remove)(struct device *dev);
        void (*shutdown)(struct device *dev);
        int (*online)(struct device *dev);
        int (*offline)(struct device *dev);
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
        const struct dev_pm_ops *pm;
        struct iommu_ops *iommu_ops;
        struct subsys_private *p;
        struct lock_class_key lock_key;
        };

        platform總線變量的定義struct bus_type platform_bus_type定義如下:

        struct bus_type platform_bus_type = {
        .name  = "platform",
        .dev_groups = platform_dev_groups,
        .match  = platform_match,
        .uevent  = platform_uevent,
        .pm  = &platform_dev_pm_ops,
        };

        其中最重要的成員是**.match**。

        當有設備的硬件信息注冊到platform_bus_type 總線的時候,會遍歷所有platform總線維護的驅動,通過名字來匹配,如果相同,就說明硬件信息和驅動匹配,就會調用驅動的platform_driver ->probe函數,初始化驅動的所有資源,讓該驅動生效。

        當有設備的驅動注冊到platform_bus_type 總線的時候,會遍歷所有platform總線維護的硬件信息,通過名字來匹配,如果相同,就說明硬件信息和驅動匹配,就會調用驅動的platform_driver ->probe函數,初始化驅動的所有資源,讓該驅動生效。

        注冊位置

        driversasePlatform.c

        platform_bus_type的注冊五、注冊代碼流程詳解

        捋架構的好處,就是可以幫助我們定位問題

        1. match函數何時被調用到?2. probe函數何時被調用到

        以下是上述兩個問題代碼的調用流程:

        代碼調用流程

        后面我們會再詳細介紹設備樹。

        聲明: 本文由入駐維科號的作者撰寫,觀點僅代表作者本人,不代表OFweek立場。如有侵權或其他問題,請聯系舉報。

        發表評論

        0條評論,0人參與

        請輸入評論內容...

        請輸入評論/評論長度6~500個字

        您提交的評論過于頻繁,請輸入驗證碼繼續

        暫無評論

        暫無評論

          掃碼關注公眾號
          OFweek人工智能網
          獲取更多精彩內容
          文章糾錯
          x
          *文字標題:
          *糾錯內容:
          聯系郵箱:
          *驗 證 碼:

          粵公網安備 44030502002758號

          主站蜘蛛池模板: 墨脱县| 激情综合区| 人妻精品久久久久中文字幕69| 好吊av| 于都县| http://国产熟女.com| 兴隆县| 国产传媒AV| 缙云县| 望江县| 长武县| 伊人AV在线| 91精品久久久无码中文字幕少妇| 阳原县| 治多县| 同德县| 99久久久国产精品无码| 制服丝袜亚洲无码| 亚洲成人经典| 国产熟妇婬乱A片免费看牛牛| 韩国三级网址| 日日撸| 建瓯市| 汕头市| 佛冈县| 哈尔滨市| 久久久中文| 洋洋av| 万州区| 平和县| 亚洲精品影院| 五月花成人网| 国产熟女精品传媒| 精品3P| 亚洲中文字幕播放| 龙岩市| 久久久久无码| 制服丝袜人妻| 会理县| 鞍山市| 新密市|