7.输入子系统框架

1.框架小结

1、入口input_init:注册类,注册驱动

  class_create(&input_class);
  register_chrdev(INPUT_MAJOR, "input", &input_fops);

2、打开驱动,将真正的file_operations引入执行open,该文件同时储存input_table

  struct input_handler *handle = imput_table[minor >> 5]            //8bit >> 5 = 3bit(8个索引)
                                                                      这里此设备号中的低5位用作特殊处理

3、input_register_handler,初始化input_table处理函数,添加实际的handler,加入全局链表input_handler_list,同时调用connect建立handlerdev连接
4、input_register_device注册具体的input_dev,加入到全局链表input_dev_list,同时调用connect建立handlerdev的连接
5、connect建立链接关系,这里有一个新的连接结构handler,包含了handlerinput_dev,这里具体的新建一个evdev结构变量,成员变量指向上面创建的devhandler,分配此设备好创建设备。调用input_register_handler,创建一个管理结构
6、app读取数据最终会调用到handlerfile中的read,阻塞方式如果进入休眠会被中断调用handlerevent来唤醒

2.有架构驱动与无架构驱动的对比

无架构驱动

  1.确定主设备号
  2.编写file_oprention结构体编写硬件相关操作
  3.构造class结构,自动创建dev设备节点
  4.注册设备驱动
  5.定义入口和出口

输入子系统架构

  input.c完成了主设备的注册,驱动设备注册,在这个框架下需要实现硬件设备驱动的程序即可。
  input_device设备驱动
  input_handler处理架构
  1.向内核申请input_dev结构体
  2.设置input_dev的成员
  3.注册input_dev驱动设备
  4.初始化定时器和中断
  5.写中断服务函数
  6.写定时器超时函数
  7.在出口函数中,释放中断函数,删除定时器,卸载驱动,释放驱动

3.关键函数、结构体解析

input_dev :设备结构

struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];              // 支持哪些事件
        /* EN_SYN:同步事件,当使用input_event()函数后就要使用这个上报同步事件
         * EN_KEY:键盘事件
         * EV_REL:相对坐标事件,eg:鼠标
         * EV_ABS:绝对坐标事件,eg:摇杆,触摸屏
         * EV_MSC:其他事件,功能
         * EV_LED:LED灯事件
         * EV_SND:声音事件
         * EV_REP:重复键盘按键事件(内部有一个定时器,若有按键事件一直按下/松动,就重复定时,时间一到就上报事件)
         * EV_FF: 受力事件
         * EV_PWR:电源事件
         * EV_FF_STATUB: 受力状态事件
         */

	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];            // 存放支持的按键值
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];            // 存放支持的相对坐标         
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];            // 存放支持的绝对坐标
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];            // 存放支持的其他事件,也就是功能
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];            // 存放支持的各种状态的LED
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];            // 存放支持的各种声音
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];              // 存放支持的受力设备
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];              // 存放支持的开关功能

	unsigned int hint_events_per_packet;

	unsigned int keycodemax;
	unsigned int keycodesize;
	void *keycode;

	int (*setkeycode)(struct input_dev *dev,
			  const struct input_keymap_entry *ke,
			  unsigned int *old_keycode);
	int (*getkeycode)(struct input_dev *dev,
			  struct input_keymap_entry *ke);

	struct ff_device *ff;

	unsigned int repeat_key;
	struct timer_list timer;

	int rep[REP_CNT];

	struct input_mt_slot *mt;
	int mtsize;
	int slot;
	int trkid;

	struct input_absinfo *absinfo;

	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
	unsigned long led[BITS_TO_LONGS(LED_CNT)];
	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
	unsigned long sw[BITS_TO_LONGS(SW_CNT)];

	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 __rcu *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	bool sync;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;
};

input_allocate_device:向内核申请一个input_dev设备,然后返回这个设备

  struct input_dev *input_allocate_device(void)

