Major and Minor Numbers - What, Representation, Allocation, Freeing, Sample, Queries

They are two types of files in Linux:
1. Normal or regular files : hello.txt, test.txt
2. Device or Special Files : /dev/zero, /dev/null

Special or Device files are located in /dev directory. These are of two types:
1. char device files: Identified by a "c" in the first column of the output of ls -l command
2. Block device files: Identified by a "b" in the first column of the output of ls -l command

Character and block devices are represented in Linux Kernel as pair of <major number>:<minor number>.

Major and Minor Number:

With "ls -l /dev" command, you can find the major and minor number of the particular device.



Major Number: Each character and block driver registered with the kernel has a major number. It's used to identify the driver.  Kernel uses major number at open call to forward execution to the appropriate driver

Minor Number: A single driver can control various hardware, or support multiple instances of the same hardware, minor number is used to distinguish between the various hardware it controls. Minor number is used by only the driver mentioned by the major number.

How are major and minor numbers stored/represented in Linux Kernel

Kernel uses dev_t data type to store both major and minor number.

Definition is present in <linux/types.h> header file.



dev_t is a 32-bit unsigned integer. Where 12 upper most bits are used to store the major number and the remaining lower most 20 bits are used to store the minor number. Note: Don't Extract the major and minor number directly.

Macros provided by Linux Kernel for Major and Minor Number

Header File: <linux/kdev_t.h>



Are Major and Minor numbers unique

Yes, Major, Minor combination are unique. Note that character and block devices have distinct numbering spaces, e.g. Major number 1 of block is assigned for RAM disks and Major number 1 of char is assigned to a set of kernel devices such as /dev/zero and /dev/null.

How are major and minor number assigned to drivers

There are two ways of a driver assigning major and minor number.
1. Static Assignment
2. Dynamic Assignment

Please note that some of the major and minor number are already reserved. You can refer Documentation/admin-guide/devices.txt for more information. Major number 230-254, 384-511 are reserved for Dynamic assignment.

Static Assignment:

register_chrdev_region is the function to allocate device number statically.

Declared in <linux/fs.h>

int register_chrdev_region(dev_t first, unsigned int count,
                                            char *name);

Arguments:

  • first -> First device number of the range you would like to allocate
  • count -> Maximum number of devices to support.
  • name -> Name of the device. It will appear in /proc/devices and sysfs

Return Value: On success 0 is returned else a negative error code on error


Dynamic Assignment:

alloc_chrdev_region is the kernel function to allocate device numbers dynamically

Declared in <linux/fs.h>

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);

Arguments:


  • dev -> On success, contains the first device number
  • firstminor -> Requested first minor number to use, usually 0
  • count -> Maximum number of devices to support
  • name -> Name of the device. It will appear in /proc/devices and sysfs

Return Value: On success 0 is returned else a negative error code on error

UnAllocating Device Number ( Major and Minor Number )

Regardless of static or dynamic, use this function to free the device numbers in your cleanup function.

void unregister_chrdev_region(dev_t first, unsigned int count);

Arguments:
  • first -> The first device number allocated
  • count -> Number of device numbers requested while allocating.

How can we find out what all device numbers have been already used.

cat /proc/devices will list all the character and block device numbers being used.



Sample Code to assign Major and Minor Number

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/fs.h>

MODULE_LICENSE("GPL");
dev_t device_number;
bool dynamic = false;
#define MAX_DEVICES 5
static int test_static_init(void)
{
    int retval;
    printk(KERN_INFO"%s: In init\n", __func__);
    if (dynamic) {
        retval = alloc_chrdev_region(&device_number, 0, 5, "embedded");
    }
    else {
        device_number = MKDEV(240, 0);
        retval = register_chrdev_region(device_number, 5, "embedded");
    }
    if (!retval)
        printk(KERN_INFO"%s: Major Number:%d\t Minor Number:%d\n",
                __func__, MAJOR(device_number), MINOR(device_number));
    else
        printk(KERN_ERR"%s: Failed in allocating device number "
                "Error:%d\n", __func__, retval);
    return 0;
}

static void test_static_exit(void)
{
    unregister_chrdev_region(device_number, 5);
    printk(KERN_INFO"%s: In exit\n", __func__);
}

module_init(test_static_init);

module_exit(test_static_exit);

What will happen when we try to statically assign the same device number which is already in use?

We get -EBUSY error


Comments

Popular posts from this blog

bb.utils.contains yocto

make config vs oldconfig vs defconfig vs menuconfig vs savedefconfig

PR, PN and PV Variable in Yocto