我是靠谱客的博主 紧张乌龟,最近开发中收集的这篇文章主要介绍驱动开发之read/write驱动开发之read/write:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

驱动开发之read/write:

系统中一切的读写都是站在用户空间的角度来考虑(把你自己当做用户空间)
什么是输入/读?数据从内核空间流向用户空间
什么是输出/写?数据从用户空间流向内核空间

read:

应用层:

ssize_t read(int fd, void *buf, size_t count);

参数1:文件描述符
参数2:存放读取到的数据的空间首地址
参数3:空间大小(不是读到的数据大小)
返回值:成功读取到的字节数

驱动层:

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

参数1:
参数2:应用层read函数的参数2
参数3:应用层read函数的参数3
参数4:文件指针偏移量
返回值:正确读取的字节数

驱动层中实现读功能:

static inline long copy_to_user(void __user *to,const void *from, unsigned long n);

参数1:用户空间缓存区首地址
参数2:内核空间的缓存区首地址
参数3:实际拷贝的字节数
返回值:0成功,非0出错

write:

应用层:

ssize_t write(int fd, const void *buf, size_t count);

参数1:
参数2:存放数据的空间首地址
参数3:实际写的字节数

驱动层:

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

参数1:
参数2:应用层write函数的参数2
参数3:应用层write函数的参数3
参数4:文件指针偏移量
返回值:正确写入的字节数

驱动层中实现写功能:

static inline long copy_from_user(void *to,const void __user * from, unsigned long n)

参数1:内核空间的缓存区首地址
参数2:用户空间缓存区首地址
参数3:实际拷贝的字节数
返回值:0成功,非0出错

 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/demo",O_RDWR);
11
if(fd == -1)
12 
{
13
perror("open");
14
return -1;
15 
}
16
17
char buf[64];
18
read(fd,buf,sizeof(buf));
19
printf("%sn",buf);
20
21
write(fd,"I am from user",15);
22 
close(fd);
23
return 0;
24 }
app.c 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
int major;
struct class *cls;
struct device *devs;
char krbuf[1024] = "I am from kernel";
char kwbuf[1024];
int demo_open(struct inode *inode,struct file *filp)
{
return 0;
}
int demo_close(struct inode *inode,struct file *filp)
{
return 0;
}
ssize_t demo_read(struct file *filp,char __user *ubuf,size_t size,loff_t *off)
{
//
printk("demo_readn");
//
strncpy(ubuf,krbuf,strlen(krbuf) + 1);
//
return strlen(krbuf) + 1;
int ret;
ssize_t n;
if(strlen(krbuf) + 1 > size)
n = size;
else
n = strlen(krbuf) + 1;
ret = copy_to_user(ubuf,krbuf,n);
if(ret != 0)
{
return -EFAULT;
}
return n;
}
ssize_t demo_write(struct file *filp,const char __user *ubuf,size_t size,loff_t *off)
{
ssize_t n;
int ret;
if(size > sizeof(kwbuf))
n = sizeof(kwbuf);
else
n = size;
ret = copy_from_user(kwbuf,ubuf,n);
if(ret != 0)
return -EFAULT;
printk("%sn",kwbuf);
return n;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.open = demo_open,
.read = demo_read,
.write = demo_write,
.release = demo_close,
};
int demo_init(void)
{
major = register_chrdev(0,"demo",&fops);
cls = class_create(THIS_MODULE,"demo");
devs = device_create(cls,NULL,MKDEV(major,0),NULL,"demo");
return 0;
}
module_init(demo_init);
void demo_exit(void)
{
device_destroy(cls,MKDEV(major,0));
class_destroy(cls);
unregister_chrdev(major,"demo");
return;
}
module_exit(demo_exit);
demo.c

 

 

分支匹配函数:

应用层:

int ioctl(int fd, int request, ...);

参数1:文件描述符
参数2:命令——用来和驱动中的某个分支匹配
参数3:可以没有参数
可以有参数(只能有一个),有参数时可以传递变量名或者变量地址,不能是常量。

 

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

参数1:
参数2:接收应用层ioctl的参数2
参数3:如果应用层参数3没有传参,此参数没有值
如果应用层参数3传递的是变量名,此参数接收了变量的内容
如果应用层参数3传递的是变量的地址,此参数接收的就是变量地址

