简体   繁体   中英

Linux Device Driver — file operations not working

I have recently updated my kernel and I am no longer able to use a previously written device drivers. My driver's init and exit functions work fine and log a message to the kernel log. However, I am no longer able to write , read , ioctl , open , or release the file. The functions do not print anything into the log file. I am compiling against 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);

You should add terminating "\n" at the end of your prints to force their flush into the kernel log buffer. Here is your module with some enhancement suggestions:

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

Check the current settings for the kernel log level .

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

In the preceding, the first column specifies that only messages with a log level lower than 4 will be printed.

The values accepted by printk() are:

   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

So, the KERN_INFO level is 6 which is greater than 4!

We modify the configuration:

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

I built your module with the suggested modifications and tried it on Linux 5.4.0-58:

$ uname -a
Linux xxxx  #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] 
$ 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] 
[ 7311.507672] 
[ 7311.507677] 
$ 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] 
$ sudo rm /dev/device

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM