In linux, every device under /dev is associated with two numbers "major number" and the minor number.
Where the major number represents the driver that the device is being controlled by and the minor number is the number that the driver uses to recognize the device so that even if the same driver controls multiple devices it can defferentiate between them.
In the kernel versions before 2.6 these two numbers were 8 bit numbers thus allowing only 256 drivers with each controlling maximum of 256 devices.
But this was not enough for the modern systems like the big servers which have a large number of devices connected to them.
Thus from 2.6 these two numbers are combined and stored in one 32 bit number of the data type dev_t. Out of the 32 bits the MSB 12 bits represent the major number and the LSB 20 bits represent the minor number.
Thus when we allocate a major number dynamically in a driver the kernel fills up the variable dev_t with the combination of the major number and the first minor that we requested for.
Given a dev_t number we can extract the major number and minor number using the macros MAJOR and MINOR respectively.
And given two integer numbers we can combine them and convert them into one dev_t using the macro MKDEV.
These three macros are defined in the header file linux/kdev_t.h as shown below.
MAJOR
The macro MAJOR accepts a dev_t type number which is 32 bits, and right shits it by MINORBITS which is defined as 20 bits as shown above.
To see how this works let us take dev_t to be a 6 bit number, with MSB 2 bits being the major number and the LSB 4 bits being the minor.
let dev_t be 33 i.e. 100001 in binary .
To extract the major number that is the first two bits we will have to right shift it 4 times.
Which gives the result 2, thus the major number is 2.
Similarly the macro MAJOR shifts dev_t by 20 bits to extract the major number.
MINOR
The minor number is stored in the lower 20 bits, to extract that we will have to mask the first
12 bits i.e. make them as 0.
Taking the same example as above
Let dev_t = 33 i.e. 100001
We create a mask 001111, which when anded with 100001 should extract the LSB 4 bits as the MSB 2 bits when anded with 0 will always be 0.
This mask is created by taking the number 1 => 000001
Left shifting it by MINORBITS that is 4 in our example
Thus the mask becomes 010000.
Now subtract this with 000001
The mask 001111 is anded bitwise with 100001
Thus we are able to extract the lower 4 bits,0001, which is the minor number .
Macro MINOR retrives the minor number in the same way except that it shifts 1 by 20 bits.
MKDEV
Given two integers, MKDEV combines them into one 32 bit number.
This is done by left shifting the major number MINORBIT times i.e. 20 times and then oring the result with the minor number.
For e.g. if the major number is 2 => 000010 and the minor number is 1 => 000001
Then left shift 2, 4 times
Then or this with the minor number
The result,100001, is the dev_t after combining the major number 2 with minor number 1.
The macro MKDEV works in the same way except that it is a 32 bit number.