命令的封装方法:
命令本身是一个32位无符号整数,这32位被分成了4个部分(方向,数据类型大小,幻数,序号)

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOC(dir,type,nr,size) 
(((dir) << _IOC_DIRSHIFT) 
((type) << _IOC_TYPESHIFT) 
((nr) << _IOC_NRSHIFT) 
((size) << _IOC_SIZESHIFT))

dir代表方向
type代表幻数
nr代表序号
size代表数据类型大小

#define _IOC_TYPESHIFT 8
#define _IOC_SIZESHIFT 16
#define _IOC_DIRSHIFT 30

 

命令 = 方向 << 30 | 数据类型大小 << 16 | 幻数 << 8 | 序号 << 0
方向占2位:无读写数据、只读数据、只写数据、读写数据
数据类型大小占14位:
幻数占8位:如何选择幻数必须查看Documetation/ioctl/ioctl-number.txt
序号占8位:

命令的封装需要调用:

_IO(幻数,序号)
_IOR(幻数,序号,数据类型)
_IOW(幻数,序号,数据类型)
_IOWR(幻数,序号,数据类型)

ioctl代码:

1:

 1 struct test
 2 {
 3
int a;
 4
char b;
 5 };
 6
 7 #define DEMO_CMD1
_IO('x',0)
 8 #define DEMO_CMD2
_IO('x',1)
 9 #define DEMO_CMD3
_IOW('x',2,int)
10 #define DEMO_CMD4
_IOW('x',3,int)
11 #define DEMO_CMD5
_IOW('x',4,struct test)
head.h
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 struct test t = {
 9
.a = 100,
10
.b = 'w',
11 };
12
13 int main(int argc, const char *argv[])
14 {
15
int fd;
16
17
fd = open("/dev/demo",O_RDWR);
18
if(fd == -1)
19 
{
20
perror("open");
21
return -1;
22 
}
23
24 //
ioctl(fd,1);
25 //
ioctl(fd,2);
26
27 
ioctl(fd,DEMO_CMD1);
28 
ioctl(fd,DEMO_CMD2);
29
30
int a = 10;
31 
ioctl(fd,DEMO_CMD3,a);
32
ioctl(fd,DEMO_CMD4,&a);
33
ioctl(fd,DEMO_CMD5,&t);
34 
close(fd);
35
return 0;
36 }
app.c
 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/fs.h>
 4 #include <linux/device.h>
 5 #include <asm/uaccess.h>
 6 #include "head.h"
 7
 8 MODULE_LICENSE("GPL");
 9
10 int major;
11 struct class *cls;
12 struct device *devs;
13
14 int demo_open(struct inode *inode,struct file *filp)
15 {
16
return 0;
17 }
18
19 long demo_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
20 {
21
int ret;
22
int a;
23
struct test t;
24
switch(cmd)
25 
{
26 #if 0
27
case 1:
28
printk("first cmdn");
29
break;
30
case 2:
31
printk("second cmdn");
32
break;
33 #endif
34
case DEMO_CMD1:
35
printk("first cmdn");
36
break;
37
case DEMO_CMD2:
38
printk("second cmdn");
39
break;
40
case DEMO_CMD3:
41
printk("%ldn",arg);
42
break;
43
case DEMO_CMD4:
44
a = *((int *)arg);
45
printk("%dn",a);
46
break;
47
case DEMO_CMD5:
48
ret = copy_from_user(&t,(struct test *)arg,sizeof(struct test));
49
printk("%d,%cn",t.a,t.b);
50
break;
51
52 
}
53
return 0;
54 }
55
56 int demo_close(struct inode *inode,struct file *filp)
57 {
58
return 0;
59 }
60
61 struct file_operations fops = {
62
.owner = THIS_MODULE,
63
.open = demo_open,
64
.unlocked_ioctl = demo_ioctl,
65
.release = demo_close,
66 };
67
68 int demo_init(void)
69 {
70
major = register_chrdev(0,"demo",&fops);
71
72
cls = class_create(THIS_MODULE,"demo");
73
74
devs = device_create(cls,NULL,MKDEV(major,0),NULL,"demo");
75
76
return 0;
77 }
78 module_init(demo_init);
79
80 void demo_exit(void)
81 {
82
device_destroy(cls,MKDEV(major,0));
83 
class_destroy(cls);
84
unregister_chrdev(major,"demo");
85
return;
86 }
87 module_exit(demo_exit);
demo.c

2.led:

head.h
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 int main(int argc, const char *argv[])
 9 {
10
int fd;
11
12
fd = open("/dev/led",O_RDWR);
13
14
while(1)
15 
{
16 
ioctl(fd,LED2_ON);
17
sleep(1);
18 
ioctl(fd,LED3_ON);
19
sleep(1);
20 
ioctl(fd,LED1_ON);
21
sleep(1);
22 
ioctl(fd,LED4_ON);
23
sleep(1);
24
25 
ioctl(fd,LED4_OFF);
26
sleep(1);
27 
ioctl(fd,LED3_OFF);
28
sleep(1);
29 
ioctl(fd,LED1_OFF);
30
sleep(1);
31 
ioctl(fd,LED2_OFF);
32
sleep(1);
33 
}
34
return 0;
35 }
app.c
 1 #include <linux/module.h>
 2 #include <linux/init.h>
 3 #include <linux/fs.h>
 4 #include <linux/device.h>
 5 #include <asm/io.h>
 6 #include "head.h"
 7
 8 #define GPX2CON 0x11000c40
 9 #define GPX1CON 0x11000c20
10 #define GPF3CON 0x114001e0
11
12 unsigned int *gpx2con;
13 unsigned int *gpx2dat;
14 unsigned int *gpx1con;
15 unsigned int *gpx1dat;
16 unsigned int *gpf3con;
17 unsigned int *gpf3dat;
18
19 int fs4412_led_major;
20 struct class *cls;
21 struct device *devs;
22
23 int fs4412_led_open(struct inode *inode,struct file *filp)
24 {
25
return 0;
26 }
27
28 long fs4412_led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
29 {
30
switch(cmd)
31 
{
32
case LED2_ON:
33
writel((readl(gpx2dat) & ~(1 << 7)) | 1 << 7,gpx2dat);
34
break;
35
case LED2_OFF:
36
writel((readl(gpx2dat) & ~(1 << 7)),gpx2dat);
37
break;
38
case LED1_ON:
39
writel((readl(gpx1dat) & ~(1 << 0)) | 1 << 0,gpx1dat);
40
break;
41
case LED1_OFF:
42
writel((readl(gpx1dat) & ~(1 << 0)),gpx1dat);
43
break;
44
case LED3_ON:
45
writel((readl(gpf3dat) & ~(1 << 4)) | 1 << 4,gpf3dat);
46
break;
47
case LED3_OFF:
48
writel((readl(gpf3dat) & ~(1 << 4)),gpf3dat);
49
break;
50
case LED4_ON:
51
writel((readl(gpf3dat) & ~(1 << 5)) | 1 << 5,gpf3dat);
52
break;
53
case LED4_OFF:
54
writel((readl(gpf3dat) & ~(1 << 5)),gpf3dat);
55
break;
56 
}
57
return 0;
58 }
59
60 struct file_operations fs4412_led_ops = {
61
.owner = THIS_MODULE,
62
.open = fs4412_led_open,
63
.unlocked_ioctl = fs4412_led_ioctl,
64 };
65
66 int __init fs4412_led_init(void)
67 {
68
fs4412_led_major = register_chrdev(0,"led",&fs4412_led_ops);
69
cls = class_create(THIS_MODULE,"led");
70
devs = device_create(cls,NULL,MKDEV(fs4412_led_major,0),NULL,"led");
71
72
gpx2con = ioremap(GPX2CON,4);
73
gpx2dat = gpx2con + 1;
74
75
gpx1con = ioremap(GPX1CON,4);
76
gpx1dat = gpx1con + 1;
77
78
gpf3con = ioremap(GPF3CON,4);
79
gpf3dat = gpf3con + 1;
80
81
writel((readl(gpx2con) & ~(0xf << 28)) | 1 << 28,gpx2con);
82
writel((readl(gpx1con) & ~(0xf << 0)) | 1 << 0,gpx1con);
83
writel((readl(gpf3con) & ~(0xff << 16)) | 0x11 << 16,gpf3con);
84
85
return 0;
86 }
87 module_init(fs4412_led_init);
88
89 void __exit fs4412_led_exit(void)
90 {
91
device_destroy(cls,MKDEV(fs4412_led_major,0));
92 
class_destroy(cls);
93
unregister_chrdev(fs4412_led_major,"led");
94
return;
95 }
96 module_exit(fs4412_led_exit);
97 MODULE_LICENSE("GPL");
led.c

3.资源的竞争