input_free_device:释放这个结构体,一般在驱动出口函数

void input_free_device(struct input_dev *dev)
EXPORT_SYMBOL(input_free_device);

input_unregister_device:卸载/sys/class/input目录下的input_dev这类设备,一般在驱动的出口处写

void input_unregister_device(struct input_dev *dev)
EXPORT_SYMBOL(input_unregister_device);            //标签内定义的函数或者符号对全部内核代码公开

set_bit:用来设置为变量,这里用来设置支持的事件类型

  static inline void set_bit(int nr, volatile unsigned long *addr)
  eg:      set_bit(KEY_L, buttons_dev->keybit);

input_event:事件上报

  void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
  //dev:要上报那个input驱动设备事件
  //type:要上报的事件类型:eg:按键填EV_KEY
  //code:对应事件里支持那个变量,eg:如按下按键L,则填入KEY_L
  //value:对应变量里的数值,eg:松开按键填入0,按下按键填入1
  
  //注意上报完事件之后需要调用input_sync来同步事件

input_sync:同时事件,其实上报事件并未把事件上报给内核,而是存储在某个地方,由intput_sync来实现上报

  static inline void input_sync(struct input_dev *dev)
  {
      input_event(dev, EV_SYN, SYN_REPORT, 0);
  }

4.源码解析

struct pin_desc{
	int irq;
	char *name;
	unsigned int pin;
	unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
	{IRQ_EINT0,  "S2", S3C2410_GPF0,   KEY_L},
	{IRQ_EINT2,  "S3", S3C2410_GPF2,   KEY_S},
	{IRQ_EINT11, "S4", S3C2410_GPG3,   KEY_ENTER},
	{IRQ_EINT19, "S5",  S3C2410_GPG11, KEY_LEFTSHIFT},
};

static struct input_dev *buttons_dev;      //硬件设备
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	/* 10ms后启动定时器 */
	irq_pd = (struct pin_desc *)dev_id;
	mod_timer(&buttons_timer, jiffies+HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
}

static void buttons_timer_function(unsigned long data)
{
	struct pin_desc * pindesc = irq_pd;
	unsigned int pinval;

	if (!pindesc)
		return;
	
	pinval = s3c2410_gpio_getpin(pindesc->pin);

	if (pinval)
	{
		/* 松开 : 最后一个参数: 0-松开, 1-按下 */
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
		input_sync(buttons_dev);
	}
	else
	{
		/* 按下 */
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
		input_sync(buttons_dev);
	}
}

static int buttons_init(void)
{
	int i;
	
	/* 1. 分配一个input_dev结构体 */
	buttons_dev = input_allocate_device();

	/* 2. 设置 */
	/* 2.1 能产生哪类事件 */
	set_bit(EV_KEY, buttons_dev->evbit);
	set_bit(EV_REP, buttons_dev->evbit);
	
	/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
	set_bit(KEY_L, buttons_dev->keybit);
	set_bit(KEY_S, buttons_dev->keybit);
	set_bit(KEY_ENTER, buttons_dev->keybit);
	set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);

	/* 3. 注册 */
	input_register_device(buttons_dev);
	
	/* 4. 硬件相关的操作 */
	init_timer(&buttons_timer);
	buttons_timer.function = buttons_timer_function;
	add_timer(&buttons_timer);
	
        // 注册中断
	for (i = 0; i < 4; i++)
	{
		request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
	}
	
	return 0;
}

static void buttons_exit(void)
{
	int i;
	for (i = 0; i < 4; i++)
	{
		free_irq(pins_desc[i].irq, &pins_desc[i]);
	}

	del_timer(&buttons_timer);
	input_unregister_device(buttons_dev);
	input_free_device(buttons_dev);	
}

module_init(buttons_init);

module_exit(buttons_exit);

MODULE_LICENSE("GPL");
原文地址:https://www.cnblogs.com/huangdengtao/p/13296741.html