Miscellaneous Devices in Linux Drivers

1. The Three Major Types of Linux Device Drivers

1. Character Devices: The IO transfer process is done in characters without buffering, such as I2C and SPI, which are character devices.

2. Block Devices: The IO transfer process is done in blocks, related to storage, such as TF cards.

3. Network Devices: Unlike the previous two, these are accessed via socket.

Miscellaneous devices are a type of character device that can automatically generate nodes.

2. Miscellaneous Devices

1. Our system has many miscellaneous devices, which we can view by entering the command cat /proc/misc.

Miscellaneous Devices in Linux Drivers

The major device number for miscellaneous devices is the same, which is 10, while the minor device numbers are different. The benefit of having the same major device number is that it saves kernel resources.

2. Major and Minor Device Numbers

  • The device number consists of a major device number and a minor device number. The major device number is unique in the Linux system, while the minor device number is not necessarily unique.

  • The device number is a way for the computer to identify devices; devices with the same device number are considered the same type of device.

  • The major device number can be compared to the area code of a phone number, such as 010 for Beijing, while the minor device number is analogous to the phone number itself.

  • The major device number can be viewed using the command cat /proc/devices.

    Miscellaneous Devices in Linux Drivers

// Path: kernel-3.18/include/linux/miscdevice.h
struct miscdevice  {
    int minor;  // Minor device number
    const char *name; // Name of the device node
    const struct file_operations *fops; // File operation set
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const char *nodename;
    umode_t mode;
};

3. Description of the File Operation Set file_operations

// Path: kernel-3.18/include/linux/fs.h
struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iterate) (struct file *, struct dir_context *);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **, void **);
    long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
    int (*show_fdinfo)(struct seq_file *m, struct file *f);
};

Each member of file_operations corresponds to a call. It looks complex, but we only need to focus on four commonly used members.

read, write, open, release
The four members in <code>file_operations correspond to the upper-level application functions read(), write(), open(), and release().

4. Registration and Deregistration of Miscellaneous Devices

extern int misc_register(struct miscdevice *misc); // Register miscellaneous device
extern int misc_deregister(struct miscdevice *misc); // Deregister miscellaneous device

Process of Registering a Miscellaneous Device

(1) Fill in the miscdevice structure.

(2) Fill in the file_operations structure.

(3) Register the miscellaneous device with the kernel and generate the device node.

// Template for registering a miscellaneous device
struct file_operations xxfops = { // Fill in the <code>file_operations structure
    .owner = THIS_MODULE
    .......
};
struct miscdevice xx_dev = { // Fill in the miscdevice structure
    .minor = MISC_DYNAMIC_MINOR,
    .name  = "xxx",
    .fops  = &xxfops
};
static int xxx_init() {
    int ret;
    ret = misc_register(&xx_dev); // Register miscellaneous device
    if (ret < 0) {
        printk("misc register error !!!\n");
        return -1;
    }
    printk("misc register succeed!!!\n");
    return 0;
}
void xxx_exit() {
    misc_deregister(&xx_dev); // Deregister miscellaneous device
}

5. Experimental Practice

Requirement: Register a miscellaneous device according to the registration process and generate a device node.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
struct file_operations misc_fops = {
    .owner = THIS_MODULE
};
struct miscdevice msic_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name  = "hello_misc",
    .fops  = &misc_fops
};
static int misc_init(void) {
    int ret = 0;
    ret = misc_register(&msic_dev);
    if (ret < 0) {
        printk("misc register is error\n");
        return -1;
    }
    printk("misc register is succeed\n");
    return 0;
}
static void misc_eixt(void) {
    printk("misc bye bye\n");
}
module_init(misc_init);
module_exit(misc_eixt);
MODULE_LICENSE("GPL");

6. Experimental ResultsMiscellaneous Devices in Linux Drivers

Leave a Comment