How to Assign a Character Device Number to a Linux Character Device Driver

Beaglebone black board

In this article, we show how to assign a character device number to a linux character device.

This is really the first step in creating a character device driver in linux.

The first thing we must do in the process is assign a device number to the character device.

The reason a character must have a unique assigned number is to be able to positively identify the device. And this is done through a device number.

Each device connected to a linux operating system must have a unique character device number.

This character device number consists of a major number and a minor number. Examples are 4:0, 126:0, 127:1. These numbers may all be used to represent devices connected to the linux operating system.

The combination of the major and minor number must be completely unique to each device. This allows for the positive identification of each device connected to the linux operating system.

Usually, devices of different kinds will have different major numbers.

For example, an RTC clock may have a major number 111. A keyboard may have a major number of 120. A mouse may have a major number of 121.

If devices are the same and there are multiple of them used in the operating system, then they may have the same major number and different minor numbers.

For example, if we were connecting 4 rtc clocks to our linux operating system, it makes sense for them to have the same major number, since they're the same device. However, to differentiate them, because they are each separate devices, they would have different minor numbers. So the rtc clocks may have character driver numbers, 127:0, 127:1, 127:2, and 127:3.

If you go to the /dev directory and run the command, ls -l, you can see the character device number, the major and minor number, for each device.

This can be seen below.

Checking the character device number- major and minor- in linux

So let's just go over this for a moment.

So you can at the very top a device named rtc0.

It is the only rtc device; therefore, it has a unique major number, 248, that isn't seen anywhere else.

Now let's look right underneath it, where we see sda, which is a hard drive. This has a character device number of 8:0.

Right under it, we see sda1, sda2, and sda5.

All of these have the same major device numbers.

And this makes sense, because sda1, sda2, and sda5 are partitions of the hard drive, so they're all part of the same component, just different sections.

Let's look at tty0, which represents a serial port. This has a character device number of 4:0

Now let's look at some of the others like tty1, tty10, tty11, tty12, etc.

Notice these all have the same major numbers and different minor numbers.

So now you understand the device number convention for devices in linux.

This is important because this will help you in the process of assigning numbers to a device. Even though you won't allocate the major number, you do allocate minor numbers. So if you are using, for example, mulitple sensors, which is common for certain setups (for example, a self-driving cars uses multiple radar sensors, lidar sensors, or cameras to see or sense a road), you won't create different major numbers for each sensor. Instead, you will just allocate one major number for a sensor (of the same type, such as radar and a different one for another type of sensor such as lidar) and then each subsequent sensor (of the same type) will get a different minor number. In that way, you will be following linux character device number convention.

So that we know how the convention is, how do we assign a character device number to a character device?

How this is done is we don't choose the major number for a device. This is dynamically allocated by the system. Because if we chose our own number, it may conflict with a device already on our system that has the same number. Therefore, it's always allocated dynamically by code.

However, we do specify if there are multiple devices (which means multiple minor numbers needed) and the name of the device.

This is all done in the kernel by kernel services and APIs.

Assigning a device number to a character drive is done through the alloc_chrdev_region() function in linux.

This is a function obtained from the fs.h header file which is found in the /include/linux/ directory. The full path to the file is /linux/fs.h

Just so that you see exactly what we're working with, go to the linux directory and check out the fs.h header file.

You will see that within this file is the extern function of the alloc_chrdev_region(), which is needed in order to assign a unique number to a character device.

This is shown below.

alloc_chrdev_region() function in fs.h file in linux operating system

So you can see there are a whole bunch of external functions.

What this means is that the function is defined elsewhere in other code.

So where is this alloc_chrdev_region() function completely defined (rather than just an extern representation)?

The alloc_chrdev_region() function is completely defined in the chr_dev.c file in the /linux/fs/ directory.

This is shown below.

alloc_chrdev_region() function in char_dev.c file in the linux operating system

So you can see this function takes in 4 parameters, dev, which is a pointer variable, baseminor which represents the starting index of the minor numbers, count which represents how many minor numbers will be present, and the another pointer variable, name, which holds the name of the character device.

We don't give a value to the *dev pointer variable, because if you look at the code, the *dev variable is already assigned a number which is made up of 2 components, major and baseminor. baseminor is the number we assign it when we use the function. major is assigned by the code dynamically through the __register_chrdev_region() function.

So let's start again.

So the general format for the alloc_chrdev_region() function is as shown below.

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

So one thing you should know is that, dev_t is a typedef which is of type unsigned int 32.

What you have to do is create a variable of dev_t and the program will automatically update that variable. You'll see this in the code below.

baseminor is usually almost always 0, since 0 is the first index for any new character device in regards to the minor number.

count is how many minor numbers are needed. If there is only a single device, this will be 1. Otherwise, you enter in the amount of devices you are creating numbers for. For example, 4 radar sensors will be 4.

Lastly, we give the character device a name. If it is a sensor, you can name it according to the sensor such as "radar".

Go to your home directory, the same directory the source code for your linux kernel, and create a directory named custom_drivers and within this directory create another directory called character_drivers (or you can simply just create one directory of character_drivers, if you prefer).

Within this directory, add a makefile by entering in, touch Makefile.

Within this makefile, add the following contents seen in this text file (containing Makefile). You do this by entering in, vim Makefile

Now add a main.c file by entering in, touch main.c

Now go into the file and add in the following contents shown below by entering in, vim main.c

Below is the all the code needed for the assignment of a character number to a character device.

So right now this is all you need to assign a character device number to a character device.

What we create in this code is a pseudo character device, representing a block of memory that is 512 bits in size. The module.h header file is to always be included and we include the fs.h file because it contains the alloc_chrdev_region() function needed to assign a character device number to our character device.

We create a singular character device named "pcd".

This file should look like that shown below.

Assignment of a character device number in linux source code

If you save this file by entering in wq and then go back to the linux terminal and be in the character_drivers directory.

Now type in, make host

If all goes well, you should see that you have no errors in your code, as can be seen below.

Assignment of a character device number in linux source code build

So now you have successfully assigned a character device number to a character device.

The next step in the process to creating a character device driver is to register the character device number with the VFS (virtual file system).

So this is how to assign a character device number to a character device in linux.

Related Resources

HTML Comment Box is loading comments...