zoukankan      html  css  js  c++  java
  • 驱动开发之platform总线与设备树

    驱动开发之platform总线与设备树

    platform总线

      实现设备和驱动的分离,为了提高驱动的通用性。
      实现分离后出现三种文件:  驱动代码(自己实现)

                  设备代码(自己实现)

                  虚拟总线代码(内核实现)

    追内核源码(设备):

    1 追内核源码:
    2 struct platform_device //描述platform设备信息
    3  {
    4     const char *name;//可以用于匹配,也可以不用于匹配。但是不能省略,不管是否匹配一定出现在sysfs文件系统的/sys/bus/platform/devices下产生文件名    
    5     struct device dev;//描述了具体的设备信息
    6     struct resource *resource; //资源结构体 
    7     const struct platform_device_id *id_entry;
    8 };
    struct device 
    {
    void (*release)(struct device *dev);//释放资源,配合驱动的remove函数使用
    };
    1 struct resource
    2  { 
    3     resource_size_t start;
    4     resource_size_t end;
    5     nsigned long flags;//描述了资源类型,platform总线中常见的资源类型有三种-->IORESOURCE_MEM(寄存器地址) IORESOURCE_IRQ IORESOURCE_DMA
    6 };
    7 
    8 如果flags传递的是IORESOURCE_MEM,start代表寄存器起始地址,end代表寄存器结束地址
    1 struct platform_device_id
    2  { 
    3     char name[PLATFORM_NAME_SIZE];//专门用来和驱动匹配的
    4 };

    追内核源码(驱动):

    1 struct platform_driver 
     {
    2 int (*probe)(struct platform_device *);//探测函数如果设备和驱动匹配成功则自动执行probe 3 int (*remove)(struct platform_device *); 4 struct device_driver driver; 5 const struct platform_device_id *id_table;//专门用于和设备匹配的 6 };
    1 struct device_driver
    2 { 
    3     const char *name;//可以用于和设备匹配,也可以不用于匹配,但是不能省略一定会在/sys/bus/platform/drivers下创建文件夹    
    4 };


    platform总线接口:

    1 platform_device_register(struct platform_device *);//注册设备(将设备结构体加入到设备链表中)
    2 platform_device_unregister(struct platform_device *);//注销设备
    1 platform_driver_register(struct platform_driver *);//注册驱动
    2 platform_driver_unregister(struct platform_driver *);//注销驱动

    test:

     1 struct dev 
     2 {
     3     char *name;
     4     int a;
     5     int b;
     6 };
     7 
     8 struct drv
     9 {
    10     char *name;
    11     int (*p)(struct dev *);
    12 };
    head.h
     1 #include <stdio.h>
     2 #include "head.h"
     3 
     4 extern struct dev mydev;
     5 extern struct drv mydrv;
     6 
     7 int main(int argc, const char *argv[])
     8 {
     9     if(strcmp(mydrv.name,mydev.name) == 0)
    10         printf("%d
    ",mydrv.p(&mydev));    
    11     return 0;
    12 }
    bus.c
    1 #include "head.h"
    2 
    3 struct dev mydev = {
    4     .name = "xxx",
    5     .a = 10,
    6     .b = 20,
    7 };
    dev.c
     1 #include "head.h"
     2 
     3 int add(struct dev *info)
     4 {
     5     return info->a + info->b;
     6 }
     7 
     8 struct drv mydrv = {
     9     .name = "xxx",
    10     .p = add,
    11 };
    dri.c

    dev.c框架:
      模块声明

      加载函数
      {
        调用 platform_device_register();
      }
      卸载函数
      {
        调用 platform_device_unregister();
      }

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/platform_device.h>
     4 
     5 void fs4412_platdev_release(struct device *dev)
     6 {
     7     printk("release ok
    ");
     8 }
     9 
    10 struct platform_device pdev = {
    11     .name = "xxx1",
    12     .dev = {
    13         .release = fs4412_platdev_release,
    14     },
    15 
    16 };
    17 
    18 int fs4412_platdev_init(void)
    19 {
    20     platform_device_register(&pdev);
    21     return 0;
    22 }
    23 module_init(fs4412_platdev_init);
    24 
    25 void fs4412_platdev_exit(void)
    26 {
    27     platform_device_unregister(&pdev);
    28     return;
    29 }
    30 module_exit(fs4412_platdev_exit);
    31 MODULE_LICENSE("GPL");
    dev.c

    drv.c框架:
      模块声明
      加载函数
      {
        调用 platform_driver_register();
      }

      卸载函数
      {
        调用 platform_driver_unregister();
      }

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/platform_device.h>
     4 
     5 int fs4412_platdrv_probe(struct platform_device *pdev)
     6 {
     7     printk("match ok
    ");
     8     return 0;
     9 }
    10 
    11 int fs4412_platdrv_remove(struct platform_device *pdev)
    12 {
    13     printk("remove ok
    ");
    14     return 0;
    15 }
    16 
    17 #if 0
    18 struct platform_device_id idtbl = {
    19     .name = "xxx1",
    20 };
    21 #endif
    22 
    23 struct platform_device_id idtbl[] = {
    24     [0] = {
    25         .name = "a",
    26     },
    27     [1] = {
    28         .name = "123",
    29     },
    30     [2] = {
    31         .name = "xxx1",
    32     },
    33 };
    34 
    35 struct platform_driver pdrv = {
    36     .driver = {
    37         .name = "xxx",
    38     },
    39 
    40 //    .id_table = &idtbl,
    41     .id_table = idtbl,
    42     .probe = fs4412_platdrv_probe,
    43     .remove = fs4412_platdrv_remove,
    44 
    45 };
    46 
    47 int fs4412_platdrv_init(void)
    48 {
    49     platform_driver_register(&pdrv);
    50     return 0;
    51 }
    52 module_init(fs4412_platdrv_init);
    53 
    54 void fs4412_platdrv_exit(void)
    55 {
    56     platform_driver_unregister(&pdrv);
    57     return;
    58 }
    59 module_exit(fs4412_platdrv_exit);
    60 MODULE_LICENSE("GPL");
    dri.c

     1     ---->>>       vi -t platform_driver_register 过程
     2 #define platform_driver_register(drv)  
     3 __platform_driver_register(drv, THIS_MODULE)
     4                         
     5                        
     6 --->drv->driver.bus = &platform_bus_type;
     7 
     8 
     9 --->struct bus_type platform_bus_type = { 
    10     .name = "platform",
    11     .match = platform_match,
    12 };    
    13 
    14 --->if (of_driver_match_device(dev, drv))//用于和设备树匹配
    15         return 1;
    16     if (acpi_driver_match_device(dev, drv))//不知道,没用过
    17         return 1;
    18  
    19 --->if (pdrv->id_table)
    20         return platform_match_id(pdrv->id_table, pdev) != NULL;
    21 
    22 
    23 --->while (id->name[0])
    24  { 
    25          if (strcmp(pdev->name, id->name) == 0) 
    26         {
    27         pdev->id_entry = id;
    28         return id;
    29         }
    30         id++;
    31 }
    32     return (strcmp(pdev->name, drv->name) == 0);
    33 
    34 ---->>>如果以上四种匹配方式都成功后则执行:
    35 #define platform_driver_register(drv)  
    36 __platform_driver_register(drv, THIS_MODULE)
    37 
    38 
    39 --->if (drv->probe) 
    40         drv->driver.probe = platform_drv_probe;
    41 
    42 (--->表示向下追内核过程)
    43 ret = drv->probe(dev);//执行自己定义的probe函数,并且传递了实参(后面可以应用是合法的)                 

    platform_led:

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     int fd;
     9 
    10     fd = open("/dev/led",O_RDWR);
    11     
    12     sleep(3);
    13 
    14     close(fd);
    15     return 0;
    16 }
    head.h
      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/platform_device.h>
      4 #include <linux/device.h>
      5 #include <linux/fs.h>
      6 #include <asm/io.h>
      7 
      8 int major;
      9 struct class *cls;
     10 struct device *devs;
     11 
     12 unsigned int *gpx2con;
     13 unsigned int *gpx1con;
     14 unsigned int *gpf3con;
     15 unsigned int *gpx2dat;
     16 unsigned int *gpx1dat;
     17 unsigned int *gpf3dat;
     18 
     19 int fs4412_platdrv_open(struct inode *inode,struct file *filp)
     20 {
     21     writel((readl(gpx2dat) & ~(1 << 7)) | 1 << 7,gpx2dat);
     22     writel((readl(gpx1dat) & ~(1 << 0)) | 1 << 0,gpx1dat);
     23     writel((readl(gpf3dat) & ~(1 << 4)) | 1 << 4,gpf3dat);
     24     writel((readl(gpf3dat) & ~(1 << 5)) | 1 << 5,gpf3dat);
     25     
     26     return 0;
     27 }
     28 
     29 int fs4412_platdrv_close(struct inode *inode,struct file *filp)
     30 {
     31     writel((readl(gpx2dat) & ~(1 << 7)) ,gpx2dat);
     32     writel((readl(gpx1dat) & ~(1 << 0)) ,gpx1dat);
     33     writel((readl(gpf3dat) & ~(1 << 4)) ,gpf3dat);
     34     writel((readl(gpf3dat) & ~(1 << 5)) ,gpf3dat);
     35     return 0;
     36 }
     37 
     38 struct file_operations fops = {
     39     .owner = THIS_MODULE,
     40     .open = fs4412_platdrv_open,
     41     .release = fs4412_platdrv_close,
     42 };
     43 
     44 int fs4412_platdrv_probe(struct platform_device *pdev)
     45 {
     46     printk("match ok
    ");
     47 
     48     major = register_chrdev(0,"plat-led",&fops);
     49     cls = class_create(THIS_MODULE,"led");
     50     devs = device_create(cls,NULL,MKDEV(major,0),NULL,"led");
     51 
     52     gpx2con = ioremap(pdev->resource[0].start,4);
     53     gpx2dat = gpx2con + 1;
     54     
     55     gpx1con = ioremap(pdev->resource[1].start,4);
     56     gpx1dat = gpx1con + 1;
     57 
     58     gpf3con = ioremap(pdev->resource[2].start,4);
     59     gpf3dat = gpf3con + 1;
     60 
     61 
     62     writel((readl(gpx2con) & ~(0xf << 28)) | 1 << 28,gpx2con);
     63     writel((readl(gpx1con) & ~(0xf << 0)) | 1 << 0,gpx1con);
     64     writel((readl(gpf3con) & ~(0xff << 16)) | 0x11 << 16,gpf3con);
     65     return 0;
     66 }
     67 
     68 int fs4412_platdrv_remove(struct platform_device *pdev)
     69 {
     70     device_destroy(cls,MKDEV(major,0));
     71     class_destroy(cls);
     72     unregister_chrdev(major,"plat-led");
     73     printk("remove ok
    ");
     74     return 0;
     75 }
     76 
     77 #if 0
     78 struct platform_device_id idtbl = {
     79     .name = "xxx1",
     80 };
     81 #endif
     82 
     83 struct platform_device_id idtbl[] = {
     84     [0] = {
     85         .name = "a",
     86     },
     87     [1] = {
     88         .name = "123",
     89     },
     90     [2] = {
     91         .name = "xxx1",
     92     },
     93 };
     94 
     95 struct platform_driver pdrv = {
     96     .driver = {
     97         .name = "xxx",
     98     },
     99 
    100 //    .id_table = &idtbl,
    101     .id_table = idtbl,
    102     .probe = fs4412_platdrv_probe,
    103     .remove = fs4412_platdrv_remove,
    104 
    105 };
    106 
    107 #if 0
    108 int fs4412_platdrv_init(void)
    109 {
    110     platform_driver_register(&pdrv);
    111     return 0;
    112 }
    113 module_init(fs4412_platdrv_init);
    114 
    115 void fs4412_platdrv_exit(void)
    116 {
    117     platform_driver_unregister(&pdrv);
    118     return;
    119 }
    120 module_exit(fs4412_platdrv_exit);
    121 #endif 
    122 module_platform_driver(pdrv); //接口代替了模块两要素
    123 MODULE_LICENSE("GPL");
    dri.c
     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/platform_device.h>
     4 
     5 void fs4412_platdev_release(struct device *dev)
     6 {
     7     printk("release ok
    ");
     8 }
     9 
    10 struct resource res[] = {
    11     {
    12         .start = 0x11000c40,
    13         .end = 0x11000c40 + 4 - 1,
    14         .flags = IORESOURCE_MEM,    
    15     },
    16 
    17     {
    18         .start = 0x11000c20,
    19         .end = 0x11000c20 + 4 - 1,
    20         .flags = IORESOURCE_MEM,
    21     },
    22 
    23     {
    24         .start = 0x114001e0,
    25         .end = 0x114001e0 + 4 - 1,
    26         .flags = IORESOURCE_MEM,
    27     },
    28 };
    29 
    30 struct platform_device pdev = {
    31     .name = "xxx1",
    32     .dev = {
    33         .release = fs4412_platdev_release,
    34     },
    35     
    36     .resource = res,
    37 };
    38 
    39 int fs4412_platdev_init(void)
    40 {
    41     platform_device_register(&pdev);
    42     return 0;
    43 }
    44 module_init(fs4412_platdev_init);
    45 
    46 void fs4412_platdev_exit(void)
    47 {
    48     platform_device_unregister(&pdev);
    49     return;
    50 }
    51 module_exit(fs4412_platdev_exit);
    52 MODULE_LICENSE("GPL");
    dev.c
     1 ifeq ($(KERNELRELEASE),)
     2 PWD = $(shell pwd)
     3 KERNEL_DIR = /home/linux/linux-3.14/
     4 #KERNEL_DIR = /lib/modules/$(shell uname -r)/build/
     5 
     6 #start:
     7 modules:
     8     make -C $(KERNEL_DIR) M=$(PWD) modules
     9 
    10 #end:
    11 clean:
    12     make -C $(KERNEL_DIR) M=$(PWD) clean
    13 else 
    14 obj-m += dev.o drv.o
    15 endif
    Makefile

    设备树:

    为什么出现设备树(故事源于Linux之父说过arm就是***):
      1、最早期的驱动是硬件和逻辑写死的
      2、当出现platform总线后将设备信息和驱动逻辑分离,为了提高驱动的通用性。
      3、很多的设备代码会被放在arch/arm/mach-xxx或者plat-xxx目录下,每当更换平台时大部分的设备代码都需要修改,为了避免这种现象出现了设备树。


    什么是设备树

      描述硬件信息的一种配置文件。

    设备树的常见文件名:
      xxx.dts 源文件
      xxx.dtb 设备树二进制文件,这个文件的内存地址会以参数的形式传递给内核uImage
      xxx.dtsi 设备树的头文件

      exynos4412-fs4412.dts -》exynos4412.dtsi ——》exynos4x12.dtsi ——》exynos4.dtsi ——》skeleton.dtsi(包含)

    设备树语法:节点、属性
      所有节点都是基于根节点。

     1 vi xxx.dtsi 
     2 /{
     3     demo@地址1{ 正确的
     4 
     5 };
     6 
     7     demo@地址2{
     8 
     9 };
    10 
    11     标签:节点名    
    12     xxx:xxx{
    13 
    14 };
    15 
    16 };
    17 
    18     demo1{ 错误的
    19 
    20 };
    21 
    22 
    23 vi yyy.dts 
    24 #include "xxx.dtsi"
    /{
    test{
    属性 = <&xxx>;//说明test节点在引用xxx节点
    };    <&标签名>;
    
    };

    属性:

      默认属性、自定义属性(厂家自定义和自己定义)

     1 #address-cells = <2>;当前节点的子节点中的reg属性有两个寄存器基地址
     2 #size-cells = <1>;当前节点的子节点中的reg属性有1个寄存器偏移量
     3 
     4 reg = <寄存器基地址1 寄存器偏移量1 寄存器基地址2 寄存器偏移量2 ...>;
     5 compatible = ",",",",","; 用于和驱动匹配
     6 compatible = "samsung,exynos4412","samsung,exynos4";
     7 
     8 
     9 struct device_driver
    10 {
    11     const struct of_device_id *of_match_table; 
    12 }
    13 
    14 struct of_device_id
    15 {
    16      char compatible[128];//数组的内容就是用来和设备树匹配的
    17 }


    led设备树信息:

    1 xxx{
    2     compatible = "fs4412,led";
    3     reg = <0x11000c40 0x4 0x11000c20 0x4 0x114001e0 0x4>;
    4 };

    回到顶层目录执行make dtbs
    cp arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot
    重启开发板

  • 相关阅读:
    URAL 2015 Zhenya moves from the dormitory(水题)
    概率DP总结(待整理)
    HDU 5236 Article(概率DP+贪心 待解决)
    2015上海邀请赛
    树链剖分(待整理)
    hust 5239 Doom(线段树 规律OR数论 待整理 )
    Java大数BigInteger BigDecimal
    hdu 5505 GT and numbers
    hdu 5532 Almost Sorted Array
    hdu 5533 Dancing Stars on Me
  • 原文地址:https://www.cnblogs.com/hslixiqian/p/9656442.html
Copyright © 2011-2022 走看看