所谓技术

-----simple,sometimes naive!
posts - 11, comments - 0, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

输入子系统的实现

Posted on 2008-05-28 21:28 vsolo 阅读(1526) 评论(0)  编辑 收藏 引用 所属分类: LINUX

这是2.6.15以前某个版本,2.6.15已经略有不同,但总体思想还是差不多

输入子系统大致实现方法:

   底层驱动层(input_dev)-----<通过结构体input_handle关联>-----输入事件处理层类接口(input_handler)-----<输入核心层input.c>-----应用层

-----------------------------------------------------
struct input_handle { //用于关联底层驱动层input_dev和事件处理层input_handler

 void *private;

 int open;

 struct input_dev *dev;
 struct input_handler *handler;

 struct input_handle *dnext;
 struct input_handle *hnext;
};
-----------------------------------------------------
void input_register_device(struct input_dev *dev)
{
 struct input_handler *handler = input_handler;
 struct input_handle *handle;

/*
 * Initialize repeat timer to default values.
 */

 init_timer(&dev->timer);
 dev->timer.data = (long) dev;
 dev->timer.function = input_repeat_key;
 dev->rep[REP_DELAY] = HZ/4;
 dev->rep[REP_PERIOD] = HZ/33;

/*
 * Add the device.
 */

 if (input_number >= INPUT_DEVICES) {
  printk(KERN_WARNING "input: ran out of input device numbers!\n");
  dev->number = input_number;
 } else {
  dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
  set_bit(dev->number, input_devices);     //编号此输入设备
 }       //input_devices[8],8*32(BITS_PER_LONG)=256b,256 minor for each major
  
 dev->next = input_dev;    //插入到单链表首 
 input_dev = dev;
 input_number++;

/*
 * Notify handlers.
 */

 while (handler) {     //故应先通过input_register_handler注册handler到单链表中,即输入子系统的第二层:事件处理层
        //事件处理层是类通用的,如endev,tsdev,mousedev等
        //且某个具体的驱动层设备可以关联多个事件处理层接口,生成多个节点
        //用户程序根据打开的节点判断调用某一类事件处理层接口,进而关联驱动层
  if ((handle = handler->connect(handler, dev)))
   input_link_handle(handle);
                                                  -------------------------------
                                                  static void input_link_handle(struct input_handle *handle)
                                                  {
                                                    handle->dnext = handle->dev->handle;
                                                    handle->hnext = handle->handler->handle;
                                                    handle->dev->handle = handle;
                                                    handle->handler->handle = handle;
                                                  }
                                                  -------------------------------
  handler = handler->next;
 }
}


------------------------------------------------
以endev为例:


static struct input_handler evdev_handler = {
 event:  evdev_event,
 connect: evdev_connect,
 disconnect: evdev_disconnect,
 fops:  &evdev_fops,
 minor:  EVDEV_MINOR_BASE,
};

static struct file_operations evdev_fops = {
 owner:  THIS_MODULE,
 read:  evdev_read,
 write:  evdev_write,
 poll:  evdev_poll,
 open:  evdev_open,
 release: evdev_release,
 ioctl:  evdev_ioctl,
 fasync:  evdev_fasync,
};


-------------------------------------

void input_register_handler(struct input_handler *handler)
{
 struct input_dev *dev = input_dev;
 struct input_handle *handle;

/*
 * Add minors if needed.
 */

 if (handler->fops != NULL)
  input_table[handler->minor >> 5] = handler;

/*
 * Add the handler.
 */

 handler->next = input_handler;   //插入到单链表首
 input_handler = handler;
 
/*
 * Notify it about all existing devices.
 */

 while (dev) {
  if ((handle = handler->connect(handler, dev)))  
   input_link_handle(handle);
  dev = dev->next;
 }
}


----------------------------------------
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
{
 struct evdev *evdev;
 int minor;

 for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); //evdev_table记录endev的个数
 if (minor == EVDEV_MINORS) {
  printk(KERN_ERR "evdev: no more free evdev devices\n");
  return NULL;
 }

 if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))           //申请一个新的endev
  return NULL;
 memset(evdev, 0, sizeof(struct evdev));

 init_waitqueue_head(&evdev->wait);

 evdev->minor = minor;
 evdev_table[minor] = evdev;       //添加到evdev_table

 evdev->handle.dev = dev;       //实现驱动层和事件处理层的关联
 evdev->handle.handler = handler;
 evdev->handle.private = evdev;

 evdev->exist = 1;

 evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);

// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);

 return &evdev->handle;
}
------------------------------------------
devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
{
 char devfs_name[16];
 sprintf(devfs_name, name, minor);     //创建设备节点:INPUT_MAJOR=13,
          //minor_base+minor:
          //       EVDEV_MINOR_BASE(64)+(0-31);
          //       MOUSEDEV_MINOR_BASE(32)+(0-31);
          //       JOYDEV_MINOR_BASE(0)+(0-31);
          //       TSDEV_MINOR_BASE(128)+(0-31);
          //input_devfs_handle=devfs_mk_dir(NULL, "input", NULL);
          //在/dev/input/下可看到相关的input设备节点

 return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
  S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL);
}
-----------------------------------------
static int __init input_init(void)
{
 if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
  printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
  return -EBUSY;
 }
 input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
 return 0;
}


----------------------------------------
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
 struct input_handle *handle = dev->handle;

/*
 * Filter non-events, and bad input values out.
 */

 if (type > EV_MAX || !test_bit(type, dev->evbit))
  return;

 switch (type) {

  case EV_KEY:

   if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
    return;

   if (value == 2) break;

   change_bit(code, dev->key);

   if (test_bit(EV_REP, dev->evbit) && dev->timer.function) {
    if (value) {
     mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
     dev->repeat_key = code;
     break;
    }
    if (dev->repeat_key == code)
     del_timer(&dev->timer);
   }

   break;
  
  case EV_ABS:

   if (code > ABS_MAX || !test_bit(code, dev->absbit))
    return;

   if (dev->absfuzz[code]) {
    if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
        (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
     return;

    if ((value > dev->abs[code] - dev->absfuzz[code]) &&
        (value < dev->abs[code] + dev->absfuzz[code]))
     value = (dev->abs[code] * 3 + value) >> 2;

    if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
        (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
     value = (dev->abs[code] + value) >> 1;
   }

   if (dev->abs[code] == value)
    return;

   dev->abs[code] = value;
   break;

  case EV_REL:

   if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
    return;

   break;

  case EV_MSC:

   if (code > MSC_MAX || !test_bit(code, dev->mscbit))
    return;
 
   break;

  case EV_LED:
 
   if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
    return;

   change_bit(code, dev->led);
   if (dev->event) dev->event(dev, type, code, value); 
 
   break;

  case EV_SND:
 
   if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
    return;

   change_bit(code, dev->snd);
   if (dev->event) dev->event(dev, type, code, value); 
 
   break;

  case EV_REP:

   if (code > REP_MAX || dev->rep[code] == value) return;

   dev->rep[code] = value;
   if (dev->event) dev->event(dev, type, code, value);

   break;

  case EV_FF:
   if (dev->event) dev->event(dev, type, code, value);
   break;
 }

/*
 * Distribute the event to handler modules.
 */

 while (handle) {
                 //遍历每个打开的handle
  if (handle->open)
          //when open a input device,record it once time
          //in function input_open_device,handle->open++; 
   handle->handler->event(handle, type, code, value);
  handle = handle->dnext;
 }
}
-----------------------------------
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
 struct evdev *evdev = handle->private;
 struct evdev_list *list = evdev->list;

 while (list) {

  do_gettimeofday(&list->buffer[list->head].time);
  list->buffer[list->head].type = type;
  list->buffer[list->head].code = code;
  list->buffer[list->head].value = value;
  list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);

  kill_fasync(&list->fasync, SIGIO, POLL_IN);

  list = list->next;
 }

 wake_up_interruptible(&evdev->wait);   //填充数据结构,并唤醒相关的等待进程。
}
-----------------------------------

 

至于何时打开:
static struct file_operations input_fops = {
 owner: THIS_MODULE,
 open: input_open_file,
};
-----------------------------------
static int input_open_file(struct inode *inode, struct file *file)
{
 struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];  //LINUX最多8类事件处理层接口,各32个节点
             //打开某个设备时,根据节点大小选择事件处理层接口
 struct file_operations *old_fops, *new_fops = NULL;
 int err;

 /* No load-on-demand here? */
 if (!handler || !(new_fops = fops_get(handler->fops)))               //得到相应的事件处理层接口的操作接口
  return -ENODEV;

 /*
  * That's _really_ odd. Usually NULL ->open means "nothing special",
  * not "no device". Oh, well...
  */
 if (!new_fops->open) {
  fops_put(new_fops);
  return -ENODEV;
 }
 old_fops = file->f_op;
 file->f_op = new_fops;

 lock_kernel();
 err = new_fops->open(inode, file);                   //进一步调用
 unlock_kernel();

 if (err) {
  fops_put(file->f_op);
  file->f_op = fops_get(old_fops);
 }
 fops_put(old_fops);
 return err;
}
---------------------------------------
static int evdev_open(struct inode * inode, struct file * file)
{
 struct evdev_list *list;
 int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;         

 if (i >= EVDEV_MINORS || !evdev_table[i])
  return -ENODEV;

 if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
  return -ENOMEM;
 memset(list, 0, sizeof(struct evdev_list));

 list->evdev = evdev_table[i];                           //得到底层驱动层
 list->next = evdev_table[i]->list;
 evdev_table[i]->list = list;

 file->private_data = list;

 if (!list->evdev->open++)     //若未打开,则调用input_open_device并标识为打开
  if (list->evdev->exist)
   input_open_device(&list->evdev->handle);

 return 0;
}
--------------------------------------
int input_open_device(struct input_handle *handle)
{
 handle->open++;      //打开handle实现
 if (handle->dev->open)
  return handle->dev->open(handle->dev);  //驱动层若有open,进一步实现
 return 0;
}

只有注册用户登录后才能发表评论。