驱动开发之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\n",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\n");
 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\n");
 8     return 0;
 9 }
10 
11 int fs4412_platdrv_remove(struct platform_device *pdev)
12 {
13     printk("remove ok\n");
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\n");
 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\n");
 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\n");
 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
重启开发板

posted @ 2018-09-16 16:20  向往的生活ing  阅读(2850)  评论(0编辑  收藏  举报