郑州门户网站建设哪家好,2018wordpress主题,厦门市建设路网站,大宗商品平台Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 专注与分散是我在题目中着重说明的一个内容。这是今天我们要学习分离与分层概念的延伸。专注是说我们要专注某层驱动的开发#xff0c;而对于其他层则是芯片厂商…Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 专注与分散是我在题目中着重说明的一个内容。这是今天我们要学习分离与分层概念的延伸。专注是说我们要专注某层驱动的开发而对于其他层则是芯片厂商需要完成的任务。分散则是要求有分层的概念明白哪些是我们需要专注的内容哪些是我们不需要关注的内容。所以专注与分散式相辅相成、不可分割的。 本篇笔记主要学习了platform设备驱动开发的相关概念。将分成两次笔记进行学习。本次笔记主要学习platform设备驱动开发相关的理论知识。主要内容包括Linux驱动的分离与分层、platform平台驱动模型简介。其中驱动的分离与分层有包括驱动的分离、驱动的分层。platform平台驱动模型简介主要包括platform总线、platform驱动与platform设备。 本节的思维导图如下 一、Linux驱动的分离与分层
1、驱动的分隔与分层 传统的I2C设备驱动 改进后的设备驱动 分割后的驱动框架 Linux总线、驱动和设备模式
2、驱动的分层 分层的目的也是为了在不同的层处理不同的内容。分层极大简化我们的驱动编写。
二、platform平台驱动模型简介
1、platform总线 bus_type结构体表示总线
1 struct bus_type {
2 const char *name; /* 总线名字 */
3 const char *dev_name;
4 struct device *dev_root;
5 struct device_attribute *dev_attrs;
6 const struct attribute_group **bus_groups; /* 总线属性 */
7 const struct attribute_group **dev_groups; /* 设备属性 */
8 const struct attribute_group **drv_groups; /* 驱动属性 */
9
10 int (*match)(struct device *dev, struct device_driver *drv);
11 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
12 int (*probe)(struct device *dev);
13 int (*remove)(struct device *dev);
14 void (*shutdown)(struct device *dev);
15
16 int (*online)(struct device *dev);
17 int (*offline)(struct device *dev);
18 int (*suspend)(struct device *dev, pm_message_t state);
19 int (*resume)(struct device *dev);
20 const struct dev_pm_ops *pm;
21 const struct iommu_ops *iommu_ops;
22 struct subsys_private *p;
23 struct lock_class_key lock_key;
24 }; match函数完成设备与驱动之间匹配。 platform 总线是 bus_type 的一个具体实例。
1 struct bus_type platform_bus_type {
2 .name platform,
3 .dev_groups platform_dev_groups,
4 .match platform_match,
5 .uevent platform_uevent,
6 .pm platform_dev_pm_ops,
7 }; platform_bus_type 就是 platform 平台总线其中 platform_match 就是匹配函数。 驱动和设备的匹配有四种方法
a.OF类型匹配
b.ACPI匹配方式
c.id_table匹配
d.直接比较驱动和设备的name字段 2、platform驱动 platform_driver 结 构 体 表 示 platform 驱 动。
1 struct platform_driver {
2 int (*probe)(struct platform_device *);
3 int (*remove)(struct platform_device *);
4 void (*shutdown)(struct platform_device *);
5 int (*suspend)(struct platform_device *, pm_message_t state);
6 int (*resume)(struct platform_device *);
7 struct device_driver driver;
8 const struct platform_device_id *id_table;
9 bool prevent_deferred_probe;
10 }; probe 函数当驱动与设备匹配成功以后 probe 函数就会执行非常重要的函数
driver 成员为 device_driver 结构体变量 Linux 内核里面大量使用到了面向对象的思维 device_driver 相当于基类提供了最基础的驱动框架。 plaform_driver 继承了这个基类 然后在此基础上又添加了一些特有的成员变量。
id_table 是个表 (也就是数组 )每个元素的类型为 platform_device_id
device_driver 结构体定义在 include/linux/device.h device_driver 结构体内容如下
1 struct device_driver {
2 const char *name;
3 struct bus_type *bus;
4
5 struct module *owner;
6 const char *mod_name; /* used for built-in modules */
7
8 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
9
10 const struct of_device_id *of_match_table;
11 const struct acpi_device_id *acpi_match_table;
12
13 int (*probe) (struct device *dev);
14 int (*remove) (struct device *dev);
15 void (*shutdown) (struct device *dev);
16 int (*suspend) (struct device *dev, pm_message_t state);
17 int (*resume) (struct device *dev);
18 const struct attribute_group **groups;
19
20 const struct dev_pm_ops *pm;
21
22 struct driver_private *p;
23 }; of_match_table 就是采用设备树的时候驱动使用的匹配表,每个匹配项都为 of_device_id 结构体类型此结构体定义在文件 include/linux/mod_devicetable.h 中内 容如下
1 struct of_device_id {
2 char name[32];
3 char type[32];
4 char compatible[128];
5 const void *data;
6 }; 对于设备树而言就是通过设备节点的 compatible 属性值和 of_match_table 中每个项目的 compatible 成员变量进行比较如果有相等的就表示设备和此驱动匹配成功。 platform_driver_register 函数向 Linux 内核注册一个 platform 驱动:
int platform_driver_register (struct platform_driver *driver) 驱动卸载函数中通过 platform_driver_unregister 函数卸载 platform 驱动:
void platform_driver_unregister(struct platform_driver *drv) platform 驱动框架如下所示
/* 设备结构体 */
1 struct xxx_dev{
2 struct cdev cdev;
3 /* 设备结构体其他具体内容 */
4 };
5
6 struct xxx_dev xxxdev; /* 定义个设备结构体变量 */
7
8 static int xxx_open(struct inode *inode, struct file *filp)
9 {
10 /* 函数具体内容 */
11 return 0;
12 }
13
14 static ssize_t xxx_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
15 {
16 /* 函数具体内容 */
17 return 0;
18 }
19
20 /*
21 * 字符设备驱动操作集
22 */
23 static struct file_operations xxx_fops {
24 .owner THIS_MODULE,
25 .open xxx_open,
26 .write xxx_write,
27 };
28
29 /*
30 * platform 驱动的 probe 函数
31 * 驱动与设备匹配成功以后此函数就会执行
32 */
33 static int xxx_probe(struct platform_device *dev)
34 {
35 ......
36 cdev_init(xxxdev.cdev, xxx_fops); /* 注册字符设备驱动 */
37 /* 函数具体内容 */
38 return 0;
39 }
40
41 static int xxx_remove(struct platform_device *dev)
42 {
43 ......
44 cdev_del(xxxdev.cdev);/* 删除 cdev */
45 /* 函数具体内容 */
46 return 0;
47 }
48
49 /* 匹配列表 */
50 static const struct of_device_id xxx_of_match[] {
51 { .compatible xxx-gpio },
52 { /* Sentinel */ }
53 };
54
55 /*
56 * platform 平台驱动结构体
57 */
58 static struct platform_driver xxx_driver {
59 .driver {
60 .name xxx,
61 .of_match_table xxx_of_match,
62 },
63 .probe xxx_probe,
64 .remove xxx_remove,
65 };
66
67 /* 驱动模块加载 */
68 static int __init xxxdriver_init(void)
69 {
70 return platform_driver_register(xxx_driver);
71 }
72
73 /* 驱动模块卸载 */
74 static void __exit xxxdriver_exit(void)
75 {
76 platform_driver_unregister(xxx_driver);
77 }
78
79 module_init(xxxdriver_init);
80 module_exit(xxxdriver_exit);
81 MODULE_LICENSE(GPL);
82 MODULE_AUTHOR(zuozhongkai); 总体来说 platform 驱动还是传统的字符设备驱动、块设备驱动或网络设备驱动只是套 上了一张“ platform” 的皮目的是为了使用总线、驱动和设备这个驱动模型来实现驱动的分离与分层。
3、platform设备 platform_device 这个结构体表示 platform 设备:
22 struct platform_device {
23 const char *name;
24 int id;
25 bool id_auto;
26 struct device dev;
27 u32 num_resources;
28 struct resource *resource;
29
30 const struct platform_device_id *id_entry;
31 char *driver_override; /* Driver name to force a match */
32
33 /* MFD cell pointer */
34 struct mfd_cell *mfd_cell;
35
36 /* arch specific additions */
37 struct pdev_archdata archdata;
38 }; 使用 platform_device_register 函数将设备信息注册到 Linux 内核中此函数原型如下所示
int platform_device_register(struct platform_device *pdev) 如果不再使用 platform 的话可以通过 platform_device_unregister 函数注销掉相应的 platform 设备 platform_device_unregister 函数原型如下
void platform_device_unregister(struct platform_device *pdev) platform 设备信息框架实例如下所示
1 /* 寄存器地址定义*/
2 #define PERIPH1_REGISTER_BASE (0X20000000) /* 外设 1 寄存器首地址 */
3 #define PERIPH2_REGISTER_BASE (0X020E0068) /* 外设 2 寄存器首地址 */
4 #define REGISTER_LENGTH 4
5
6 /* 资源 */
7 static struct resource xxx_resources[] {
8 [0] {
9 .start PERIPH1_REGISTER_BASE,
10 .end (PERIPH1_REGISTER_BASE REGISTER_LENGTH - 1),
11 .flags IORESOURCE_MEM,
12 },
13 [1] {
14 .start PERIPH2_REGISTER_BASE,
15 .end (PERIPH2_REGISTER_BASE REGISTER_LENGTH - 1),
16 .flags IORESOURCE_MEM,
17 },
18 };
19
20 /* platform 设备结构体 */
21 static struct platform_device xxxdevice {
22 .name xxx-gpio,
23 .id -1,
24 .num_resources ARRAY_SIZE(xxx_resources),
25 .resource xxx_resources,
26 };
27
28 /* 设备模块加载 */
29 static int __init xxxdevice_init(void)
30 {
31 return platform_device_register(xxxdevice);
32 }
33
34 /* 设备模块注销 */
35 static void __exit xxx_resourcesdevice_exit(void)
36 {
37 platform_device_unregister(xxxdevice);
38 }
39
40 module_init(xxxdevice_init);
41 module_exit(xxxdevice_exit);
42 MODULE_LICENSE(GPL);
43 MODULE_AUTHOR(zuozhongkai);
以下内容将在明天的笔记中详细说明
三、硬件原理图分析
四、驱动开发
1、platform设备与驱动程序开发
2、测试APP开发
五、运行测试
1、编译驱动程序和测试APP
2、运行测试 本文为参考正点原子开发板配套教程整理而得仅用于学习交流使用不得用于商业用途。