S3C2440 Input Subsystem Study Notes Section 1

Publisher:daits摸鱼的Latest update time:2023-08-10 Source: elecfansKeywords:S3C2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

  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)) 

[1] [2]
Keywords:S3C2440 Reference address:S3C2440 Input Subsystem Study Notes Section 1

Previous article:s3c2440 input subsystem learning section 2
Next article:U-Boot transplantation (4) adds support for S3C2440 (modifies compilation errors)

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号