我是靠谱客的博主 机灵猫咪,这篇文章主要介绍2022/10/20——platform总线驱动练习,现在分享给大家,希望可以做个参考。

通过platform总线驱动实现

  1. 应用程序通过阻塞的io模型来读取number变量的值

  2. number是内核驱动中的一个变量

  3. number的值随着按键按下而改变(按键中断) 例如number=0 按下按键number=1 ,再次按下按键number=0

  4. 在按下按键的时候需要同时将led1的状态取反

  5. 驱动中需要编写字符设备驱动 f.驱动中需要自动创建设备节点

  6. 这个驱动需要的所有设备信息放在设备树的同一个节点

驱动文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include <linux/of.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/cdev.h> #include <linux/ioctl.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #define CNAME "mycdev" unsigned int major; char kbuf[128]={};//定义数组用于存放和用户之间拷贝的数据 int *p=(int*)kbuf; struct class *cls;//句柄 struct device *dev; //定义队列头 wait_queue_head_t wq_head; //判断是否有数据准备好的标识变量 unsigned int condition=0; int number=0; struct resource *res; int irqno; struct gpio_desc *desc; //中断处理函数 irqreturn_t irq_handler(int irq,void *dev) { //电位反转 number=number%2; gpiod_set_value(desc,number); *p=number; //将反转后的电平状态保存 number++; //唤醒 condition=1; wake_up_interruptible(&wq_head); return IRQ_HANDLED; } int pdrv_probe(struct platform_device *pdr) { int ret; printk("%s:%dn",__FILE__,__LINE__); res=platform_get_resource(pdr,IORESOURCE_MEM,0); if(res==NULL) { printk("获取资源失败n"); return -ENODATA; } irqno=platform_get_irq(pdr,0); if(irqno<0) { printk("获取资源失败n"); return irqno; } printk("%#x %dn",res->start,irqno); //获取GPIO编号 desc=gpiod_get_from_of_node(pdr->dev.of_node,"led2",0,GPIOD_OUT_HIGH,NULL); if(IS_ERR(desc)) { printk("获取GPIO编号失败n"); return PTR_ERR(desc); } //注册中断 ret=request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING,"key2_inte",NULL); if(ret) { printk("注册中断失败n"); return ret; } printk("注册中断成功n"); //初始化队列头 condition=0; init_waitqueue_head(&wq_head); return 0; } int pdrv_remove(struct platform_device *pdr) { free_irq(irqno,NULL); gpiod_set_value(desc,0); gpiod_put(desc); printk("%s:%dn",__FILE__,__LINE__); return 0; } //定义名字表 struct of_device_id oftable[]={ {.compatible="hqyj,platform"}, {}, }; MODULE_DEVICE_TABLE(of,oftable); //定义并初始化对象 struct platform_driver pdrv ={ .probe=pdrv_probe, .remove=pdrv_remove, .driver={ .name="test", .of_match_table=oftable,//设备树匹配 }, }; //read() ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff) { //size参数是用户期待读到的字节长度 int ret; if(file->f_flags&O_NONBLOCK) { //非阻塞,退出 return -EINVAL; } else{ //阻塞 ret=wait_event_interruptible(wq_head,condition); if(ret) { printk("接收阻塞休眠n"); return ret; } } if(size>sizeof(kbuf)) size=sizeof(kbuf); ret=copy_to_user(ubuf,kbuf,size); if(ret) { printk("数据从内核向用户拷贝失败n"); return -EIO; } condition=0; return size; } //操作方法结构体的初始化 struct file_operations fops= { .read=mycdev_read, }; static int __init mycdev_init(void) { //动态注册字符设备驱动 major=register_chrdev(0,CNAME,&fops); if(major<0) { printk("字符设备驱动注册失败n"); return major; } printk("字符设备驱动注册成功major=%dn",major); //向上提交节点目录 cls=class_create(THIS_MODULE,"LED"); if(IS_ERR(cls)) { printk("向上提交目录失败n"); return PTR_ERR(cls); } printk("向上提交目录成功n"); //创建设备节点文件 dev=device_create(cls,NULL,MKDEV(major,0),NULL,"myled"); if(IS_ERR(dev)) { printk("创建节点失败n"); return PTR_ERR(dev); } printk("创建节点成功n"); platform_driver_register(&pdrv); return 0; } static void __exit mycdev_exit(void) { //注销对象 platform_driver_unregister(&pdrv); //注销中断 free_irq(irqno,NULL); //释放设备号 gpiod_set_value(desc,0); gpiod_put(desc); //销毁节点 device_destroy(cls,MKDEV(major,0)); //销毁目录 class_destroy(cls); //注销字符设备驱动 unregister_chrdev(major,CNAME); } module_init(mycdev_init); module_exit(mycdev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("zhangyang_sh@hqyj.com");

test.c——测试用的应用程序

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<sys/ioctl.h> #include<sys/wait.h> int main(int argc,char const *argv[]) { int fd,number; fd=open("/dev/myled",O_RDWR); if(fd<0) { printf("打开文件失败n"); exit(-1); } printf("打开文件成功n"); while(1) { read(fd,&number,sizeof(number)); printf("number=%dn",number); } close(fd); return 0; }

实验现象

 

最后

以上就是机灵猫咪最近收集整理的关于2022/10/20——platform总线驱动练习的全部内容,更多相关2022/10/20——platform总线驱动练习内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(88)

评论列表共有 0 条评论

立即
投稿
返回
顶部