Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1833585
  • 博文数量: 195
  • 博客积分: 4227
  • 博客等级: 上校
  • 技术积分: 2835
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-04 10:39
文章分类

全部博文(195)

文章存档

2013年(1)

2012年(26)

2011年(168)

分类: LINUX

2011-02-18 13:28:42

input子系统
 
谨以此文纪念过往的岁月。
 
一.前言
linux的input子系统在网上的资料很多,讲应用的很多,但是input子系统如何去工作的较少,想通过源码去理解input子系统如何工作的。
二.input子系统应用
一般input子系统应用流程如下
input_allocate_device -> input_register_device->input_event->input_unregister_device
关于其具体的使用会在讲述函数时说明。
2.1 input_dev 结构体
struct input_dev {
 const char *name;   
 const char *phys;   --物理路径
 const char *uniq;   --设备的唯一识别码
 struct input_id id; --设备id
 unsigned long evbit[BITS_TO_LONGS(EV_CNT)];   --BITS_TO_LONGS其实将多个bit组合成多个long类型的数据,evbit用于表明设备对事件类型的支持
 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)];
 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 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 sync;
 int abs[ABS_MAX + 1];
 int rep[REP_MAX + 1];
 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 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;
 spinlock_t event_lock;
 struct mutex mutex;
 unsigned int users;
 int going_away;
 struct device dev;
 struct list_head h_list;
 struct list_head node;
};
2.2申请设备
申请设备比较简单。
struct input_dev *input_allocate_device(void)
{
 struct input_dev *dev;
 dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
 if (dev) {
  dev->dev.type = &input_dev_type;   --设置设备类型
  dev->dev.class = &input_class;     --设置设备类
  device_initialize(&dev->dev);
  mutex_init(&dev->mutex);
  spin_lock_init(&dev->event_lock);
  INIT_LIST_HEAD(&dev->h_list);
  INIT_LIST_HEAD(&dev->node);
  __module_get(THIS_MODULE);
 }
 return dev;
}
2.3设备初始化
2.3.1设定设备所支持的事件
有两种手段可以去设定,1.__set_bit(EV_KEY,xx->evbit),设定evbit支持EV_KEY 2.xx_dev->evbit[0] = BIT(EV_KEY);
2.3.2设定设备事件使能位
其设置方法同上。
__set_bit(xx_keycodes[i], xx_dev->keybit);
对于上面两个性质的设置还可以通过调用input_set_capability函数来实现。
其源码如下:
下面的源码很简单易懂,不说了。
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
 switch (type) {
 case EV_KEY:
  __set_bit(code, dev->keybit);
  break;
 case EV_REL:
  __set_bit(code, dev->relbit);
  break;
 case EV_ABS:
  __set_bit(code, dev->absbit);
  break;
 case EV_MSC:
  __set_bit(code, dev->mscbit);
  break;
 case EV_SW:
  __set_bit(code, dev->swbit);
  break;
 case EV_LED:
  __set_bit(code, dev->ledbit);
  break;
 case EV_SND:
  __set_bit(code, dev->sndbit);
  break;
 case EV_FF:
  __set_bit(code, dev->ffbit);
  break;
 case EV_PWR:
  /* do nothing */
  break;
 default:
  printk(KERN_ERR
   "input_set_capability: unknown type %u (code %u)\n",
   type, code);
  dump_stack();
  return;
 }
 __set_bit(type, dev->evbit);
}
2.3.3设置设备的信息
设置设备的name,bus,以及open,close等等成员。关于open和close还有点事可以说的。open必须要返回0,否则出错,close无返回值。
2.4 input设备注册
int input_register_device(struct input_dev *dev)
{
 static atomic_t input_no = ATOMIC_INIT(0);   --这个记住每调用一次该函数input_no增加一次
 struct input_handler *handler;               --设置handler初始
 const char *path;
 int error;
 __set_bit(EV_SYN, dev->evbit);     --每个设备都要支持该事件
 init_timer(&dev->timer);           --初始化定时器,在linux中采用定时器定时去查询设备事件
 if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {   --如果rep没有设定
  dev->timer.data = (long) dev;             
  dev->timer.function = input_repeat_key;  --定时器处理函数
  dev->rep[REP_DELAY] = 250;
  dev->rep[REP_PERIOD] = 33;
 }
 if (!dev->getkeycode)
  dev->getkeycode = input_default_getkeycode;
 if (!dev->setkeycode)
  dev->setkeycode = input_default_setkeycode;
 dev_set_name(&dev->dev, "input%ld",(unsigned long) atomic_inc_return(&input_no) - 1); --设置设备名称
 error = device_add(&dev->dev);    --设备添加
 if (error)
  return error;
 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
 printk(KERN_INFO "input: %s as %s\n",dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
 kfree(path);
 error = mutex_lock_interruptible(&input_mutex);    --锁定互斥
 if (error) {
  device_del(&dev->dev);
  return error;
 }
 list_add_tail(&dev->node, &input_dev_list);    --将设备节点添加到input设备链表中。
 list_for_each_entry(handler, &input_handler_list, node)   --从input处理链表中查询匹配
  input_attach_handler(dev, handler);             --匹配处理函数
 input_wakeup_procfs_readers();   --这个不管
 mutex_unlock(&input_mutex);
 return 0;
}
根据上面的函数,来一一分析其调用的函数。
No.1 input_repeat_key该函数在没有设定repeat参数情况下调用。下面的函数在看event层的时候在回过头来看。
static void input_repeat_key(unsigned long data)   
{
 struct input_dev *dev = (void *) data;
 unsigned long flags;
 spin_lock_irqsave(&dev->event_lock, flags);  --自旋锁锁定,记住临界区的代码不能够阻塞。
 if (test_bit(dev->repeat_key, dev->key) &&is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
  input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
  if (dev->sync) {
   input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
  }
  if (dev->rep[REP_PERIOD])
   mod_timer(&dev->timer, jiffies +
     msecs_to_jiffies(dev->rep[REP_PERIOD]));
 }
 spin_unlock_irqrestore(&dev->event_lock, flags);
}
No.2 input_default_getkeycode
这个函数是默认的获取keycode,下面的函数又是很好理解的,偷懒一下。
static int input_default_getkeycode(struct input_dev *dev, int scancode, int *keycode)
{
 if (!dev->keycodesize)
  return -EINVAL;
 if (scancode >= dev->keycodemax)
  return -EINVAL;
 *keycode = input_fetch_keycode(dev, scancode);
 return 0;
}
static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
 switch (dev->keycodesize) {
  case 1:
   return ((u8 *)dev->keycode)[scancode];
  case 2:
   return ((u16 *)dev->keycode)[scancode];
  default:
   return ((u32 *)dev->keycode)[scancode];
 }
}
No.3 input_default_setkeycode
默认的设置keycode函数,来好好看一下。
static int input_default_setkeycode(struct input_dev *dev,int scancode, int keycode)
{
 int old_keycode;
 int i;
 if (scancode >= dev->keycodemax)    --scancode是设置的"位",检查设置位是否溢出
  return -EINVAL;
 if (!dev->keycodesize)   
  return -EINVAL;
 if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))  --检测大小是否匹配。
  return -EINVAL;
 switch (dev->keycodesize) {  --下面是查询替换事件查询表
  case 1: {
   u8 *k = (u8 *)dev->keycode;
   old_keycode = k[scancode];
   k[scancode] = keycode;
   break;
  }
  case 2: {
   u16 *k = (u16 *)dev->keycode;
   old_keycode = k[scancode];
   k[scancode] = keycode;
   break;
  }
  default: {
   u32 *k = (u32 *)dev->keycode;
   old_keycode = k[scancode];
   k[scancode] = keycode;
   break;
  }
 }
 clear_bit(old_keycode, dev->keybit);  --更改位
 set_bit(keycode, dev->keybit);
 for (i = 0; i < dev->keycodemax; i++) {   --防止出错
  if (input_fetch_keycode(dev, i) == old_keycode) {
   set_bit(old_keycode, dev->keybit);
   break; /* Setting the bit twice is useless, so break */
  }
 }
 return 0;
}
No.4 input_attach_handler
这个函数很重要,这个其实类似于platform中probe函数,将设备与设备事件处理相连接。
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
 const struct input_device_id *id;
 int error;
 if (handler->blacklist && input_match_device(handler->blacklist, dev))  --先检测dev是否在黑名单中,强人!!!下面会看这handler在哪儿设置了。
  return -ENODEV;
 id = input_match_device(handler->id_table, dev);  --查询到设备id表
 if (!id)
  return -ENODEV;
 error = handler->connect(handler, dev, id);   --将两者连接起来。
 if (error && error != -ENODEV)
  printk(KERN_ERR"input: failed to attach handler %s to device %s, ""error: %d\n",handler->name, kobject_name(&dev->dev.kobj), error);
 return error;
}
这儿先转走,那handler的input_handler_list在哪儿添加成员的呢?
阅读(2369) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~