Input sub system

12 篇文章 1 订阅
drivers/input/input.c:
	input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
	
static const struct file_operations input_fops = {
	.owner = THIS_MODULE,
	.open = input_open_file,
};

怎么读按键?

input_open_file
	struct input_handler *handler = input_table[iminor(inode) >> 5];
	new_fops = fops_get(handler->fops)  //  =>&evdev_fops
	file->f_op = new_fops;
	err = new_fops->open(inode, file);

app: read > ... > file->f_op->read  

input_table数组由谁构造?

input_register_handler

注册input_handler:

input_register_handler
	// 放入数组
	input_table[handler->minor >> 5] = handler;
	
	// 放入链表
	list_add_tail(&handler->node, &input_handler_list);

	// 对于每个input_dev,调用input_attach_handler
	list_for_each_entry(dev, &input_dev_list, node)
		input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev

注册输入设备:

input_register_device
	// 放入链表
	list_add_tail(&dev->node, &input_dev_list);
	
	// 对于每一个input_handler,都调用input_attach_handler
	list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev


input_attach_handler
	id = input_match_device(handler->id_table, dev);
	
	error = handler->connect(handler, dev, id);

注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
如果能支持,则调用input_handler的connect函数建立"连接"

怎么建立连接?

  1. 分配一个input_handle结构体
  2. input_handle.dev = input_dev; // 指向左边的input_dev
    input_handle.handler = input_handler; // 指向右边的input_handler
  3. 注册:
    input_handler->h_list = &input_handle;
    inpu_dev->h_list = &input_handle;
evdev_connect
	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); // 分配一个input_handle
	
	// 设置
	evdev->handle.dev = dev;  // 指向左边的input_dev
	evdev->handle.name = evdev->name;
	evdev->handle.handler = handler;  // 指向右边的input_handler
	evdev->handle.private = evdev;
	
	// 注册
	error = input_register_handle(&evdev->handle);

怎么读按键?
app: read

   		evdev_read
   			// 无数据并且是非阻塞方式打开,则立刻返回
			if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
				return -EAGAIN;
			
			// 否则休眠
			retval = wait_event_interruptible(evdev->wait,
				client->head != client->tail || !evdev->exist);
   			

谁来唤醒?

evdev_event
	wake_up_interruptible(&evdev->wait);

evdev_event被谁调用?
猜:应该是硬件相关的代码,input_dev那层调用的
在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数

gpio_keys_isr
	// 上报事件
	input_event(input, type, button->code, !!state);
	input_sync(input);
	
input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
	struct input_handle *handle;

	list_for_each_entry(handle, &dev->h_list, d_node)
		if (handle->open)
			handle->handler->event(handle, type, code, value);

怎么写符合输入子系统框架的驱动程序?

  1. 分配一个input_dev结构体
  2. 设置
  3. 注册
  4. 硬件相关的代码,比如在中断服务程序里上报事件

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)]; // 表示能产生哪些相对位移事件, x,y,滚轮
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
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)];

测试:
1.
hexdump /dev/event1 (open(/dev/event1), read(), )
秒 微秒 类 code value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

  1. 如果没有启动QT:
    cat /dev/tty1
    按:s2,s3,s4
    就可以得到ls

或者:
exec 0</dev/tty1
然后可以使用按键来输入

  1. 如果已经启动了QT:
    可以点开记事本
    然后按:s2,s3,s4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值