Linux 设备驱动程序——文件操作不起作用

时间:2021-01-03 01:46:21

标签: c linux linux-kernel linux-device-driver

我最近更新了内核,但无法再使用以前编写的设备驱动程序。我的驱动程序的 initexit 功能运行良好,并将一条消息记录到内核日志中。但是,我不再能够ioctl打开释放< /em> 文件。这些函数不会将任何内容打印到日志文件中。我正在编译 linux-headers-5.4.79-v7l+。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>


MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "device"

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static long int device_ioctl(struct file *, unsigned int, unsigned long);

static struct file_operations fops =
{
    owner: THIS_MODULE,
    read: device_read,
    write:device_write,
    unlocked_ioctl: device_ioctl,
    open: device_open,
    release: device_release

};

struct cdev *device_cdev;
dev_t deviceNumbers;

static int init(void)
{
    int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);

    if (ret < 0) {
        printk(KERN_ALERT "Error registering: %d", ret);
        return -1;
    }

    device_cdev = cdev_alloc();

    cdev_init(device_cdev, &fops);

    ret = cdev_add(device_cdev, deviceNumbers, 1);

    printk(KERN_INFO "Device initialized");

    return 0;
}

static void cleanup(void)
{
    unregister_chrdev_region(deviceNumbers, 1);

    cdev_del(device_cdev);

    printk(KERN_INFO "Device unloaded");
}

static int device_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "Device open");
    return 0;
}


static int device_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "Device released");
    return 0;
}


static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
    printk(KERN_INFO "Device write");
    return 0;
}

static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
    printk(KERN_INFO "Device read");
    return 0;
}

static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
    printk(KERN_INFO "Device IOCTL");
    return 0;
}


module_init(init);
module_exit(cleanup);

1 个答案:

答案 0 :(得分:3)

您应该在打印的末尾添加终止“\n”以强制将它们刷新到内核日志缓冲区中。这是您的模块,其中包含一些增强建议:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>


MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "device"

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static long int device_ioctl(struct file *, unsigned int, unsigned long);

static const struct file_operations fops =
{
    .owner= THIS_MODULE,
    .read= device_read,
    .write=device_write,
    .unlocked_ioctl= device_ioctl,
    .open= device_open,
    .release= device_release

};

struct cdev *device_cdev;
dev_t deviceNumbers;

static  int __init init(void)  // <------ Add __init keyword for kernel cleanups
{
    // This returns the major number chosen dynamically in deviceNumbers
    int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);

    if (ret < 0) {
        printk(KERN_ALERT "Error registering: %d\n", ret);
        return -1;
    }

    device_cdev = cdev_alloc();

    cdev_init(device_cdev, &fops);

    ret = cdev_add(device_cdev, deviceNumbers, 1);

    printk(KERN_INFO "Device initialized (major number is %d)\n", MAJOR(deviceNumbers));

    return 0;
}

static void __exit cleanup(void)  // <------ Add __exit keyword for kernel cleanups
{
    unregister_chrdev_region(deviceNumbers, 1);

    cdev_del(device_cdev);

    printk(KERN_INFO "Device unloaded\n");
}

static int device_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "Device open\n");
    return 0;
}


static int device_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "Device released\n");
    return 0;
}


static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
    printk(KERN_INFO "Device write\n");
    return len;  // <-------------- To stop the write
}

static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
    printk(KERN_INFO "Device read\n");
    return len; // <-------------- To stop the read
}

static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
    printk(KERN_INFO "Device IOCTL\n");
    return 0;
}


module_init(init);
module_exit(cleanup);

检查 kernel log level 的当前设置。

$ cat /proc/sys/kernel/printk
4   4   1   7

在前面,第一列指定只打印日志级别低于 4 的消息。

printk() 接受的值是:

   KERN_EMERG             0        System is unusable
   KERN_ALERT             1        Action must be taken immediately
   KERN_CRIT              2        Critical conditions
   KERN_ERR               3        Error conditions
   KERN_WARNING           4        Warning conditions
   KERN_NOTICE            5        Normal but significant condition
   KERN_INFO              6        Informational
   KERN_DEBUG             7        Debug-level messages

因此,KERN_INFO 级别是 6,它大于 4!

我们修改配置:

$ sudo sh -c "echo 7 4 1 7 > /proc/sys/kernel/printk"
$ cat /proc/sys/kernel/printk
7   4   1   7

我按照建议的修改构建了您的模块,并在 Linux 5.4.0-58 上进行了尝试:

$ uname -a
Linux xxxx 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ sudo insmod ./device.ko
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
$ lsmod
Module                  Size  Used by
device                 16384  0
[...]
$ cat /proc/devices
Character devices:
[...]
235 device
$ sudo mknod /dev/device c 235 0
$  ls -l /dev/device
crw-r--r-- 1 root root 235, 0 janv.   3 10:33 /dev/device
$ sudo sh -c "echo foo > /dev/device"
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
$ sudo rmmod device
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
[ 7361.523964] Device unloaded
$ sudo rm /dev/device