• Linux input子系统学习总结(三)----Input设备驱动


    Input 设备驱动 ---操作硬件获取硬件寄存器中设备输入的数据,并把数据交给核心层;

    一 、设备驱动的注册步骤:

    1、分配一个struct  input_dev :

             struct      input_dev  *input_dev

    2、 初始化 input_dev 这个结构体 :

    3、 注册这个input_dev 设备:

    Input_register_device(dev);

    4、 在input设备发生输入操作时,提交所发生的事件及键值、坐标等信息:

    Input_report_abs()///报告X,y的坐标值

    Input_report_key()///报告触摸屏的状态,是否被按下

    Input_sync () ///表示提交一个完整的报告,这样linux内核就知道哪几个数据组合起来代表一个事件

    二、Linux 中输入事件的类型:

    EV_SYN  0X00  同步事件

    EV_KEY  0X01  按键事件

    EV_REL  0X02  相对坐标

    EV_ABS  0X03  绝对坐标

    ....

    三、关键程序片段(以USB鼠标为例:drivershidusbhidusbmouse.c

    1、 module_usb_driver(usb_mouse_driver);///系统启动时注册usb_mouse_driver (在usb架构中实现)

    2、 usb_mouse_probe (设备初始化,usbmouse 属于usb设备,匹配成功后注册input设备)

    3、 input_register_device(mouse->dev); 注册设备驱动

    4、 input_attach_handler(dev, handler);///遍历所有的input_handler,并与 dev 进行匹配

    usbmouse除了可以和evdev_handler 匹配成功,还和mousedev_handler 匹配成功,所以会分别调用evdev_handler的connect 函数创建event 节点和 mousedev_handler 的connect创建mouse节点

    5、 input_match_device(handler, dev);///---->handler 和 device 进行真正的匹配(通过id_table 进行匹配)

    6、 handler->connect(handler, dev, id);///匹配成功调用handler的connect 函数

    7、 evdev_connect()///将创建 event(0、1、2…)节点

    8、 mousedev_connect()///将创建 mouse(0、1、2…)节点

    9、 mousedev_create()

    10、cdev_init(&mousedev->cdev, &mousedev_fops);

    11、usb_mouse_irq()///最终的数据在中断里面获取到,并保存到mouse –>data 里面

    12input_report_key input_report_rel input_sync ///报告按键信息

    13、input_event

    14、input_handle_event(dev, type, code, value)

    15、input_pass_values(dev, dev->vals, dev->num_vals);

    16 、input_to_handler(handle, vals, count);

    17、handler->event(handle, v->type, v->code, v->value);

                           

    1 static struct usb_driver usb_mouse_driver = {
    2     .name        = "usbmouse",
    3     .probe        = usb_mouse_probe,///当有新的usbmouse加入时,系统会进行匹配,匹配成功后则调用probe函数,完成设备的初始化
    4     .disconnect    = usb_mouse_disconnect,
    5     .id_table    = usb_mouse_id_table,
    6 };
    7 
    8 module_usb_driver(usb_mouse_driver);///系统启动时注册usb_mouse_driver
     1 static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
     2 {
     3     struct usb_device *dev = interface_to_usbdev(intf);
     4     struct usb_host_interface *interface;
     5     struct usb_endpoint_descriptor *endpoint;
     6     struct usb_mouse *mouse;
     7     struct input_dev *input_dev;
     8     int pipe, maxp;
     9     int error = -ENOMEM;
    10 
    11     interface = intf->cur_altsetting;
    12 
    13     if (interface->desc.bNumEndpoints != 1)
    14         return -ENODEV;
    15 
    16     endpoint = &interface->endpoint[0].desc;
    17     if (!usb_endpoint_is_int_in(endpoint))
    18         return -ENODEV;
    19 
    20     pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
    21     maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
    22 
    23     mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
    24     input_dev = input_allocate_device();
    25     if (!mouse || !input_dev)
    26         goto fail1;
    27 
    28     mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
    29     if (!mouse->data)
    30         goto fail1;
    31 
    32     mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
    33     if (!mouse->irq)
    34         goto fail2;
    35 
    36     mouse->usbdev = dev;
    37     mouse->dev = input_dev;
    38 
    39     if (dev->manufacturer)
    40         strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
    41 
    42     if (dev->product) {
    43         if (dev->manufacturer)
    44             strlcat(mouse->name, " ", sizeof(mouse->name));
    45         strlcat(mouse->name, dev->product, sizeof(mouse->name));
    46     }
    47 
    48     if (!strlen(mouse->name))
    49         snprintf(mouse->name, sizeof(mouse->name),
    50              "USB HIDBP Mouse %04x:%04x",
    51              le16_to_cpu(dev->descriptor.idVendor),
    52              le16_to_cpu(dev->descriptor.idProduct));
    53 
    54     usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
    55     strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
    56 
    57     input_dev->name = mouse->name;
    58     input_dev->phys = mouse->phys;
    59     usb_to_input_id(dev, &input_dev->id);
    60     input_dev->dev.parent = &intf->dev;
    61 
    62     ////evbit 关于设备支持事件类型的 bitmap 
    63     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); ///BIT_MASK 找到参数值所在的 bit位
    64     input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | ///鼠标支持左键、右键、中键三个按键
    65         BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
    66     input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); ///REL_X REL_Y 表示鼠标的位置信息
    67     input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | ///在已有按键的基础上加上一个边键和一个而外的键
    68         BIT_MASK(BTN_EXTRA);
    69     input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);///给相对事件加上滚轮的事件
    70 
    71     input_set_drvdata(input_dev, mouse);
    72 
    73     input_dev->open = usb_mouse_open;
    74     input_dev->close = usb_mouse_close;
    75 
    76     usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
    77              (maxp > 8 ? 8 : maxp),
    78              usb_mouse_irq, mouse, endpoint->bInterval);
    79     mouse->irq->transfer_dma = mouse->data_dma;
    80     mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    81 
    82     error = input_register_device(mouse->dev);
    83     if (error)
    84         goto fail3;
    85 
    86     usb_set_intfdata(intf, mouse);
    87     return 0;
    88 
    89 fail3:    
    90     usb_free_urb(mouse->irq);
    91 fail2:    
    92     usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
    93 fail1:    
    94     input_free_device(input_dev);
    95     kfree(mouse);
    96     return error;
    97 }
    View Code
     1 int input_register_device(struct input_dev *dev)
     2 {
     3     struct input_devres *devres = NULL;
     4     struct input_handler *handler;
     5     unsigned int packet_size;
     6     const char *path;
     7     int error;
     8 
     9     if (dev->devres_managed) {
    10         devres = devres_alloc(devm_input_device_unregister,
    11                       sizeof(struct input_devres), GFP_KERNEL);
    12         if (!devres)
    13             return -ENOMEM;
    14 
    15         devres->input = dev;
    16     }
    17 
    18     /* Every input device generates EV_SYN/SYN_REPORT events. */
    19     __set_bit(EV_SYN, dev->evbit);
    20 
    21     /* KEY_RESERVED is not supposed to be transmitted to userspace. */
    22     __clear_bit(KEY_RESERVED, dev->keybit);
    23 
    24     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
    25     input_cleanse_bitmasks(dev);
    26 
    27     packet_size = input_estimate_events_per_packet(dev);
    28     if (dev->hint_events_per_packet < packet_size)
    29         dev->hint_events_per_packet = packet_size;
    30 
    31     dev->max_vals = dev->hint_events_per_packet + 2;
    32     dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
    33     if (!dev->vals) {
    34         error = -ENOMEM;
    35         goto err_devres_free;
    36     }
    37 
    38     /*
    39      * If delay and period are pre-set by the driver, then autorepeating
    40      * is handled by the driver itself and we don't do it in input.c.
    41      */
    42     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
    43         dev->timer.data = (long) dev;
    44         dev->timer.function = input_repeat_key;
    45         dev->rep[REP_DELAY] = 250;
    46         dev->rep[REP_PERIOD] = 33;
    47     }
    48 
    49     if (!dev->getkeycode)
    50         dev->getkeycode = input_default_getkeycode;
    51 
    52     if (!dev->setkeycode)
    53         dev->setkeycode = input_default_setkeycode;
    54 
    55     error = device_add(&dev->dev);
    56     if (error)
    57         goto err_free_vals;
    58 
    59     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    60     pr_info("%s as %s
    ",
    61         dev->name ? dev->name : "Unspecified device",
    62         path ? path : "N/A");
    63     kfree(path);
    64 
    65     error = mutex_lock_interruptible(&input_mutex);
    66     if (error)
    67         goto err_device_del;
    68 
    69     list_add_tail(&dev->node, &input_dev_list);
    70 
    71     list_for_each_entry(handler, &input_handler_list, node)
    72         input_attach_handler(dev, handler);////遍历所有的input_handler,并与 dev 进行匹配
    73 
    74     input_wakeup_procfs_readers();
    75 
    76     mutex_unlock(&input_mutex);
    77 
    78     if (dev->devres_managed) {
    79         dev_dbg(dev->dev.parent, "%s: registering %s with devres.
    ",
    80             __func__, dev_name(&dev->dev));
    81         devres_add(dev->dev.parent, devres);
    82     }
    83     return 0;
    84 
    85 err_device_del:
    86     device_del(&dev->dev);
    87 err_free_vals:
    88     kfree(dev->vals);
    89     dev->vals = NULL;
    90 err_devres_free:
    91     devres_free(devres);
    92     return error;
    93 }
    View Code
     1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
     2 {
     3     const struct input_device_id *id;
     4     int error;
     5 
     6     id = input_match_device(handler, dev);////---->handler 和 device 进行真正的匹配
     7     if (!id)
     8         return -ENODEV;
     9 
    10     error = handler->connect(handler, dev, id);///如果返回id不为空就执行handler 的 connect  ---> 调用 evdev.c 的 connect 函数
    11     if (error && error != -ENODEV)
    12         pr_err("failed to attach handler %s to device %s, error: %d
    ",
    13                handler->name, kobject_name(&dev->dev.kobj), error);
    14 
    15     return error;
    16 }
    View Code

    查看设备在系统中对应的节点信息(包括设备名称ID对应的handler等),例如usb鼠标对应的节点信息如下:

    鼠标对应的事件驱动为mouse1 和event3,因为它和两个事件驱动匹配成功;

    Event 节点里面存放的数据都是没有经过处理的原始数据流,通过命令$cat  event3可以看到鼠标输入的数据,但是mouse 节点里面的数据是经过处理的有结构的数据,直接对应鼠标点击或滑动的具体坐标,应用程序可以直接读取使用,可以通过命令$cat  mouse1可以看到鼠标输入的数据

  • 相关阅读:
    springboot框架
    java是什么
    Java文件读写
    Spring Cloud学习入门路线方案
    Spring Cloud学习路线
    Lucene——索引过程分析Index
    Lucene学习入门——核心类API
    爬虫技术框架——Heritrix
    Spring Cloud入门程序——注册服务提供者
    Spring Cloud入门程序
  • 原文地址:https://www.cnblogs.com/EaIE099/p/5067684.html
Copyright © 2020-2023  润新知