1 #define LED_ON
_IO('x',0)
2 #define LED_OFF
_IO('x',1)
head.h
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 int main(int argc, const char *argv[])
 9 {
10
int fd;
11
12
fd = open("/dev/led0",O_RDWR);
13
14
while(1)
15 
{
16 
ioctl(fd,LED_ON);
17
sleep(1);
18
19 
ioctl(fd,LED_OFF);
20
sleep(1);
21 
}
22
return 0;
23 }
app0.c
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 int main(int argc, const char *argv[])
 9 {
10
int fd;
11
12
fd = open("/dev/led1",O_RDWR);
13
14
while(1)
15 
{
16 
ioctl(fd,LED_ON);
17
sleep(1);
18
19 
ioctl(fd,LED_OFF);
20
sleep(1);
21 
}
22
return 0;
23 }
app1.c
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 int main(int argc, const char *argv[])
 9 {
10
int fd;
11
12
fd = open("/dev/led2",O_RDWR);
13
14
while(1)
15 
{
16 
ioctl(fd,LED_ON);
17
sleep(1);
18
19 
ioctl(fd,LED_OFF);
20
sleep(1);
21 
}
22
return 0;
23 }
app2.c
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <sys/ioctl.h>
 6 #include "head.h"
 7
 8 int main(int argc, const char *argv[])
 9 {
10
int fd;
11
12
fd = open("/dev/led3",O_RDWR);
13
14
while(1)
15 
{
16 
ioctl(fd,LED_ON);
17
sleep(1);
18
19 
ioctl(fd,LED_OFF);
20
sleep(1);
21 
}
22
return 0;
23 }
app3.c

1 #include <linux/module.h>

2 #include <linux/init.h>

3 #include <linux/fs.h>

4 #include <linux/device.h>

5 #include <asm/io.h>

6 #include "head.h"

7

8 #define GPX2CON 0x11000c40

9 #define GPX1CON 0x11000c20
 10 #define GPF3CON 0x114001e0
 11
 12 unsigned int *gpx2con;
 13 unsigned int *gpx2dat;
 14 unsigned int *gpx1con;
 15 unsigned int *gpx1dat;
 16 unsigned int *gpf3con;
 17 unsigned int *gpf3dat;
 18
 19 int fs4412_led_major;
 20 struct class *cls;
 21 struct device *devs;
 22
 23 int fs4412_led_open(struct inode *inode,struct file *filp)
 24 {
 25
int num;
 26
num = iminor(inode);//获取次设备号
 27
filp->private_data = (void *)num;
 28
return 0;
 29 }
 30
 31 void fs4412_led_on(int num)
 32 {
 33
switch(num)
 34 
{
 35
case 0:
 36
//点亮地一个灯
 37
break;
 38
case 1:
 39
break;
 40
case 2:
 41
break;
 42
case 3:
 43
break;
 44 
}
 45 }
 46
 47 void fs4412_led_off(int num)
 48 {
 49
switch(num)
 50 
{
 51
case 0:
 52
//关闭地一个灯
 53
break;
 54
case 1:
 55
break;
 56
case 2:
 57
break;
 58
case 3:
 59
break;
 60 
}
 61 }
 62
 63
 64 long fs4412_led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
 65 {
 66
int num;
 67
num = (int)filp->private_data;
 68
switch(cmd)
 69 
{
 70
case LED_ON:
 71 
fs4412_led_on(num);
 72
break;
 73
case LED_OFF:
 74 
fs4412_led_off(num);
 75
break;
 76 #if 0
 77
case LED2_ON:
 78
writel((readl(gpx2dat) & ~(1 << 7)) | 1 << 7,gpx2dat);
 79
break;
 80
case LED2_OFF:
 81
writel((readl(gpx2dat) & ~(1 << 7)),gpx2dat);
 82
break;
 83
case LED1_ON:
 84
writel((readl(gpx1dat) & ~(1 << 0)) | 1 << 0,gpx1dat);
 85
break;
 86
case LED1_OFF:
 87
writel((readl(gpx1dat) & ~(1 << 0)),gpx1dat);
 88
break;
 89
case LED3_ON:
 90
writel((readl(gpf3dat) & ~(1 << 4)) | 1 << 4,gpf3dat);
 91
break;
 92
case LED3_OFF:
 93
writel((readl(gpf3dat) & ~(1 << 4)),gpf3dat);
 94
break;
 95
case LED4_ON:
 96
writel((readl(gpf3dat) & ~(1 << 5)) | 1 << 5,gpf3dat);
 97
break;
 98
case LED4_OFF:
 99
writel((readl(gpf3dat) & ~(1 << 5)),gpf3dat);
100
break;
101 #endif
102 
}
103
return 0;
104 }
105
106 struct file_operations fs4412_led_ops = {
107
.owner = THIS_MODULE,
108
.open = fs4412_led_open,
109
.unlocked_ioctl = fs4412_led_ioctl,
110 };
111
112 int __init fs4412_led_init(void)
113 {
114
int i;
115
fs4412_led_major = register_chrdev(0,"led",&fs4412_led_ops);
116
cls = class_create(THIS_MODULE,"led");
117
118
for(i = 0;i < 4;i ++)
119
devs = device_create(cls,NULL,MKDEV(fs4412_led_major,i),NULL,"led%d",i);
120
121
gpx2con = ioremap(GPX2CON,4);
122
gpx2dat = gpx2con + 1;
123
124
gpx1con = ioremap(GPX1CON,4);
125
gpx1dat = gpx1con + 1;
126
127
gpf3con = ioremap(GPF3CON,4);
128
gpf3dat = gpf3con + 1;
129
130
writel((readl(gpx2con) & ~(0xf << 28)) | 1 << 28,gpx2con);
131
writel((readl(gpx1con) & ~(0xf << 0)) | 1 << 0,gpx1con);
132
writel((readl(gpf3con) & ~(0xff << 16)) | 0x11 << 16,gpf3con);
133
134
return 0;
135 }
136 module_init(fs4412_led_init);
137
138 void __exit fs4412_led_exit(void)
139 {
140
int i;
141
for(i = 3;i >= 0;i --)
142 
device_destroy(cls,MKDEV(fs4412_led_major,i));
143 
class_destroy(cls);
144
unregister_chrdev(fs4412_led_major,"led");
145
return;
146 }
147 module_exit(fs4412_led_exit);
148 MODULE_LICENSE("GPL");
led_muiltfile.c

 

  

