Linux 生成简单字符设备,但设备驱动程序文件不会写入或读取
我正在尝试编写一个简单的字符设备/LKM,用于读取、写入和查找。 我在这方面遇到了很多问题,但我已经花了数周的时间处理它/排除故障,无法让它正常工作。目前,我的模块正确地创建和装载以及卸载,但是如果我尝试回显到设备驱动程序文件,终端就会崩溃,当我尝试使用cat读取时,它返回killd 本模块的步骤: 首先,我通过运行make-C/lib/modules/$(uname-r)/buildm=$pwdmodules来创建模块 对于我的内核,uname-r是4.10.17newkernel 我使用sudo insmod simple\u char\u driver.ko安装模块 如果运行lsmod,将列出该模块 如果运行dmesg,init函数“此设备现在已打开”中的KERN_警报将正确触发 此外,如果我运行sudormmod,该函数“此设备现在已关闭”KERN_警报也会正确触发 该模块也在cat/proc/devices中正确显示 我使用sudomknod-m777/dev/simple_char_驱动程序c240 0在/dev中创建了设备驱动程序文件 在创建此文件之前,我确保240主数字尚未使用 我的设备驱动程序c文件包含以下代码:Linux 生成简单字符设备,但设备驱动程序文件不会写入或读取,linux,module,linux-kernel,linux-device-driver,device-driver,Linux,Module,Linux Kernel,Linux Device Driver,Device Driver,我正在尝试编写一个简单的字符设备/LKM,用于读取、写入和查找。 我在这方面遇到了很多问题,但我已经花了数周的时间处理它/排除故障,无法让它正常工作。目前,我的模块正确地创建和装载以及卸载,但是如果我尝试回显到设备驱动程序文件,终端就会崩溃,当我尝试使用cat读取时,它返回killd 本模块的步骤: 首先,我通过运行make-C/lib/modules/$(uname-r)/buildm=$pwdmodules来创建模块 对于我的内核,uname-r是4.10.17newkernel 我使用su
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<asm/uaccess.h>
#define BUFFER_SIZE 1024
MODULE_LICENSE("GPL");
//minor nunmber 0;
static int place_in_buffer = 0;
static int end_of_buffer = 1024;
static int MAJOR_NUMBER = 240;
char* DEVICE_NAME = "simple_char_driver";
typedef struct{
char* buf;
}buffer;
char *device_buffer;
static int closeCounter=0;
static int openCounter=0;
ssize_t simple_char_driver_read (struct file *pfile, char __user *buffer, size_t length, loff_t *offset){
int bytesRead = 0;
if (*offset >=BUFFER_SIZE){
bytesRead = 0;
}
if (*offset + length > BUFFER_SIZE){
length = BUFFER_SIZE - *offset;
}
printk(KERN_INFO "Reading from device\n");
if (copy_to_user(buffer, device_buffer + *offset, length) != 0){
return -EFAULT;
}
copy_to_user(buffer, device_buffer + *offset, length);
*offset += length;
printk(KERN_ALERT "Read: %s", buffer);
printk(KERN_ALERT "%d bytes read\n", bytesRead);
return 0;
}
ssize_t simple_char_driver_write (struct file *pfile, const char __user *buffer, size_t length, loff_t *offset){
int nb_bytes_to_copy;
if (BUFFER_SIZE - 1 -*offset <= length)
{
nb_bytes_to_copy= BUFFER_SIZE - 1 -*offset;
printk("BUFFER_SIZE - 1 -*offset <= length");
}
else if (BUFFER_SIZE - 1 - *offset > length)
{
nb_bytes_to_copy = length;
printk("BUFFER_SIZE - 1 -*offset > length");
}
printk(KERN_INFO "Writing to device\n");
if (*offset + length > BUFFER_SIZE)
{
printk("sorry, can't do that. ");
return -1;
}
printk("about to copy from device");
copy_from_user(device_buffer + *offset, buffer, nb_bytes_to_copy);
device_buffer[*offset + nb_bytes_to_copy] = '\0';
*offset += nb_bytes_to_copy;
return nb_bytes_to_copy;
}
int simple_char_driver_open (struct inode *pinode, struct file *pfile)
{
printk(KERN_ALERT"This device is now open");
openCounter++;
printk(KERN_ALERT "This device has been opened this many times: %d\n", openCounter);
return 0;
}
int simple_char_driver_close (struct inode *pinode, struct file *pfile)
{
printk(KERN_ALERT"This device is now closed");
closeCounter++;
printk(KERN_ALERT "This device has been closed this many times: %d\n", closeCounter);
return 0;
}
loff_t simple_char_driver_seek (struct file *pfile, loff_t offset, int whence)
{
printk(KERN_ALERT"We are now seeking!");
switch(whence){
case 0:{
if(offset<= end_of_buffer && offset >0){
place_in_buffer = offset;
printk(KERN_ALERT" this is where we are in the buffer: %d\n", place_in_buffer);
}
else{
printk(KERN_ALERT"ERROR you are attempting to go ouside the Buffer");
}
break;//THIS IS SEEK_SET
}
case 1:{
if(((place_in_buffer+offset)<= end_of_buffer)&&((place_in_buffer+offset)>0)){
place_in_buffer = place_in_buffer+offset;
printk(KERN_ALERT" this is where we are in the buffer: %d\n", place_in_buffer);
}
else{
printk(KERN_ALERT"ERROR you are attempting to go ouside the Buffer");
}
break;
}
case 2:{//THIS IS SEEK END
if((end_of_buffer-offset)>=0&& offset>0){
place_in_buffer = end_of_buffer-offset;
printk(KERN_ALERT" this is where we are in the buffer: %d\n", place_in_buffer);
}
else{
printk(KERN_ALERT"ERROR you are attempting to go ouside the Buffer");
}
break;
}
default:{
}
}
printk(KERN_ALERT"I sought %d\n", whence);
return place_in_buffer;
}
struct file_operations simple_char_driver_file_operations = {
.owner = THIS_MODULE,
.read = simple_char_driver_read,
.write = simple_char_driver_write,
.open = simple_char_driver_open,
.llseek = &simple_char_driver_seek,
.release = simple_char_driver_close,
};
static int simple_char_driver_init(void)
{
printk(KERN_ALERT "inside %s function\n",__FUNCTION__);
register_chrdev(MAJOR_NUMBER,DEVICE_NAME, &simple_char_driver_file_operations);
device_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
return 0;
}
static void simple_char_driver_exit(void)
{
printk(KERN_ALERT "inside %s function\n",__FUNCTION__);
unregister_chrdev(MAJOR_NUMBER, DEVICE_NAME);
kfree(device_buffer);
}
module_init(simple_char_driver_init);
module_exit(simple_char_driver_exit);
#包括
#包括
#包括
#包括
#包括
#定义缓冲区大小1024
模块许可证(“GPL”);
//小数目0;
静态int将_放入_缓冲区=0;
_缓冲区的静态int end_=1024;
静态int MAJOR_编号=240;
char*DEVICE\u NAME=“simple\u char\u driver”;
类型定义结构{
char*buf;
}缓冲器;
字符*设备缓冲区;
静态int closeCounter=0;
静态int-openCounter=0;
简单字符驱动程序读取(结构文件*pfile,字符用户*buffer,大小长度,loff*t偏移量){
int字节读取=0;
如果(*偏移量>=缓冲区大小){
字节读取=0;
}
如果(*偏移+长度>缓冲区大小){
长度=缓冲区大小-*偏移量;
}
printk(内核信息“从设备读取”);
如果(复制到用户(缓冲区、设备缓冲区+*偏移量、长度)!=0){
返回-默认值;
}
复制到用户(缓冲区、设备缓冲区+*偏移量、长度);
*偏移量+=长度;
printk(内核警报“读取:%s”,缓冲区);
printk(内核警报“%d字节读取”,字节读取);
返回0;
}
简单字符驱动程序写入(结构文件*pfile,常量字符*user*缓冲区,大小长度,loff*t偏移量){
int nb_字节到_副本;
if(缓冲区大小-1-*偏移长度)
{
nb_字节到副本=长度;
printk(“缓冲区大小-1-*偏移>长度”);
}
printk(内核信息“写入设备”\n);
如果(*偏移+长度>缓冲区大小)
{
printk(“对不起,不能那样做。”);
返回-1;
}
printk(“即将从设备复制”);
从用户复制(设备缓冲区+*偏移量、缓冲区、nb字节复制到用户);
设备缓冲区[*偏移量+nb字节到拷贝]='\0';
*偏移量+=nb_字节到_拷贝;
将nb_字节返回到_副本;
}
int simple_char_driver_open(结构索引节点*pinode,结构文件*pfile)
{
printk(KERN_警报“此设备现在已打开”);
openCounter++;
printk(KERN_ALERT“此设备已被打开此多次:%d\n”,openCounter);
返回0;
}
int simple\u char\u driver\u close(结构索引节点*pinode,结构文件*pfile)
{
printk(KERN_ALERT“此设备现已关闭”);
closeCounter++;
printk(KERN_ALERT“此设备已关闭此多次:%d\n”,closeCounter);
返回0;
}
loff\u t simple\u char\u driver\u seek(结构文件*pfile,loff\u t offset,int where)
{
printk(KERN_警报“我们正在寻找!”);
开关(从何处){
案例0:{
如果(抵销0){
将_放入_缓冲区=偏移量;
printk(KERN\u警报“这是我们在缓冲区中的位置:%d\n”,将\u放入\u缓冲区);
}
否则{
printk(KERN_ALERT“您试图移出缓冲区时出错”);
}
break;//这是SEEK\u集
}
案例1:{
如果((将_放入_缓冲区+偏移量)0)){
将_放入_缓冲区=将_放入_缓冲区+偏移量;
printk(KERN\u警报“这是我们在缓冲区中的位置:%d\n”,将\u放入\u缓冲区);
}
否则{
printk(KERN_ALERT“您试图移出缓冲区时出错”);
}
打破
}
案例2:{//这是搜索结束
如果((缓冲区的结束偏移量)>=0&&offset>0){
将_放入_buffer=_buffer-offset的结束_;
printk(KERN\u警报“这是我们在缓冲区中的位置:%d\n”,将\u放入\u缓冲区);
}
否则{
printk(KERN_ALERT“您试图移出缓冲区时出错”);
}
打破
}
默认值:{
}
}
printk(内核警报“我寻找了%d\n”,从哪里来);
返回放置在缓冲区中的位置;
}
结构文件\u操作简单\u字符\u驱动程序\u文件\u操作={
.owner=此_模块,
.read=简单字符驱动程序读取,
.write=simple\u char\u driver\u write,
.open=简单字符驱动程序打开,
.llseek=&simple\u char\u driver\u seek,
.release=simple\u char\u driver\u close,
};
静态int简单字符驱动程序初始化(void)
{
printk(内核警报“在%s函数内”\n“,\uu函数\uuuu);
寄存器chrdev(主设备号、设备名和简单字符驱动程序文件操作);
设备缓冲区=kmalloc(缓冲区大小,GFP内核);
返回0;
}
静态无效简单字符驱动程序退出(无效)
{
printk(内核警报“在%s函数内”\n“,\uu函数\uuuu);
注销chrdev(主要设备编号、设备名称);
kfree(设备缓冲区);
}
模块初始化(简单字符驱动初始化);
模块退出(简单字符驱动程序退出);
正如我前面所说的,这个文件可以正确地创建,没有错误或警告。
但是,当前如果我尝试回显到设备文件
使用:echo“hello world”>>/dev/simple\u char\u驱动程序
我使用的终端崩溃了
如果我不能
ssize_t simple_char_driver_read (struct file *pfile, char __user *buffer, size_t length, loff_t *offset)
{
if (*offset > BUFFER_SIZE)
{
printk("offset is greater than buffer size");
return 0;
}
if (*offset + length > BUFFER_SIZE)
{
length = BUFFER_SIZE - *offset;
}
if (copy_to_user(buffer, device_buffer + *offset, length) != 0)
{
return -EFAULT;
}
*offset += length;
return length;
}
ssize_t simple_char_driver_write (struct file *pfile, const char __user *buffer, size_t length, loff_t *offset){
/* *buffer is the userspace buffer where you are writing the data you want to be written in the device file*/
/* length is the length of the userspace buffer*/
/* current position of the opened file*/
/* copy_from_user function: destination is device_buffer and source is the userspace buffer *buffer */
int nb_bytes_to_copy;
if (BUFFER_SIZE - 1 -*offset <= length)
{
nb_bytes_to_copy= BUFFER_SIZE - 1 -*offset;
printk("BUFFER_SIZE - 1 -*offset <= length");
}
else if (BUFFER_SIZE - 1 - *offset > length)
{
nb_bytes_to_copy = length;
printk("BUFFER_SIZE - 1 -*offset > length");
}
printk(KERN_INFO "Writing to device\n");
if (*offset + length > BUFFER_SIZE)
{
printk("sorry, can't do that. ");
return -1;
}
printk("about to copy from device");
copy_from_user(device_buffer + *offset, buffer, nb_bytes_to_copy);
device_buffer[*offset + nb_bytes_to_copy] = '\0';
*offset += nb_bytes_to_copy;
return nb_bytes_to_copy;
}
copy_from_user(device_buffer + *offset, buffer, nb_bytes_to_copy);
device_buffer[*offset + nb_bytes_copy] = '\0';