Linux 生成简单字符设备,但设备驱动程序文件不会写入或读取

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

我正在尝试编写一个简单的字符设备/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文件包含以下代码:

#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';