欢迎大家来到IT世界,在知识的湖畔探索吧!
输入子系统讲解
Linux内核为了能够处理各种不同类型的输入设备,比如 触摸屏 ,鼠标 , 键盘 , 操纵杆 ,设计并实现了为驱动层程序的实现提供统一接口函数;为上层应用提供试图统一的抽象层 , 即是Linux 输入子系统 。
从上图输入子系统的框架图,可以看出,输入子系统由Input driver(驱动层)、Input core(输入子系统核心)、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