Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
89 views
in Technique[技术] by (71.8m points)

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

question from:https://stackoverflow.com/questions/65545916/linux-device-driver-file-operations-not-working

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should add terminating " " 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
", 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)
", 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
");
}

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...