天天看點

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;                     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; 我隻是截取了與我們有關的本分

繼續閱讀