s3c2440触摸屏驱动分析(LINUX2.6)(3)

这篇文章主要是分析tsdev的设备结点的访问的,通过此分析,也会领悟到整个中断过程和事件上报(event处理)的过程。关于设备结点的访问肯定离不开我们平时谈到的操作指针,与tsdev设备对应的操作指针就是&tsdev_fops(其是tsdev_handler结构体中的一员)。这时有人肯定有一点疑惑,在input文件夹下那么多的.c文件,每个文件都会有对应的input_handler结构体,也就是会有相应的&input_fops指针操作指针,这样一来,我们怎么知道使用哪个操作指针哦?好的,我们先来看看以下代码:

input子系统的初始化

static int __init input_init(void)
{
         int err;
 
         err = class_register(&input_class);//这里注册了一个类,所有的input device都是属于此类的,在sys系统表现为所有input device都会在/dev/class/input目录下。
         if (err) {
                   printk(KERN_ERR "input: unable to register input_dev class/n");
                   return err;
         }
 
         err = input_proc_init();//在/proc下面建立相关的交互文件.
         if (err)
                   goto fail1;
 
         err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//然后注册主设备号INPUT_MAJOR(13),次设备号0~255,操作指针是&input_fops
         if (err) {
                   printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
                   goto fail2;
         }
 
         return 0;
 
 fail2:        input_proc_exit();
 fail1:        class_unregister(&input_class);
         return err;
}
Input_fops定义如下:
static const struct file_operations input_fops = {
         .owner = THIS_MODULE,
         .open = input_open_file,
};
打开文件所对应的操作函数为input_open_file.代码如下示:
static int input_open_file(struct inode *inode, struct file *file)
{
         struct input_handler *handler = input_table[iminor(inode) >> 5];
         const 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;//找到handler后就判断它是否存在,同时判断它是否有操作指针。
iminor(inode)作用是通过设备结点,可以求出设备的次设备号。input_table是input_handler结构体的全局数组,通过次设备号右移5位后,在数组中找到相应的handler。到这里就有点眉目了吧,我们通过input_table这个全局数组,很方便的找到了我们设备对应input_handler。对于我们上面的实例,我们可以通过tsdev中设备的此设备号,得到对应的tsdev_handler。
         if (!new_fops->open) {
                   fops_put(new_fops);
                   return -ENODEV;
         }
         old_fops = file->f_op;
         file->f_op = new_fops;//以上两行完成了对handler->fops操作指针的保存
 
         err = new_fops->open(inode, file);//如果存在open就调用
 
         if (err) {
                   fops_put(file->f_op);
                   file->f_op = fops_get(old_fops);
         }
         fops_put(old_fops);
         return err;
}
到这里大家应该明白了吧,总的来说,如果对设备结点进行open操作后,由上诉代码就会完成其设备对应的handler的查找,再转向对handler的操作指针中open函数的调用。具体问题具体分析,我们现在来分析一下tsdev_open的代码吧。
static int tsdev_open(struct inode *inode, struct file *file)
{
 int i = iminor(inode) - TSDEV_MINOR_BASE;//这样就可以得到在tsdev_table[]中的序号了
 struct tsdev_client *client;
 struct tsdev *tsdev;
 int error;

 if (i >= TSDEV_MINORS)
  return -ENODEV;
 error = mutex_lock_interruptible(&tsdev_table_mutex);
 if (error)
    return error;
 tsdev = tsdev_table[i & TSDEV_MINOR_MASK];//然后在数组中取出对应的tsdev
 if (tsdev)
    get_device(&tsdev->dev);//增加tsdev中的device的引用计数
 mutex_unlock(&tsdev_table_mutex);
 if (!tsdev)
    return -ENODEV;
 client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);//向内核申请一个tsdev_client的数据结构的空间
 if (!client) {
  error = -ENOMEM;
  goto err_put_tsdev;
 }
 spin_lock_init(&client->buffer_lock);
 client->tsdev = tsdev;//使tsdev与client联系起来
 client->raw = i >= TSDEV_MINORS / 2;
 tsdev_attach_client(tsdev, client);//把client挂在tsdev的client_list列表上
 error = tsdev_open_device(tsdev);
 if (error)
  goto err_free_client;
 file->private_data = client;//将client赋给file的私有区
 return 0;
 err_free_client:
          tsdev_detach_client(tsdev, client);
          kfree(client);
 err_put_tsdev:
          put_device(&tsdev->dev);
          return error;
}
我们来分析一下tsdev_open_device的代码:
static int tsdev_open_device(struct tsdev *tsdev)
{
 int retval;
 retval = mutex_lock_interruptible(&tsdev->mutex);
 if (retval)
  return retval;
 if (!tsdev->exist)
  retval = -ENODEV;
 else if (!tsdev->open++) {
  retval = input_open_device(&tsdev->handle);
  if (retval)
   tsdev->open--;
 }
 mutex_unlock(&tsdev->mutex);
 return retval;
}
可以看出input_open_device是重点,else if(!tsdev->open++)可以看出判断是否是第一次打开的。如果是第一次打开就调用input_open_device函数,我们来分析一下这个函数代码吧:
int input_open_device(struct input_handle *handle)
{
 struct input_dev *dev = handle->dev;//从handle中获得input_dev结构体
 int retval;
 retval = mutex_lock_interruptible(&dev->mutex);
 if (retval)
     return retval;
 if (dev->going_away) {
     retval = -ENODEV;
     goto out;
 }
 handle->open++;//增加handle的引用计数
 if (!dev->users++ && dev->open)//如果是第一次打开的,并且dev存在open函数,这样就直接调用dev->open(dev)
     retval = dev->open(dev);
 if (retval) {
  dev->users--;
  if (!--handle->open) {
    synchronize_rcu();
  }
 }
 out:
      mutex_unlock(&dev->mutex);
      return retval;
}
可以看出这里存在原子操作。
在分析对设备结点read和write的时候,我们先来分析一下tsdev的事件处理。还记得我们在第一篇文章中分析了触摸屏的中断了吗?每次触笔按下,AD数据转换,最后到触笔抬起的整个过程中,有两次事件上报,一次是AD几次数据转换后的值,填充到ts.xp和ts.yp的数据缓冲区里,当填满后再求均值,最后把key和abs事件上报。第二次事件上报是,当触笔抬起的时候将key和abs的事件上报。好的,现在我们来好好分析一下吧。
我们先来分析第一次的事件上报的过程吧,我们又回到touch_timer_fire函数代码当中来,注意一下的代码:
    input_report_abs(ts.dev, ABS_X, ts.xp);
    input_report_abs(ts.dev, ABS_Y, ts.yp);
    input_report_key(ts.dev, BTN_TOUCH, 1);
    input_report_abs(ts.dev, ABS_PRESSURE, 1);
