I am learning Linux device driver and got stuck on the major, minor numbers. What I have so far is:
Devices are accessed through names in the file system. Those names are called as special files or device files or inodes of the file system.
And each of the device files are associated with the MAJOR and MINOR numbers bundled into a dev_t
type.
register_chrdev_region
Some of the Questions are yet troubling me...
fops
structure is linked to the f_ops
field of file structure
of the device file when we initialize device like cdev_init(&c_dev, &fops);
?open("/dev/mydev", O_RONLY);
actually calls the open()
function of the drivers. Does numbers comes in picture here
to find the actual write method of device driver, if yes how?open()
read()
write()
etc.?The major number and minor number tell the kernel how to access the device. A common major number is assigned to all devices that are being controlled by the same device driver. The minor number helps to distinguish between the exact device type/controller using the same device driver.
These numbers are the “major” and “minor” numbers for the particular device. The following listing shows a few devices as they appear on my system. Their major numbers are 10, 1, and 4, while the minors are 0, 3, 5, 64-65, and 128-129. The major number identifies the driver associated with the device.
All the hardware elements that a Unix system recognizes has a major & a minor number and basically, major number represents "A type of hardware" and minor number represents "an instance of that type of hardware". "All devices controlled by the same device driver have a common major device number.
There are two ways of a driver assigning major and minor number.
I think the story should starts from what happened when you type:
mknod /dev/c83 c 8 3
it will call ext2_mknod("/dev", "c83", CHAR, DEV(8, 3)), most file systems implement mknod as a wrapper of init_special_inode:
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode))
inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
mode);
}
when you finally call open("/dev/c83"), it will goes into function def_chr_fops.chrdev_open, which will replace the fops for file "/dev/c83" with the fops your registered in cdev_init():
int chrdev_open(struct inode * inode, struct file * filp)
{
struct cdev *p;
...
p = inode->i_cdev;
...
filp->f_op = fops_get(p->ops);
...
if (filp->f_op->open) {
lock_kernel();
ret = filp->f_op->open(inode,filp);
unlock_kernel();
}
...
return ret;
}
after that, every system call such as read/write/close goes directly to functions pointers registered in cdev_init()!
so, for your first question:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With