总结:

struct file_operations
{
ssize_t (*read)(struct file *filp,char __user *ubuf,size_t size,loff_t *off);
ssize_t (*write)(struct file *filp,const char __user *ubuf,size_t size,loff_t *off);
long (*unlock_ioctl)(struct file *filp,unsigned int cmd,unsigned long arg);
};
读写都是站在用户空间的角度来考虑
输入:数据从内核空间流向用户空间
输出:数据从用户空间流向内核空间
应用层:ssize_t read(int fd,void *buf,size_t size);
驱动层:ssize_t (*read)(struct file *filp,char __user *ubuf,size_t size,loff_t *off);
int copy_to_user(void *to,void *from,size_t size);
应用层:ssize_t write(int fd,const void *buf,size_t size);
驱动层:ssize_t (*write)(struct file *filp,const char __user *ubuf,size_t size,loff_t *off);
int copy_from_user(void *to,void *from,size_t size);
应用层:int ioctl(int fd,int cmd,...)
驱动层:long (*unlock_ioctl)(struct file *filp,unsigned int cmd,unsigned long arg);
命令分成了4个部分:
2位方向、14位数据类型大小、8位幻数、8位序号
设置命令需要调用一些宏函数:
_IO(幻数,序号);
_IOR(幻数,序号,数据类型);
_IOW(幻数,序号,数据类型);
_IOWR(幻数,序号,数据类型);
避免冲突需要查看Documetation/ioctl/ioctl-number.txt:
查看幻数和序号配合使用时哪些值会有冲突。
假设:4个灯,使不同的设备文件(led0 led1 led2 led3)操作不同的led灯。
相应的可以有4个进程,每个进程打开一个设备文件。这四个进程访问的是同一个驱动。
在操作驱动接口时调用的也是相同的接口,这种情况下会造成资源的竞争。
int led_open(struct inode *,struct file *)
{
num = iminor(inode);
filp->private_data = (void *)num;
}
long led_ioctl()
{
int num;
num = (int)filp->private_data;
}
课程总结

 


转载于:https://www.cnblogs.com/hslixiqian/p/9655949.html

最后

以上就是紧张乌龟为你收集整理的驱动开发之read/write驱动开发之read/write:的全部内容,希望文章能够帮你解决驱动开发之read/write驱动开发之read/write:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部