想必大家很熟悉了,其实这3者都封装了input_event函数,我们拿其中一个来分析一下吧!
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
 input_event(dev, EV_ABS, code, value);/可以看到是对EV_ABS事件的处理
}
我们继续深入:
void input_event(struct input_dev *dev,
   unsigned int type, unsigned int code, int value)//这里的参数对应的顺序是:ts.dev,EV_ABS,ABS_X,ts.xp
{
 unsigned long flags;
 if (is_event_supported(type, dev->evbit, EV_MAX)) {//首先判断设备是否支持这类功能
  spin_lock_irqsave(&dev->event_lock, flags);
  add_input_randomness(type, code, value);
  input_handle_event(dev, type, code, value);//这个函数很重要,我们来看看这里面的代码吧
  spin_unlock_irqrestore(&dev->event_lock, flags);
 }
}
这个代码很长,我们不需要全看,我们只需要看看我们需要的部分。
static void input_handle_event(struct input_dev *dev,
          unsigned int type, unsigned int code, int value)
{
 int disposition = INPUT_IGNORE_EVENT;
 switch (type) {//很明显,type是EV_ABS
 case EV_SYN:
  switch (code) {
  case SYN_CONFIG:
   disposition = INPUT_PASS_TO_ALL;
   break;
  case SYN_REPORT:
   if (!dev->sync) {
    dev->sync = 1;
    disposition = INPUT_PASS_TO_HANDLERS;
   }
   break;
  }
  break;
 case EV_KEY:
  if (is_event_supported(code, dev->keybit, KEY_MAX) &&
      !!test_bit(code, dev->key) != value) {
   if (value != 2) {
    __change_bit(code, dev->key);
    if (value)
     input_start_autorepeat(dev, code);
   }
   disposition = INPUT_PASS_TO_HANDLERS;
  }
  break;
 case EV_SW:
  if (is_event_supported(code, dev->swbit, SW_MAX) &&
      !!test_bit(code, dev->sw) != value) {
   __change_bit(code, dev->sw);
   disposition = INPUT_PASS_TO_HANDLERS;
  }
  break;
 case EV_ABS://这里就是我们需要关注的地方了,
  if (is_event_supported(code, dev->absbit, ABS_MAX)) {//这里判断是否支持ABS_X这个值
   value = input_defuzz_abs_event(value,
     dev->abs[code], dev->absfuzz[code]);//这个函数的具体操作我还是没办法弄明白,希望明白的同志和我说一声啦!
   if (dev->abs[code] != value) {//如果不同,我们就把新的value赋给abs[code]。
    dev->abs[code] = value;
    disposition = INPUT_PASS_TO_HANDLERS;//这个很重要,为最后的操作做好了铺垫。我们直接来看看程序的结尾处吧!
   }
  }
  break;
 case EV_REL:
  if (is_event_supported(code, dev->relbit, REL_MAX) && value)
   disposition = INPUT_PASS_TO_HANDLERS;
  break;
 case EV_MSC:
  if (is_event_supported(code, dev->mscbit, MSC_MAX))
   disposition = INPUT_PASS_TO_ALL;
  break;
 case EV_LED:
  if (is_event_supported(code, dev->ledbit, LED_MAX) &&
      !!test_bit(code, dev->led) != value) {
   __change_bit(code, dev->led);
   disposition = INPUT_PASS_TO_ALL;
  }
  break;
 case EV_SND:
  if (is_event_supported(code, dev->sndbit, SND_MAX)) {
   if (!!test_bit(code, dev->snd) != !!value)
    __change_bit(code, dev->snd);
   disposition = INPUT_PASS_TO_ALL;
  }
  break;
 case EV_REP:
  if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
   dev->rep[code] = value;
   disposition = INPUT_PASS_TO_ALL;
  }
  break;
 case EV_FF:
  if (value >= 0)
   disposition = INPUT_PASS_TO_ALL;
  break;
 case EV_PWR:
  disposition = INPUT_PASS_TO_ALL;
  break;
 }
 if (type != EV_SYN)
  dev->sync = 0;
 if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
  dev->event(dev, type, code, value);
 if (disposition & INPUT_PASS_TO_HANDLERS)
  input_pass_event(dev, type, code, value);//很明显,我们满足if语句里面的要求,我们再往下看看吧!
}
static void input_pass_event(struct input_dev *dev,
        unsigned int type, unsigned int code, int value)
{
 struct input_handle *handle;
 rcu_read_lock();
 handle = rcu_dereference(dev->grab);
 if (handle)//如果input device 被强制指定了handler的话,我们就执行指定的handler的event函数。关于如何强制指定handler是与ioctl标志为EVIOCGRAB有关的。
  handle->handler->event(handle, type, code, value);
 else//如果不是强制的话,我们就来遍历dev->h_list列表,我们知道handle是挂在这个链表上面的。
  list_for_each_entry_rcu(handle, &dev->h_list, d_node)//这个就是一个遍历过程,目的就是为了找到哪个handle被打开了,只有handle被打开后,它才可以接受事件,我们也就可以调用其对应的handler->event了。
   if (handle->open)
    handle->handler->event(handle,
       type, code, value);
 rcu_read_unlock();
}
在tsdev中.这个event函数对应的代码为:
static void tsdev_event(struct input_handle *handle, unsigned int type,
   unsigned int code, int value)
{
 struct tsdev *tsdev = handle->private;
 struct input_dev *dev = handle->dev;
 int wake_up_readers = 0;
 switch (type) {
 case EV_ABS:
  switch (code) {
  case ABS_X:
   tsdev->x = value;
   break;
  case ABS_Y:
   tsdev->y = value;
   break;
  case ABS_PRESSURE:
   if (value > dev->absmax[ABS_PRESSURE])
    value = dev->absmax[ABS_PRESSURE];
   value -= dev->absmin[ABS_PRESSURE];
   if (value < 0)
    value = 0;
   tsdev->pressure = value;
   break;
  }
  break;
我只是截取了与我们有关的本分
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值