I have been exposed to S3C2440 for a while, but I have never persisted in studying. As a recent graduate, I was deeply affected by my lack of skills and the pressure at work, so I decided to change my past and insist on studying every day after work. Here I don’t I dare to say that I can finish learning 2440, because technology never ends. But I believe I can keep going. I am a person who loves to think and realize what I think through various methods. I want to be the creator of my thoughts. Taking into account the different knowledge capacity of each chapter, the blog will be updated from time to time starting today. In the early stage, it will be updated according to the video tutorial directory of Teacher Wei Dongshan. If there is anything poorly written, please give me some advice.
Okay, without further ado, let’s get to the point.
The starting point of this blog is Teacher Wei Dongshan’s second period learning video. In the first video, we learned about simple driver structures, such as LED drivers, button drivers, etc. However, these drivers are only suitable for our daily use and there is no way for others to call them. But if you want to write a universal driver, just To use the ready-made driver - input input subsystem.
First, let’s review the past and write a driver framework according to Boss Wei’s method:
1. Make sure the main device is good
2. Construct a file_operations structure. The structure contains commonly used interfaces, such as open, write, read, etc.
3. Next, register a character device driver (register_chrdev)
4. Entry function, exit function, and modification.
The same framework is generally used in the input subsystem. The difference is that in the input subsystem, these frameworks are written by kernel driver development. All we have to do is integrate our code into it.
The core of the input subsystem is input.c (directory: /linux/driver/input/input.c) Now we start to analyze the system framework:
There is no frame picture at the moment.
The core of the input subsystem is input.c. We start with the entry function and the code is as follows. We see that err in the entry function = register_chrdev(INPUT_MAJOR, "input", &input_fops); This is to register a device named input, and the device number is INPUT_MAJOR, input_fops are function calling interfaces.
static int __init input_init(void)
{
int err;
err = class_register(&input_class);
if (err) {
printk(KERN_ERR "input: unable to register input_dev classn");
return err;
}
err = input_proc_init();
if (err)
goto fail1;
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
goto fail2;
}
return 0;
fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}
Next, let's take a look at what calling interfaces input_fops provides?
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,//This only provides an open interface. Such an interface function only has one interface. I guess there should be an implicit interface in input_open_file.
};
Take another look at the input_open_file function.
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5]; //Get an input_handler based on the minor device number of the open file
const struct file_operations *old_fops, *new_fops = NULL;
int err;
/* No load-on-demand here? */
if (!handler || !(new_fops = fops_get(handler->fops))) //New fileoperlations structure = handler->fops
return -ENODEV;
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
return -ENODEV;
}
old_fops = file->f_op;
file->f_op = new_fops; //Assign the f_ops of the new file to the f_op of the file????? I don’t understand. . .
err = new_fops->open(inode, file); //Finally call the open function of the file; the final application read function calls the file->f_op->read function.
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
input_table is an array defined by input_handler.
static struct input_handler *input_table[8]
Register what input_handler does
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
INIT_LIST_HEAD(&handler->h_list);
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5])
return -EBUSY;
input_table[handler->minor >> 5] = handler; //Put handler into the array
}
list_add_tail(&handler->node, &input_handler_list); // Put it in the linked list
list_for_each_entry(dev, &input_dev_list, node) //For each device_input, put it into the connection table
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
return 0;
Next, let’s take a look at what registration input_register_devide does.
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
. . . .
. . . . .
ist_add_tail(&dev->node, &input_dev_list); // Put it in the linked list
. . . . . .
list_for_each_entry(handler, &input_handler_list, node) //Call input_attach_handler for each item in the handler list
input_attach_handler(dev, handler); //Determine whether input_dev is supported based on the id_table of input_handler
As can be seen from input_register_device and input_register_handler, whether we register device or handler first, input_attach_handler will eventually be called. Continue to analyze input_attach_handler.
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev))
return -ENODEV;
id = input_match_device(handler->id_table, dev); //Compare handler->id_table with the input device to see if the handler supports it and whether it matches
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); //If it matches, call the connect function in handler
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %dn",
handler->name, kobject_name(&dev->cdev.kobj), error);
return error;
Summary: When registering input_dev or input_handler, the left and right input_handlers will be compared in pairs, and the input_handler's id_table will be used to determine whether the input_handler can support input_drv. If it does, the input_handler's connect function will be called for linking.
Let’s take a look at how to create a link.
Taking evdev_connect as an example, first enter evdev.c to find the evdev_handler structure. The code is as follows:
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect, //This is the link function of evdev, enter the evdev_connect function static int evdev_connect
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
.....
.....
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //Assign an input_handle
//set up
evdev->handle.dev = dev; //Point to input_dev on the left
evdev->handle.name = evdev->name;
evdev->handle.handler = handler; //Point to the input_handler on the right
evdev->handle.private = evdev;
//register
error = input_register_handle(&evdev->handle);
//Follow input_register_handle
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
list_add_tail(&handle->d_node, &handle->dev->h_list); //Establish a relationship between the device and input_handle->dev
list_add_tail(&handle->h_node, &handler->h_list); //Hook the system's handler_list and input_handle structures,
//In this way, the device and system can be linked together through the input_handle structure.
if (handler->start)
handler->start(handle);
return 0;
}
Summary: 1. Allocate an inout_hanfle structure
2. input_handle.dev = input_dev; //Point to input_dev on the right
input_handle.handler = input_handler; //Pointing to the input_handler on the right
3. Register
input_handler->h_list = &input_handle;
input_dev->h_list = &input)handle;
Data reading:
When the application reader reads data through the read function, it will call evdev_handler (just take evdev as an example)
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
int retval;
if (count < evdev_event_size())
return -EINVAL;
//If there is no data and it is opened in a non-blocking manner, return immediately
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
Previous article:s3c2440 input subsystem learning section 2
Next article:U-Boot transplantation (4) adds support for S3C2440 (modifies compilation errors)
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Innovation is not limited to Meizhi, Welling will appear at the 2024 China Home Appliance Technology Conference
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- How to design high frequency (>100K) ultrasonic sensor processing circuit
- A design scheme of smart water meter controlled by NFC
- Oscilloscope waveform jitter can be turned into stable waveform by setting trigger properly
- How to measure the noise floor of an oscilloscope
- Xintang M2354 Fault Injection Attack Protection
- Date in spring - go to the beach and relax
- Sub-library: BlueCoin Development Platform
- [Atria AT32WB415 Review] 4. Implementation of printf under AT32 IDE (printf redirection)
- Power amplifier driving capacitive load case sharing
- Sapphire on PCB---DFM about optical positioning points