linux学习(6)---输入子系统

主要内容---输入子系统编程--主要针对输入设备
1,输入系统的作用和框架
2,输入子系统的编程
3,输入子系统和平台总线的结合
4,输入子系统的执行流程
---------------------------------

1,输入系统的作用和框架
    针对输入设备: button, keyboard, mouse, ts, gsensor, joystick
    按照产生数据的类型进行分类:
        1,按键数据---键值
            button, keyboard
        2, 绝对坐标数据---有最大值和最小值
            ts, gsensor,陀螺仪
        3, 相对坐标数据---下一个坐标是相对于之前的坐标
            mouse
    
    引入输入子系统对输入设备进行驱动管理:
        1, 为驱动定义一个标准的编程方式
        2, 用户空间到数据格式是统一的
        
        
    框架:
        
        应用层
        ------------------------------------
        input handler 数据处理层: drivers/input/evdev.c
            1, 和用户进行交互,实现fops
            2, 不知道数据是如何得到,但是知道如何将数据交给用户
        
        
        -------------------------------------
        input core层--drivers/input/input.c
            1,维护了两个链表
            2, 为上下两层提供接口
        
        
        ---------------------------------------
        input device层: 输入设备硬件层--自己去写
            自带的input device代码:
                drivers/input/touchscreen/
                
            1, 初始化硬件,获取硬件中数据
            2, 知道得到数据,但是不知道如何将数据给用
            
        -------------------------------------------
        
        
        确保zImage已经包含了input core和input handler层代码
        make menuconfig
            Device Drivers  --->
                Input device support  --->
                    -*- Generic input layer (needed for keyboard, mouse, ...)// input.c
                    <*>   Event interface //  input handler层代码 evdev.c
        
        
2,输入子系统的编程:Documentation/input/input-programming.txt
    a, 分配一个input device对象
    b, 初始化input device对象
    c, 注册input device对象
    d, 硬件初始化
        
        
        struct input_dev *input_allocate_device(void)
        void input_free_device(struct input_dev *dev)
        
        int input_register_device(struct input_dev *dev)
        void input_unregister_device(struct input_dev *dev)
        
        //上报数据
            void input_report_key(struct input_dev *dev, unsigned int code, int value)
                    |
                    void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
        
        
        struct input_dev {
            const char *name;
            const char *phys;
            const char *uniq;
            struct input_id id;


            //位表
            // evbit表示能够产生哪些数据类型
            unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
            // keybit表示能够产生哪些按键数据
            unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//keybit[BITS_TO_LONGS(768)]=keybit[24]
            // relbit表示能够产生哪些相对坐标数据
            unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
            // absbit 表示能够产生哪些绝对坐标数据
            unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//absbit[2];
            unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
            unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
            unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
            unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
            unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
        
            struct device dev; //父类

            struct list_head    h_list;
            struct list_head    node;//链表的结点
        };
    
    
        struct input_event { //用户读取到输入设备的数据包
            struct timeval time;//时间戳
            __u16 type;//读取到数据类型: EV_KEY, EV_ABS, EV_REL
            __u16 code;//码值
            __s32 value;//状态
        };

    
================================================================================
看源码:

    1,看整个分层
    2,应用和驱动是如何交互
        open, read()
    
