Linux Kernel Lecture Hall (2) legendary character devices (1)
When I was still at school, I once heard an installer say in an assembly group that the installation of the driver is not as simple as you think, it can be divided into character device drivers and block device drivers. I was wondering at the time. I said I didn't seem to have seen it when I installed it. I just put the CD in the past and kept clicking Next. Then I restarted it. Later, I was besieged by several experts in the Group and defeated. As time passes, my brother is now a brother of the road, and it is no longer so easy to be blinded. Even if you are a good DIY player, you should not tell me that drivers should be classified. Otherwise, I will talk to you about the kernel. Let's see who else can play. Haha. I smiled proudly. I found that one of the advantages of kernel learning is that it is very good to install B. You just need to familiarize yourself with the terms in the kernel to scare and scare people out. It works well, but if you hit an expert, you should pay attention to it. Haha.
Well, learning the kernel is not intended to scare people, but to grasp its principles, learn its skills and methods, but to know what it means. In addition, the kernel code has a certain degree of complexity, after reading the kernel code, let's look at what we have written. It's no different from toys. This is the benefit of kernel learning!
If you read a series of articles about the driver model, you should feel like you have been tossing and tossing for a long time. What if you don't do anything else?
I was planning to implement a set of all the things I want to talk about. If I have read the entire series, I should have created a bus, driver, and device, file systems and a series of capabilities, but in this case, I am afraid that everyone will not be able to stand it. To tell the truth, both of them are also uncomfortable and it takes too much time and effort. It is a duplicate wheel. It is not as good as others. Therefore, we decided to return to the original source, instead of writing it on our own!
Character devices are a legend. Anyone who has ever played Linux knows this thing. Many comrades can write a character device as a cat or a tiger. But brother no, brother has a pursuit of people, know its own, must know its own. I will never turn people into the door irresponsibly. I will still explain everything I have to say. We don't need to refer to the concept first. What are character devices and Block devices. This is meaningless. What do you need to know most is what this character device has done? How did he work? After figuring out what a character device is, you will understand. If I want to learn more about Block devices, what is the difference between a one-to-one ratio? You will understand. I have never liked the concept of NLP. Some comrades ask you to call character devices. He answers you to the char device. You say Block devices, he says Block devices, and you say bottom half, he says bottom half. If you say NXP, he said xp. Fortunately, it's a mix of roads. You know a little about it. Otherwise, they will be pinned down. Well, I will not talk much about it. In general, I want to express a Learning Attitude: I don't need to worry about it.
Next, let's take a look at character devices.
The comrades who have read the articles in the driver model series should now have a kind of consciousness. For now, we call it "initialization consciousness ". That is to say, you used register_chrdev () for registration. But that's because our predecessors have paved the road. Well, let's take a look at what our predecessors have done, remind me again that you must have an "initialization consciousness ".
Under the guidance of "initialization consciousness", we found a file: char_dev.c. Open this file and check it. There is such an initialization function:
Void _ init chrdev_init (void)
{
Cdev_map = kobj_map_init (base_probe, & chrdevs_lock );
Bdi_init (& directly_mappable_cdev_bdi );
}
Base_probe is a simple function:
Static struct kobject * base_probe (dev_t Dev, int * part, void * Data)
{
If (request_module ("char-Major-% d", Major (Dev), minor (Dev)> 0)
/* Make old-style 2.4 aliases work */
Request_module ("char-Major-% d", Major (Dev ));
Return NULL;
}
The request_module function can be used to load a module.
Chrdevs_lock is a large lock. Nothing else. It's just these two things.
The key lies in:
Struct kobj_map * kobj_map_init (kobj_probe_t * base_probe, struct mutex * Lock)
{
Struct kobj_map * P = kmalloc (sizeof (struct kobj_map), gfp_kernel );
Struct probe * base = kzarloc (sizeof (* base), gfp_kernel );
Int I;
If (P = NULL) | (base = NULL )){
Kfree (P );
Kfree (base );
Return NULL;
}
Base-> Dev = 1;
Base-> range = ~ 0;
Base-> Get = base_probe;
For (I = 0; I <255; I ++)
P-> probes [I] = base;
P-> lock = lock;
Return P;
}
One of the most critical roles came to the market without knowing it, namely, struct kobj_map.
We can see that a piece of memory is allocated with kmalloc and assigned to struct kobj_map * P.
Struct kobj_map {
Struct probe {
Struct probe * next;
Dev_t dev;
Unsigned long range;
Struct module * owner;
Kobj_probe_t * Get;
INT (* Lock) (dev_t, void *);
Void * data;
} * Probes [255];
Struct mutex * lock;
};
A struct array with a length of 255 and a lock are embedded in it.
In the Linux kernel, If you directly allocate a relatively large amount of memory, there are basically hash ideas in it, mainly for efficiency. Members in this struct will know what to use.
Next
Struct probe * base = kzarloc (sizeof (* base), gfp_kernel );
Let's show off the kernel author. How good is writing struct probe * base = kzarloc (sizeof (struct probe), gfp_kernel? No matter what it is, I just take the essence of it.
Next:
If (P = NULL) | (base = NULL )){
Kfree (P );
Kfree (base );
Return NULL;
}
If you have any questions, you can carefully study the kfree function. This is correct. Let me talk about another idea. If you have any questions, read the source code and do not go through the book or Google Baidu. All functions in the Linux kernel are self-sufficient. You can solve all your questions by reading the kernel source code. Of course, if you don't mean not to read a book, I mean to try not to read it if you don't.
Next:
Base-> Dev = 1;
Base-> range = ~ 0; // reverse, much better than writing a bunch of 0xff..., and better portability
Base-> Get = base_probe; // point the function pointer to the callback function passed in.
Next:
For (I = 0; I <255; I ++)
P-> probes [I] = base;
Use base to initialize the entire kobj_map.probe [255].
P-> lock = lock;
Return P;
Finally, the lock is passed and the pointer is returned.
Next:
Bdi_init (& directly_mappable_cdev_bdi );
You don't need to worry about it. It doesn't help us understand character devices, and it can only be messy.
Okay. Let's get there today.
The next section may take a long time, but it is too busy recently. Please be considerate! Thank you. Smoke. Pai_^