在学习了字符设备驱动的两种模板框架程序后,下面就用实例程序来验证一下。
实验例程源码保存在光盘的“i.MX6UL终结者光盘资料/06_Linux驱动例程/01_chartest”这个目录下。
我们用chartest这个虚拟设备为例,完整的编写一个字符设备驱动程序。chartest是一个虚拟的字符设备,只是为了讲解字符设备驱动,后面的章节中会介绍实际的硬件驱动程序。
chartest虚拟设备实现的功能:在设备中存在两个缓冲区,一个读缓冲,一个写缓冲,缓冲区的大小为100字节。在应用程序中可以通过读写函数来使用这个设备。
1 常规字符驱动程序
创建chartest_manual_major.c文件(光盘的“i.MX6UL终结者光盘资料/06_Linux驱动例程/01_chartest/chartest_manual_major.c),编写好的chartest驱动程序如下所示(注意每行前面的行号不要复制):
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/delay.h>
4 #include <linux/ide.h>
5 #include <linux/init.h>
6 #include <linux/module.h>
7
8 #define CHRDEVBASE_MAJOR 200 /* 主设备号 */
9 #define CHRDEVBASE_NAME "chartest" /* 设备名 */
10 dev_t devno;
11 struct cdev *cdev;
12 static char readbuf[100]; /* 读缓冲区 */
13 static char writebuf[100]; /* 写缓冲区 */
14 static char kerneldata[] = {
"kernel data!"};
15
16 /*
17 * @description : 打开设备
18 * @param – inode : 传递给驱动的 inode
19 * @param - filp : 设备文件,file 结构体有个叫做 private_data 的成员变量
20 * 一般在 open 的时候将 private_data 指向设备结构体。
21 * @return : 0 成功;其他 失败
22 */
23 static int chartest_open(struct inode *inode, struct file *filp)
24 {
25 printk("chartest open!\r\n");
26 return 0;
27 }
28
29 /*
30 * @description : 从设备读取数据
31 * @param - filp : 要打开的设备文件(文件描述符)
32 * @param - buf : 返回给用户空间的数据缓冲区
33 * @param - cnt : 要读取的数据长度
34 * @param - offt : 相对于文件首地址的偏移
35 * @return : 读取的字节数,如果为负值,表示读取失败
36 */
37 static ssize_t chartest_read(struct file *filp, char __user *buf,
38 size_t cnt, loff_t *offt)
39 {
40 int retvalue = 0;
41
42 /* 向用户空间发送数据 */
43 memcpy(readbuf, kerneldata, sizeof(kerneldata));
44 retvalue = copy_to_user(buf, readbuf, cnt);
45 if(retvalue == 0){
46 printk("kernel senddata ok!\r\n");
47 }else{
48 printk("kernel senddata failed!\r\n");
49 }
50
51 //printk("chartest read!\r\n");
52 return 0;
53 }
54
55 /*
56 * @description : 向设备写数据
57 * @param - filp : 设备文件,表示打开的文件描述符
58 * @param - buf : 要写给设备写入的数据
59 * @param - cnt : 要写入的数据长度
60 * @param - offt : 相对于文件首地址的偏移
61 * @return : 写入的字节数,如果为负值,表示写入失败
62 */
63 static ssize_t chartest_write(struct file *filp,
64 const char __user *buf,
65 size_t cnt, loff_t *offt)
66 {
67 int retvalue = 0;
68 /* 接收用户空间传递给内核的数据并且打印出来 */
69 retvalue