----------------------------------------------
1,分层


    input handler
        evdev.c
            module_init(evdev_init);
            module_exit(evdev_exit);
    
            static struct input_handler evdev_handler = {
                    .event          = evdev_event,
                    .connect        = evdev_connect,
                    .disconnect     = evdev_disconnect,
                    .fops           = &evdev_fops,
                    .minor          = EVDEV_MINOR_BASE, //64
                    .name           = "evdev",
                    .id_table       = evdev_ids,//由于比较的
            };

    
            
             input_register_handler(&evdev_handler);
                    |
                    INIT_LIST_HEAD(&handler->h_list);//记录儿子的
                    //将当前的evdev_handler放入到input_table[2]
                    input_table[handler->minor >> 5] = handler;
                    
                    list_add_tail(&handler->node, &input_handler_list);
                    list_for_each_entry(dev, &input_dev_list, node)
                            input_attach_handler(dev, handler);
                                |
                                id = input_match_device(handler, dev);//匹配
                                handler->connect(handler, dev, id); //匹配成功,调用了handler中connect方法
                            
        调用的connect方法:
            .connect        = evdev_connect,
                |
                //在数组中找出一个没有被占用的位置
                for (minor = 0; minor < EVDEV_MINORS; minor++)
                    if (!evdev_table[minor])
                        break;
                        
                //分配了一个evdev对象
                evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
                
                //初始化evdev对象
                INIT_LIST_HEAD(&evdev->client_list);
                spin_lock_init(&evdev->client_lock);
                mutex_init(&evdev->mutex);
                //初始化等待队列头
                init_waitqueue_head(&evdev->wait);

                
                evdev->exist = true;
                evdev->minor = minor;

                //利用handle记录了inputdev 和input handler
                evdev->handle.dev = input_get_device(dev);
                evdev->handle.name = dev_name(&evdev->dev);
                evdev->handle.handler = handler;
                //相互留个联系方式
                evdev->handle.private = evdev;
                
                //创建设备节点--device_create()
                //设置名字---event0, event1,
                dev_set_name(&evdev->dev, "event%d", minor);
                evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
                evdev->dev.class = &input_class;
                evdev->dev.parent = &dev->dev;
                evdev->dev.release = evdev_free;
                device_initialize(&evdev->dev);
                error = device_add(&evdev->dev);
                
                //inputdev, input handler, input handle建立双向关系
                error = input_register_handle(&evdev->handle);
                        |
                        struct input_handler *handler = handle->handler;
                        struct input_dev *dev = handle->dev;
                        
                        list_add_tail_rcu(&handle->d_node, &dev->h_list);
                        list_add_tail_rcu(&handle->h_node, &handler->h_list);
                
                //将当前的evdev放入到evdev_table[minor]
                error = evdev_install_chrdev(evdev);
                            |
                            evdev_table[evdev->minor] = evdev;
                
                
               
    创建设备节点:
        //创建设备节点--device_create()
        dev_set_name(&evdev->dev, "event%d", minor);
        evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
        evdev->dev.class = &input_class;
        evdev->dev.parent = &dev->dev;
        evdev->dev.release = evdev_free;
        device_initialize(&evdev->dev);
        device_add(&evdev->dev);

        
    device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
        |
        dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
            |
            struct device *dev = NULL;
            dev = kzalloc(sizeof(*dev), GFP_KERNEL);
            dev->devt = devt;
            dev->class = class;
            dev->parent = parent;
            dev->release = device_create_release;
            device_register(dev);
                |
                device_initialize(dev);
                return device_add(dev);
            
    ---------------------------------------
    input core
        input.c
        
    subsys_initcall(input_init);
    module_exit(input_exit);

        static LIST_HEAD(input_dev_list);
        static LIST_HEAD(input_handler_list);
    
            
             err = class_register(&input_class);
             err = input_proc_init();
             register_chrdev(INPUT_MAJOR, "input", &input_fops);//申请设备号
            
            
    -----------------------------------
    input device

            input_register_device(inputdev);
                |
                list_add_tail(&dev->node, &input_dev_list);

                list_for_each_entry(handler, &input_handler_list, node)
                    input_attach_handler(dev, handler);
                        |
                        id = input_match_device(handler, dev);//匹配
                        handler->connect(handler, dev, id); //调用了handler中connect方法

    2,应用和驱动是如何交互
        fd = open("/dev/event0")
        
        struct input_event event;
        read(fd, &event, sizeof(struct input_event)))
        
        
    ----------------------------------------------------------------------
    VFS:
        sys_open
            根据设备号找cdev
    --------------------------------
    驱动层的open:
    input.c
        register_chrdev(INPUT_MAJOR, "input", &input_fops);
            static const struct file_operations input_fops = {
                .owner = THIS_MODULE,
                .open = input_open_file,
                .llseek = noop_llseek,
            };
        
        input_open_file()
            |
            handler = input_table[iminor(inode) >> 5];
            if (handler)
                new_fops = fops_get(handler->fops);
                
            //将evdev_handler中fop给了file的f_op
            file->f_op = new_fops;
            //调用了evdev_handler中fop中open()
            err = new_fops->open(inode, file);//调到evedev.c层,调用了evdev_open
                
        -------------------------------------------------------------------
            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,
            #ifdef CONFIG_COMPAT
                .compat_ioctl    = evdev_ioctl_compat,
            #endif
                .fasync        = evdev_fasync,
                .flush        = evdev_flush,
                .llseek        = no_llseek,
            };
            
            evdev_open
                |
                struct evdev *evdev;
                struct evdev_client *client;
                //获取到次设备号,并且减去64
                int i = iminor(inode) - EVDEV_MINOR_BASE;
                //从全局数组中获取到evdev
                evdev = evdev_table[i];
                
                //分配evdev_client对象,并且为缓冲队列分配空间
                bufsize = evdev_compute_buffer_size(evdev->handle.dev);

                client = kzalloc(sizeof(struct evdev_client) +
                            bufsize * sizeof(struct input_event),
                         GFP_KERNEL);
                
                client->bufsize = bufsize;
                client->evdev = evdev;
                //将evdev_client关联到evdev中去
                evdev_attach_client(evdev, client);
                    |
                    list_add_tail_rcu(&client->node, &evdev->client_list);
        
                file->private_data = client;
        
        
        
        
        
        
        struct input_event event;
        read(fd, &event, sizeof(struct input_event)))
        ---------------------------------------------------------
        sys_read
            |
            filp->f_fop->read()
        ----------------------------------------------------------
        evdev.c
            .read            = evdev_read,
                |
                //阻塞
                retval = wait_event_interruptible(evdev->wait,
                    client->packet_head != client->tail || !evdev->exist);
                //如果阻塞被唤醒,会从evdev_client中获取数据event
                while (retval + input_event_size() <= count &&
                   evdev_fetch_next_event(client, &event)) {
                            |
                            *event = client->buffer[client->tail++];
                //拷贝给用户
                if (input_event_to_user(buffer + retval, &event))
                        
        
        
        谁唤醒?
        input devce层:
        btn_input->evbit[0] |= BIT_MASK(EV_KEY);
        btn_input->keybit[BIT_WORD(KEY_DOWN)] |= BIT_MASK(KEY_DOWN);
            input_sync()
                |
                input_event(dev, EV_SYN, SYN_REPORT, 0);
            input_event(btn_input, EV_KEY, KEY_DOWN,  0);
                |
                void input_event(struct input_dev *dev,
                        unsigned int type, unsigned int code, int value)
                        |
                        if (is_event_supported(type, dev->evbit, EV_MAX)) {
                            input_handle_event(dev, type, code, value);
                                |
                                switch (type) {
                                    case EV_KEY:
                                        if (is_event_supported(code, dev->keybit, KEY_MAX){
                                            disposition = INPUT_PASS_TO_HANDLERS;
                                        }
                                }
                        }
                        if (disposition & INPUT_PASS_TO_HANDLERS)
                                input_pass_event(dev, type, code, value);
                                    |
                                    struct input_handler *handler;
                                    struct input_handle *handle;
                                    //通过input dev找到input handle
                                    list_for_each_entry_rcu(handle, &dev->h_list, d_node)
                                    //通过input  handle找到input handler
                                    handler = handle->handler;
                                    //调用了 input handler中的event(), 调转到evdevc.
                                    handler->event(handle, type, code, value);
                        -----------------------------------
                        evdev.c
                            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,
                            };
                            evdev_event(handle, type, code, value)
                                |
                                struct evdev *evdev = handle->private;
                                struct evdev_client *client;
                                struct input_event event;
                                
                                //通过传递过来的参数初始化input_event对象
                                do_gettimeofday(&event.time);
                                event.type = type;
                                event.code = code;
                                event.value = value;
                                //通过evdev获取到evdev_client
                                list_for_each_entry_rcu(client, &evdev->client_list, node)
                                    evdev_pass_event(client, &event);
                                        |
                                        client->buffer[client->head++] = *event;
                                if (type == EV_SYN && code == SYN_REPORT)
                                        wake_up_interruptible(&evdev->wait);//如果调用input_sync那么表示唤醒等待队列
            input_sync(btn_input);

input子系统示例:

simple_input_app.c:

/******************simple_input_app.c*********************/


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/input.h>




int main(int argc, char *argv[])
{
	int ret;
	struct input_event event;

	int fd = open("/dev/event0", O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}


	while(1)
	{
		ret = read(fd, &event, sizeof(struct input_event));
		if(ret < 0)
		{
			perror("read");
			exit(1);
		}

		if(event.type == EV_KEY)
		{
			if(event.code == KEY_DOWN)
			{
				if(event.value)
				{
					printf("<APP>-------KEY_DOWN pressed\n");
				}else{
					printf("<APP>-------KEY_DOWN up\n");
				}
				
			}

		}
	
		
		

	}



	return 0;
}

simple_input_btn.c:

/******************simple_input_btn.c*********************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>


struct input_dev *btn_input;
static int irqno ;

irqreturn_t button_interrupt(int irq, void *dev_id)
{
		printk("--------%s-----------\n", __FUNCTION__);

		// 获取数据
		int value = gpio_get_value(S5PV210_GPH0(1));

		if(value)
		{
			//抬起
			//将数据上报给用户
			//参数1---哪个设备上报的
			//参数2---上报那种数据类型
			//参数3---上报码值
			//参数4--按键的状态/值
			//input_report_key(btn_input, KEY_DOWN, 0);
			input_event(btn_input, EV_KEY, KEY_DOWN,  0);
			//最后要有一个结束/同步
			input_sync(btn_input);
		
		}else{
			//按下
			input_event(btn_input, EV_KEY, KEY_DOWN,  1);
			input_sync(btn_input);

		}
		
       
        return IRQ_HANDLED;
}

static int __init simple_btn_input_init(void)
{
		int ret;

		/*
			a, 分配一个input device对象
			b, 初始化input device对象
			c, 注册input device对象
			d, 硬件初始化				
		*/

		//a, 分配一个input device对象
		btn_input = input_allocate_device();
		if(btn_input == NULL)
		{
			printk("input_allocate_device error\n");
			return -ENOMEM;
		}

		//b, 初始化input device对象
		//该设备能够产生哪种数据类型---EV_KEY表示产生按键数据
		btn_input->evbit[0] |= BIT_MASK(EV_KEY);
		//能够产生哪个按键---比如能够产生下键 KEY_DOWN, KEY_ESC
		// btn_input->keybit[108/32] |= 1<<(108%32);
		btn_input->keybit[BIT_WORD(KEY_DOWN)] |= BIT_MASK(KEY_DOWN);

	   //c, 注册input device对象
	   ret = input_register_device(btn_input);
	   if(ret != 0)
	   {
	   		printk("input_register_device error\n");
			
			goto err_free_input;
	   }

#if 1
		//d, 硬件初始化--申请中断
		irqno = IRQ_EINT(1);
		ret = request_irq(irqno, button_interrupt, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
						"key_input_eint1", NULL);
		if(ret != 0)
		{
			printk("request_irq error\n");
			
			goto err_unregister;
		}

#endif

		return 0;


err_unregister:
	input_unregister_device(btn_input);
err_free_input:
	input_free_device(btn_input);
	return ret;
}



static void __exit simple_btn_input_exit(void)
{
	  // free_irq(irqno, NULL);
	   input_unregister_device(btn_input);
       input_free_device(btn_input);
}

module_init(simple_btn_input_init);
module_exit(simple_btn_input_exit);
MODULE_LICENSE("GPL");

猜你喜欢

转载自blog.csdn.net/linken_yue/article/details/82320657
今日推荐