應用程序write函數(shù)的使用:
char *p = “hello,world”;?
write(fd, p, 12); //將數(shù)據(jù)寫入到設備
底層驅動write接口
struct file_operations { ssize_t (*write) (struct file *file, const char __user *buf, size_t count, loff_t *ppos);};write接口作用:用于寫設備,將數(shù)據(jù)寫入到設備中與應用程序write的調用關系:應用程序調用write->...->調用驅動write接口參數(shù):file:文件指針buf:保存用戶緩沖區(qū)的首地址(p),在驅動程序中不能直接訪問這個buf,如果驅動程序要向從用戶空間將數(shù)據(jù)從buf拷貝到內核空間,必須利用內核提供的內存拷貝函數(shù)count:用戶要寫入的字節(jié)數(shù),例如12字節(jié) ppos:保存寫的位置信息,例如 獲取上一次的寫位置: loff_t pos = *ppos; 假如這次成功寫了12字節(jié); 最后要更新寫位置信息: *ppos = pos + 12;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
切記:對于write接口的第二個參數(shù)buf,這個buf指針保存的是用戶緩沖區(qū)的首地址,在內核空間不能直接訪問操作,需要利用內核的內存拷貝函數(shù),將用戶數(shù)據(jù)拷貝到內核空間,這個內存拷貝函數(shù):
unsigned long copy_from_user(void *to, void __user *from, unsigned long n)作用:將用戶緩沖區(qū)的數(shù)據(jù)拷貝到內核緩沖區(qū)中參數(shù):to:目的地址,傳遞內核緩沖區(qū)的首地址from:源地址,傳遞用戶緩沖區(qū)的首地址(buf)n:要拷貝的字節(jié)數(shù)將來只要看到__user修飾的指針,就不能在驅動中直接訪問操作,必須利用內存拷貝函數(shù)!
1
2
3
4
5
6
7
8
9
案例:編寫字符設備驅動,提供write接口,將用戶空間的數(shù)據(jù)寫入到內核空間
int udata = 0x5555;? write(fd, &udata, sizeof(udata));
#include #include #include //struct file_operations#include //struct cdev + 設備號#include #include #include //copy_to_user//聲明描述LED硬件相關的數(shù)據(jù)結構struct led_resource { char *name; int gpio;};//定義初始化LED硬件信息static struct led_resource led_info[] = { [0] = { .name = "LED1", .gpio = S5PV210_GPC0(3) }, [1] = { .name = "LED2", .gpio = S5PV210_GPC0(4) }};//定義設備號static dev_t dev;//定義字符設備對象static struct cdev led_cdev;//調用關系:應用程序open->....->led_openstatic int led_open(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 1); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序close->...->led_closestatic int led_close(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 0); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序read->...->led_readstatic ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ //定義初始化內核緩沖區(qū)(存儲空間再后1G虛擬內存中) int kdata = 0x5555; //將內核數(shù)據(jù)上報給用戶 //切記:buf雖然保存的用戶緩沖區(qū)的首地址,但不能直接訪問 //*(int *)buf = kdata;錯誤 copy_to_user(buf, &kdata, sizeof(kdata)); printk("%s ", __func__); return sizeof(kdata); //失敗返回負值,成功返回實際讀取的字節(jié)數(shù)}//調用關系:應用程序write->...->最終調用led_writestatic ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ //定義內核緩沖區(qū) int kdata; //拷貝用戶數(shù)據(jù)到內核 copy_from_user(&kdata, buf, sizeof(kdata)); printk("%s:從用戶寫入的數(shù)據(jù) kdata = %#x ", __func__, kdata); return count; //失敗返回負值,成功返回寫入的字節(jié)數(shù)}//定義初始化硬件操作方法static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, //打開設備 .release = led_close, //關閉設備 .read = led_read, //讀取設備 .write = led_write //寫設備};static int led_init(void){ int i; //申請設備號 alloc_chrdev_region(&dev, 0, 1, "tarena"); //初始化字符設備對象 cdev_init(&led_cdev, &led_fops); //注冊字符設備對象到內核 cdev_add(&led_cdev, dev, 1); //申請GPIO資源和配置GPIO為輸出口,輸出0(省電) for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_request(led_info[i].gpio, led_info[i].name); gpio_direction_output(led_info[i].gpio, 0); } return 0;}static void led_exit(void){ int i; //輸出0,釋放GPIO資源 for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_set_value(led_info[i].gpio, 0); gpio_free(led_info[i].gpio); } //卸載字符設備對象 cdev_del(&led_cdev); //釋放設備號 unregister_chrdev_region(dev, 1);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
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
#include #include #include #include int main(void){ int fd; int udata = 0x5555; //定義用戶緩沖區(qū) //打開設備 //open->....->調用led_open fd = open("/dev/myled", O_RDWR); if (fd < 0) { printf("打開設備失敗! "); return -1; } //write->...->調用led_write write(fd, &udata, sizeof(udata)); //關閉設備 //close->...->調用led_close close(fd); return 0;}
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
案例:用戶寫1,開所有的燈;用戶寫0,關所有的燈;
#include #include #include //struct file_operations#include //struct cdev + 設備號#include #include #include //copy_to_user//聲明描述LED硬件相關的數(shù)據(jù)結構struct led_resource { char *name; int gpio;};//定義初始化LED硬件信息static struct led_resource led_info[] = { [0] = { .name = "LED1", .gpio = S5PV210_GPC0(3) }, [1] = { .name = "LED2", .gpio = S5PV210_GPC0(4) }};//定義設備號static dev_t dev;//定義字符設備對象static struct cdev led_cdev;//調用關系:應用程序open->....->led_openstatic int led_open(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 1); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序close->...->led_closestatic int led_close(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 0); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序read->...->led_readstatic ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ //定義初始化內核緩沖區(qū)(存儲空間再后1G虛擬內存中) int kdata = 0x5555; //將內核數(shù)據(jù)上報給用戶 //切記:buf雖然保存的用戶緩沖區(qū)的首地址,但不能直接訪問 //*(int *)buf = kdata;錯誤 copy_to_user(buf, &kdata, sizeof(kdata)); printk("%s ", __func__); return sizeof(kdata); //失敗返回負值,成功返回實際讀取的字節(jié)數(shù)}//調用關系:應用程序write->...->最終調用led_writestatic ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ int i; //定義內核緩沖區(qū) int kdata; //拷貝用戶數(shù)據(jù)到內核 copy_from_user(&kdata, buf, sizeof(kdata)); //開或者關燈 for (i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, kdata); return count; //失敗返回負值,成功返回寫入的字節(jié)數(shù)}//定義初始化硬件操作方法static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, //打開設備 .release = led_close, //關閉設備 .read = led_read, //讀取設備 .write = led_write //寫設備};static int led_init(void){ int i; //申請設備號 alloc_chrdev_region(&dev, 0, 1, "tarena"); //初始化字符設備對象 cdev_init(&led_cdev, &led_fops); //注冊字符設備對象到內核 cdev_add(&led_cdev, dev, 1); //申請GPIO資源和配置GPIO為輸出口,輸出0(省電) for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_request(led_info[i].gpio, led_info[i].name); gpio_direction_output(led_info[i].gpio, 0); } return 0;}static void led_exit(void){ int i; //輸出0,釋放GPIO資源 for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_set_value(led_info[i].gpio, 0); gpio_free(led_info[i].gpio); } //卸載字符設備對象 cdev_del(&led_cdev); //釋放設備號 unregister_chrdev_region(dev, 1);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
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
#include #include #include #include int main(void){ int fd; int udata; //定義用戶緩沖區(qū) //打開設備 //open->....->調用led_open fd = open("/dev/myled", O_RDWR); if (fd < 0) { printf("打開設備失敗! "); return -1; } //write->...->調用led_write while (1) { udata = 1; //開 write(fd, &udata, sizeof(udata)); sleep(1); udata = 0; //關 write(fd, &udata, sizeof(udata)); sleep(1); } //關閉設備 //close->...->調用led_close close(fd); return 0;}
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
案例:用戶能夠指定其中某個燈的開關狀態(tài);
提示:
用戶不僅僅要告訴燈的開關狀態(tài),還要告訴驅動用戶現(xiàn)在要想操作哪個燈;
#include #include #include //struct file_operations#include //struct cdev + 設備號#include #include #include //copy_to_user//聲明LED操作的數(shù)據(jù)結構struct led_cmd { int index; int cmd;};//聲明描述LED硬件相關的數(shù)據(jù)結構struct led_resource { char *name; int gpio;};//定義初始化LED硬件信息static struct led_resource led_info[] = { [0] = { .name = "LED1", .gpio = S5PV210_GPC0(3) }, [1] = { .name = "LED2", .gpio = S5PV210_GPC0(4) }};//定義設備號static dev_t dev;//定義字符設備對象static struct cdev led_cdev;//調用關系:應用程序open->....->led_openstatic int led_open(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 1); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序close->...->led_closestatic int led_close(struct inode *inode, struct file *file){ int i; for(i = 0; i < ARRAY_SIZE(led_info); i++) gpio_set_value(led_info[i].gpio, 0); printk("%s ", __func__); return 0; //執(zhí)行成功返回0,執(zhí)行失敗返回負值 }//調用關系:應用程序read->...->led_readstatic ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ //定義初始化內核緩沖區(qū)(存儲空間再后1G虛擬內存中) int kdata = 0x5555; //將內核數(shù)據(jù)上報給用戶 //切記:buf雖然保存的用戶緩沖區(qū)的首地址,但不能直接訪問 //*(int *)buf = kdata;錯誤 copy_to_user(buf, &kdata, sizeof(kdata)); printk("%s ", __func__); return sizeof(kdata); //失敗返回負值,成功返回實際讀取的字節(jié)數(shù)}//調用關系:應用程序write->...->最終調用led_writestatic ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ //定義內核緩沖區(qū) struct led_cmd kdata; //拷貝用戶數(shù)據(jù)到內核 copy_from_user(&kdata, buf, sizeof(kdata)); //開或者關燈 gpio_set_value(led_info[kdata.index - 1].gpio, kdata.cmd); printk("%s:第%d燈被%s ", __func__, kdata.index, kdata.cmd?"打開":"關閉"); return count; //失敗返回負值,成功返回寫入的字節(jié)數(shù)}//定義初始化硬件操作方法static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, //打開設備 .release = led_close, //關閉設備 .read = led_read, //讀取設備 .write = led_write //寫設備};static int led_init(void){ int i; //申請設備號 alloc_chrdev_region(&dev, 0, 1, "tarena"); //初始化字符設備對象 cdev_init(&led_cdev, &led_fops); //注冊字符設備對象到內核 cdev_add(&led_cdev, dev, 1); //申請GPIO資源和配置GPIO為輸出口,輸出0(省電) for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_request(led_info[i].gpio, led_info[i].name); gpio_direction_output(led_info[i].gpio, 0); } return 0;}static void led_exit(void){ int i; //輸出0,釋放GPIO資源 for (i = 0; i < ARRAY_SIZE(led_info); i++) { gpio_set_value(led_info[i].gpio, 0); gpio_free(led_info[i].gpio); } //卸載字符設備對象 cdev_del(&led_cdev); //釋放設備號 unregister_chrdev_region(dev, 1);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
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
#include #include #include #include //聲明LED操作的數(shù)據(jù)結構struct led_cmd { int index; //指定燈的編號 int cmd; //開關命令};int main(void){ int fd; struct led_cmd udata; //定義用戶緩沖區(qū) //打開設備 //open->....->調用led_open fd = open("/dev/myled", O_RDWR); if (fd < 0) { printf("打開設備失敗!
"); return -1; } //write->...->調用led_write while (1) { udata.index = 1; //第一個燈 udata.cmd = 1; //開 write(fd, &udata, sizeof(udata)); sleep(1); udata.index = 2; //第二個燈 write(fd, &udata, sizeof(udata)); sleep(1); } //關閉設備 //close->...->調用led_close close(fd); return 0;}
?
評論
查看更多