chrdevbase设备有两个缓冲区(读/写),大小均为100字节,可在应用程序中进行基础的写入和读取数据操作。
应用程序实现步骤为:1)调用open函数打开chrdevbase设备;2)使用write函数向chrdevbase设备的缓冲区writebuf中写入数据或使用read函数读取缓冲区readbuf中的数据;3)使用close函数关闭chrdevbase设备。
驱动程序及解析
1 头文件导入
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
这些头文件为开发字符设备驱动程序提供了必要的工具和接口。在一个字符设备驱动程序中,开发者通常需要管理设备的打开、读写、关闭等操作,同时与硬件进行交互,并处理可能出现的延迟或错误。通过包含这些头文件,开发者可以使用 Linux 内核提供的标准化工具和功能来简化驱动程序的开发过程
2 参数定义
#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名称 */
static char readbuf[100]; /* 读缓冲区 */
static char writebuf[100]; /* 写缓冲区 */
static char kerneldata[] = {"kernel data"}:
主设备号用于区分不同的设备驱动程序,设备名称是字符设备的标识符,"static"关键字用于指定"readbuf"的存储类为静态,意味着它的生命周期贯穿整个驱动程序的运行过程,100表示字节长度,"kerneldata"是一个静态字符数组,被初始化成一个字符串。
3 打开设备
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
//printk("chrdevbase open!\r\n")
return 0;
}
"static"表示这个函数的作用域仅限于这个源文件内,其他文件不能直接调用这个函数。"struct inode *inode"为指向"inode"结构体的指针,表示正在被打开的设备文件的索引节点,"struct file *filp"是指向"file"结构体的指针,表示与文件操作相关的信息。
4 从设备读取数据
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 向用户空间发送数据 */
memcpy(readbuf, kerneldata, sizeof(kerneldata));
retvalue = copy_to_user(buf, readbuf, cnt);
if(retvalue == 0){
printk("kernel senddata ok!\r\n");
}else{
printk("kernel senddata failed!\r\n");
}
//printk("chrdevbase read!\r\n");
return 0;
}
"ssize_t"表示可以返回读取的字节数,或错误代码(如负值),cnt为需要读取的字节数,offt为文件的偏移量指针,表示从文件的哪个位置开始读。memcpy函数从kerneldata拷贝数据到readbuf,sizeof(kerneldata)确保了memcpy的字节数与kerneldata的大小一致。copy_to_user是一个内核函数,尝试将readbuf中cnt个字节的数据复制到用户空间的buf。
5 向设备写数据
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 接收用户空间传递给内核的数据并且打印出来 */
retvalue = copy_to_user(writebuf, buf, cnt);
if(retvalue == 0){
printk("kernel recevdata:%s\r\n", writebuf);
}else{
printk("kernel recevdata failed!\r\n");
}
//printk("chrdevbase write!\r\n");
return 0;
}
注意copy_to_user的参数格式一般如下:
long copy_to_user(void *to, const void *from, unsigned long n);
其中,to表示目标地址、from为源地址、n为要复制的字节数。