《嵌入式设备驱动程序基础笔记》第16期

《嵌入式设备驱动程序基础笔记》第16期输入子系统讲解Linux内核为了能够处理各种不同类型的输入设备,比如 触摸屏 ,鼠标 , 键盘 , 操纵杆 ,设计并实现了为驱动层程序的实现提供

欢迎大家来到IT世界,在知识的湖畔探索吧!

输入子系统讲解

Linux内核为了能够处理各种不同类型的输入设备,比如 触摸屏 ,鼠标 , 键盘 , 操纵杆 ,设计并实现了为驱动层程序的实现提供统一接口函数;为上层应用提供试图统一的抽象层 , 即是Linux 输入子系统

《嵌入式设备驱动程序基础笔记》第16期

从上图输入子系统的框架图,可以看出,输入子系统由Input driver(驱动层)、Input core(输入子系统核心)、Event handler(事件处理层)三部分组成

  • Input driver :主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。
  • Input core :承上启下。为设备驱动层提供了规范和接口;通知事件处理层对事件进行处理;(内核已经帮我们做好,即input.c
  • Event handler :提供用户编程的接口(设备节点),并处理驱动层提交的数据处理。
  • input.c

    1,subsys_initcall(input_init);
    
    2,input_init
    
    3,class_register(&input_class);//注册名为input的类
    
    4,input_proc_init
    
    5,register_chrdev(INPUT_MAJOR, "input", &input_fops);
    /*static const struct file_operations input_fops = {
    	.owner = THIS_MODULE,
    	.open = input_open_file,
    };
    */
    
    6,static int input_open_file(struct inode *inode, struct file *file)
    
    7,struct input_handler *handler = input_table[iminor(inode) >> 5];
    
    8,new_fops = fops_get(handler->fops)
    
    9,file->f_op = new_fops;
    
    10,new_fops->open(inode, file);
    

    欢迎大家来到IT世界,在知识的湖畔探索吧!

    重要的结构体

    1,input_handler

    欢迎大家来到IT世界,在知识的湖畔探索吧!/**
     * struct input_handler - implements one of interfaces for input devices
     * @private: driver-specific data
     * @event: event handler
     * @connect: called when attaching a handler to an input device
     * @disconnect: disconnects a handler from input device
     * @start: starts handler for given handle. This function is called by
     *	input core right after connect() method and also when a process
     *	that "grabbed" a device releases it
     * @fops: file operations this driver implements
     * @minor: beginning of range of 32 minors for devices this driver
     *	can provide
     * @name: name of the handler, to be shown in /proc/bus/input/handlers
     * @id_table: pointer to a table of input_device_ids this driver can
     *	handle
     * @blacklist: prointer to a table of input_device_ids this driver should
     *	ignore even if they match @id_table
     * @h_list: list of input handles associated with the handler
     * @node: for placing the driver onto input_handler_list
     */
    struct input_handler {
    
    	void *private;
    
    	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
    	void (*disconnect)(struct input_handle *handle);
    	void (*start)(struct input_handle *handle);
    
    	const struct file_operations *fops;
    	int minor;
    	const char *name;
    
    	const struct input_device_id *id_table;
    	const struct input_device_id *blacklist;
    
    	struct list_head	h_list;
    	struct list_head	node;
    };

    * @connect: called when attaching a handler to an input device

    2,input_handle

    struct input_handle {
    
    	void *private;
    
    	int open;
    	const char *name;
    
    	struct input_dev *dev;
    	struct input_handler *handler;
    
    	struct list_head	d_node;
    	struct list_head	h_node;
    };

    2,input_dev

    欢迎大家来到IT世界,在知识的湖畔探索吧!
    struct input_dev {
    
    	void *private;
    
    	const char *name;
    	const char *phys;
    	const char *uniq;
    	struct input_id id;
    
    	unsigned long evbit[NBITS(EV_MAX)];
    	unsigned long keybit[NBITS(KEY_MAX)];
    	unsigned long relbit[NBITS(REL_MAX)];
    	unsigned long absbit[NBITS(ABS_MAX)];
    	unsigned long mscbit[NBITS(MSC_MAX)];
    	unsigned long ledbit[NBITS(LED_MAX)];
    	unsigned long sndbit[NBITS(SND_MAX)];
    	unsigned long ffbit[NBITS(FF_MAX)];
    	unsigned long swbit[NBITS(SW_MAX)];
    
    	unsigned int keycodemax;
    	unsigned int keycodesize;
    	void *keycode;
    	int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
    	int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
    
    	struct ff_device *ff;
    
    	unsigned int repeat_key;
    	struct timer_list timer;
    
    	int state;
    
    	int sync;
    
    	int abs[ABS_MAX + 1];
    	int rep[REP_MAX + 1];
    
    	unsigned long key[NBITS(KEY_MAX)];
    	unsigned long led[NBITS(LED_MAX)];
    	unsigned long snd[NBITS(SND_MAX)];
    	unsigned long sw[NBITS(SW_MAX)];
    
    	int absmax[ABS_MAX + 1];
    	int absmin[ABS_MAX + 1];
    	int absfuzz[ABS_MAX + 1];
    	int absflat[ABS_MAX + 1];
    
    	int (*open)(struct input_dev *dev);
    	void (*close)(struct input_dev *dev);
    	int (*flush)(struct input_dev *dev, struct file *file);
    	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
    
    	struct input_handle *grab;
    
    	struct mutex mutex;	/* serializes open and close operations */
    	unsigned int users;
    
    	struct class_device cdev;
    	union {			/* temporarily so while we switching to struct device */
    		struct device *parent;
    	} dev;
    
    	struct list_head	h_list;
    	struct list_head	node;
    }

    几个重要的函数:

    1,int input_register_handler(struct input_handler *handler) //input.c

    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;
    	}
    
    	list_add_tail(&handler->node, &input_handler_list);//(1)
    
    	list_for_each_entry(dev, &input_dev_list, node)
    		input_attach_handler(dev, handler);
    
    	input_wakeup_procfs_readers();
    	return 0;
    }

    在上述函数里有个重要的函数:input_attach_handler(dev, handler);

    备注:list_add_tail(&handler->node, &input_handler_list);//(1)

    2,int input_register_handle(struct input_handle *handle) //input.c

    int input_register_handle(struct input_handle *handle)
    {
    	struct input_handler *handler = handle->handler;
    
    	list_add_tail(&handle->d_node, &handle->dev->h_list);
    	list_add_tail(&handle->h_node, &handler->h_list);
    
    	if (handler->start)
    		handler->start(handle);
    
    	return 0;
    }

    备注:

    list_add_tail(&handle->d_node, &handle->dev->h_list);//(2)

    list_add_tail(&handle->h_node, &handler->h_list); //(3)

    通过(1)(2)(3)即可将设备与驱动连接在一起,看似复杂,总结一句话:

    当注册设备时,系统遍历相应的列表查看是否有合适的驱动;当注册驱动时,系统遍历列表查看是否有合适的设备。

    编写一个按键驱动程序:

    实现功能:四个按键分别对应键盘上的:L,S,ENTER,LEFTSHIFT

    /*
    1,allocate input_dev structural morphology
    2,configure
    3,register
    4,operate hardware relative 
    */
    #include <linux/module.h>
    #include <linux/version.h>
    
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/sched.h>
    #include <linux/pm.h>
    #include <linux/sysctl.h>
    #include <linux/proc_fs.h>
    #include <linux/delay.h>
    #include <linux/platform_device.h>
    #include <linux/input.h>
    #include <linux/irq.h>
    
    #include <asm/gpio.h>
    #include <asm/io.h>
    #include <asm/arch/regs-gpio.h>
    
    #define TEN_MS  jiffies+HZ/100
    
    static struct input_dev *input_button_dev;
    static struct pin_desc     *irq_pd;
    static struct timer_list    input_button_timer;
    
    struct pin_desc{
    	int irq;
    	char *name;
    	unsigned int pin;
    	unsigned int key_val;
    };
    
    struct pin_desc pin_descs[4]={
    	{IRQ_EINT0,   "BUTTON1",S3C2410_GPF0,    KEY_L},
    	{IRQ_EINT2,   "BUTTON2",S3C2410_GPF2,    KEY_S},
    	{IRQ_EINT11, "BUTTON3",S3C2410_GPG3,   KEY_ENTER},
    	{IRQ_EINT19, "BUTTON4",S3C2410_GPG11, KEY_LEFTSHIFT},
    };
    
    //按键中断处理函数
    static irqreturn_t input_button_irq(int irq, void *dev_id)
    {
    	irq_pd = (struct pin_desc  *)	dev_id;
    	mod_timer(&input_button_timer,TEN_MS);
    	return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    #define Button_Release 0
    #define Button_Press     1
    
    static void input_button_timer_irq(unsigned long data)
    {
    	struct pin_desc *pindesc = irq_pd;
    	unsigned int pinval;
    
    	if(!pindesc)
    		return ;
    	pinval = s3c2410_gpio_getpin(pindesc->pin);
    	if(pinval)
    	{
    		input_event(input_button_dev,EV_KEY,pindesc->key_val,Button_Release);
    		input_sync(input_button_dev);
    	}
    	else
    	{
    		input_event(input_button_dev,EV_KEY,pindesc->key_val,Button_Press);
    		input_sync(input_button_dev);
    	}
    }
    
    
    //入口与出口函数
    static int input_button_init(void)
    {
    	int count = 0;
    	
    	input_button_dev = input_allocate_device();
    
    	set_bit(EV_KEY,input_button_dev->evbit);//产生按键类事件
      set_bit(EV_REP,input_button_dev->evbit);
    	//产生这一类事件中具体哪个事件
    	set_bit(KEY_L,input_button_dev->keybit);
    	set_bit(KEY_S,input_button_dev->keybit);
    	set_bit(KEY_ENTER,input_button_dev->keybit);
    	set_bit(KEY_LEFTSHIFT,input_button_dev->keybit);
    
    	input_register_device(input_button_dev);
    
    	init_timer(&input_button_timer);
    	input_button_timer.function=&input_button_timer_irq;
    	add_timer(&input_button_timer);
    	
    	for(count =0 ; count < 4; count ++)
    	{
    		//注册中断
    		request_irq(pin_descs[count].irq,input_button_irq,IRQT_BOTHEDGE,pin_descs[count].name,&pin_descs[count]);
    	}
    	return 0;
    }
    
    static void input_button_exit(void)
    {
    	int count = 0;
    	input_unregister_device(input_button_dev);
    	for(count = 0 ; count < 4; count ++)
    	{
    		//注册中断
    		free_irq(pin_descs[count].irq,&pin_descs[count]);
    	}
    	del_timer(&input_button_timer);
    	input_free_device(input_button_dev);
    }
    
    module_init(input_button_init);
    module_exit(input_button_exit);
    MODULE_LICENSE("GPL");

    Makefile

    KERN_DIR = /work/system/linux-2.6.22.6
    all:
    	make -C $(KERN_DIR) M=`pwd` modules
    	rm -rf modules.order Module.symvers 
    .PHONY:
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order Module.symvers
    obj-m   += input_button.o

    编译:

    make

    测试:

    1,加载好编译生成的模块后,终端输入:

    cat /dev/tty1

    然后按下四个按键查看现象

    2,在终端输入:

    exec 0</dev/tty1

    然后按下四个按键查看现象,即可看到:当我们输入ls时按下enter键出现相应的内容(即相当于我们键盘上输入命令ls)

    备注:

    1,hexdump:以某种格式查看文件(具体用法:Linux中输入man hexdump查看)

    2,exec:exec()函数家族将当前进程映像替换为一个新的进程映像(具体用法:Linux中输入man exec查看)

    免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/35084.html

    (0)

    相关推荐

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注

    联系我们YX

    mu99908888

    在线咨询: 微信交谈

    邮件:itzsgw@126.com

    工作时间:时刻准备着!

    关注微信