<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【Linux】關(guān)于正點(diǎn)原子input子系統(tǒng),驅(qū)動(dòng)中按鍵中斷只檢測(cè)了上升或下降沿卻可以實(shí)現(xiàn)連按(EV_REP)的原因

      問(wèn)題

      在學(xué)習(xí)到Linux內(nèi)核input子系統(tǒng)時(shí),產(chǎn)生了一個(gè)疑惑。可以看到,我們改造按鍵中斷驅(qū)動(dòng)程序(請(qǐng)見(jiàn)keyinputdriver.c(內(nèi)核驅(qū)動(dòng)代碼)),通過(guò)檢測(cè)按鍵的上升沿和下降沿,在中斷處理函數(shù)(上半部?jī)?nèi))通過(guò)mod_timer(&dev->timer, jiffies + msecs_to_jiffies(20))函數(shù)啟動(dòng)定時(shí)器。在定時(shí)器處理函數(shù)中上報(bào)和同步按鍵事件(EV_KEY和EV_REP)。那么問(wèn)題來(lái)了,驅(qū)動(dòng)中,按鍵中斷是上升沿和下降沿觸發(fā),當(dāng)連按的時(shí)候,中斷只觸發(fā)了一次,為什么會(huì)一直上報(bào)的呢?

      keyinputdriver.c(內(nèi)核驅(qū)動(dòng)代碼)點(diǎn)擊查看代碼
      #include <linux/module.h>
      #include <linux/kernel.h>
      #include <linux/init.h>
      #include <linux/fs.h>
      #include <linux/slab.h>
      #include <linux/uaccess.h>
      #include <linux/io.h>
      #include <linux/cdev.h>
      #include <linux/device.h>
      #include <linux/of.h>
      #include <linux/of_address.h>
      #include <linux/of_gpio.h>
      #include <linux/irq.h>
      #include <linux/of_irq.h>
      #include <linux/types.h>
      #include <linux/atomic.h>
      #include <linux/string.h>
      #include <linux/interrupt.h>
      #include <asm/mach/map.h> 
      #include <asm/uaccess.h> 
      #include <asm/io.h>
      #include <linux/input.h>
      
      #define KEYINPUT_CNT        1
      #define KEYINPUT_NAME       "keyinput"
      #define KEY_NUM             1
      #define KEY0_VALUE          0X01
      #define INVAKEY             0XFF
      
      
      struct irq_keydesc
      {
          int gpio;                                   /* io編號(hào) */
          int irqnum;                                 /* 中斷號(hào) */
          unsigned char value;                        /* 鍵值 */
          char name[10];                              /* 名字 */
          irqreturn_t (*handler)(int, void*);         /* 中斷處理函數(shù) */
      
      };
      
      
      struct keyinput_dev
      {
          struct device_node *nd;
          struct irq_keydesc irqkey[KEY_NUM];
          struct timer_list timer;
          
          struct input_dev *inputdev;
      };
      struct keyinput_dev keyinput;
      
      
      /* 按鍵處理函數(shù) */
      static irqreturn_t key0_handler(int irq, void *dev_id)
      {
          struct keyinput_dev *dev = dev_id;
      
          dev->timer.data = (volatile unsigned long)dev;
          /* 開(kāi)始定時(shí) */
          mod_timer(&dev->timer, jiffies + msecs_to_jiffies(20));
          
          return IRQ_HANDLED;
      }
      
      /* 定時(shí)器處理函數(shù) */
      static void timer_func(unsigned long arg)
      {
          int value = 0;
          struct keyinput_dev *dev = (struct keyinput_dev*)arg;
          
          value = gpio_get_value(dev->irqkey[0].gpio);
          if (0 == value) /* 按下 */
          {
              // printk("KEY0 press!\r\n");
              input_event(dev->inputdev, EV_KEY, KEY_0, 1);
               
          }
          else if (1 == value) /* 釋放 */
          {
              // printk("KEY0 release!\r\n");
              input_event(dev->inputdev, EV_KEY, KEY_0, 0);
              
          }
          input_sync(dev->inputdev);
      }
      
      /* 按鍵初始化 */
      static int keyio_init(struct keyinput_dev *dev)
      {
          int i = 0;
          int ret = 0;
          /* 按鍵初始化 */
          dev->nd = of_find_node_by_path("/key");
          if (NULL == dev->nd)
          {
              ret = -EINVAL;
              goto fail_findnode;
          }
          
          for (i = 0; i < KEY_NUM; i++)
          {
              dev->irqkey[i].gpio = of_get_named_gpio(dev->nd, "key-gpios", i);
          }
      
          for (i = 0; i < KEY_NUM; i++)
          {
              memset(dev->irqkey[i].name, 0, sizeof(dev->irqkey[i].name));
              sprintf(dev->irqkey[i].name, "KEY%d", i);
              gpio_request(dev->irqkey[i].gpio, "key-gpios");
              gpio_direction_input(dev->irqkey[i].gpio);
              /* 按鍵中斷初始化 */
              dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);
      #if 0
              dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd, i);
      #endif // 0         
          }
          
          /* 按鍵中斷初始化 */
          dev->irqkey[0].handler = key0_handler;
          dev->irqkey[0].value = KEY0_VALUE;
          for (i = 0; i < KEY_NUM; i++)
          {
              ret = request_irq(dev->irqkey[i].irqnum, dev->irqkey[i].handler, 
                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 
                          dev->irqkey[i].name, 
                          &keyinput);
              if (ret)
              {
                  printk("irq %d request failed!\r\n", dev->irqkey[i].irqnum);
                  goto fail_irq;
              }
          }
      
          /* 定時(shí)器初始化 */
          init_timer(&dev->timer);
          dev->timer.function = timer_func;
      
      
      
      fail_irq:
          for (i = 0; i < KEY_NUM; i++)
          {
              gpio_free(dev->irqkey[i].gpio);
          }
      fail_findnode:
          return ret;
      }
      
      static int __init keyinput_init(void)
      {
          int ret = 0;
      
          /* 1、初始化io key */
          ret = keyio_init(&keyinput);
          if (ret < 0)
          {
              goto fail_keyinit;
          }
      
          /* 2、注冊(cè)input_dev*/
          keyinput.inputdev = input_allocate_device();
          if (NULL == keyinput.inputdev)
          {
              ret = -EINVAL;
              goto fail_keyinit;
          }
      
          keyinput.inputdev->name = KEYINPUT_NAME;
          __set_bit(EV_KEY, keyinput.inputdev->evbit);    //設(shè)置按鍵事件
          __set_bit(EV_REP, keyinput.inputdev->evbit);    //設(shè)置重復(fù)事件
          __set_bit(KEY_0, keyinput.inputdev->keybit);    //設(shè)置key0
      
          ret = input_register_device(keyinput.inputdev);
          if (ret)
          {
              goto fail_input_register;
          }
          
          return 0;
      fail_input_register:
          input_free_device(keyinput.inputdev);
      fail_keyinit:
          return ret;
      }
      
      
      static void __exit keyinput_exit(void)
      {
          int i = 0;
          /* 1、刪除定時(shí)器 */
          del_timer_sync(&keyinput.timer);
      
          /* 2、釋放中斷 */
          for (i = 0; i < KEY_NUM; i++)
          {
              free_irq(keyinput.irqkey[i].irqnum, &keyinput);
          }
          /* 3、釋放GPIO */
          for (i = 0; i < KEY_NUM; i++)
          {
              gpio_free(keyinput.irqkey[i].gpio);
          }
      
          /* 4、注銷(xiāo)input_dev */
          input_unregister_device(keyinput.inputdev);
          input_free_device(keyinput.inputdev);
      }
      
      
      module_init(keyinput_init);
      module_exit(keyinput_exit);
      
      MODULE_AUTHOR("tyler");
      MODULE_LICENSE("GPL");
      
      keyinputAPP.c(測(cè)試APP代碼)點(diǎn)擊查看代碼
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      #include <poll.h> 
      #include <sys/select.h> 
      #include <sys/time.h> 
      #include <signal.h> 
      #include <fcntl.h>
      #include <linux/input.h>
      /*
       * ./keyinputAPP <filename> <0/1>
       * ./keyinputAPP /dev/input/event2  
       * 
       */
      
      
      static struct input_event inputevent;
      
      int main(int argc, char* argv[])
      {
          int fd, err;
          char * filename;
      
          if (argc != 2)
          {
              printf("args num error!!\r\n");
              return -1;
          }
          
          filename = argv[1];
      
          fd = open(filename, O_RDWR);
          if (fd < 0)
          {
              printf("open error\r\n");
              return -1;
          }
          while (1)
          {
              err = read(fd, &inputevent, sizeof(inputevent));
              if (err > 0) /* 數(shù)據(jù)讀取成功 */
              {
                  switch (inputevent.type)
                  {
                  case EV_KEY:
                      if (inputevent.code < BTN_MISC)
                      {
                          printf("key %d %s\r\n", inputevent.code, inputevent.value ? "press":"release");
                      }
                      else
                      {
                          printf("button %d %s\r\n", inputevent.code, inputevent.value ? "press":"release");
                      }
                      
                      printf("EV_KEY事件\r\n");
                      break;
                  case EV_SYN:
                      
                      break;
                  case EV_REL:
                      break;
                  case EV_ABS:
                      break;
                  };
      
              }
              else
              {
                  printf("讀取失敗!\r\n");
              }
              
          }
          
      
          close(fd);
          return 0;
      }
      
      
      

      input輸入系統(tǒng)實(shí)現(xiàn)按鍵重復(fù)的方式

      簡(jiǎn)單來(lái)說(shuō),在input的子系統(tǒng)中,實(shí)現(xiàn)按鍵重復(fù)的方式是啟動(dòng)了一個(gè)內(nèi)核定時(shí)器,通過(guò)保存按鍵值和上一次的值進(jìn)行比較來(lái)檢測(cè)按鍵是否按下。如果沒(méi)檢測(cè)到釋放按鍵,那么就會(huì)不斷地利用mod_timer來(lái)啟動(dòng)定時(shí)器,進(jìn)行按鍵重復(fù)上報(bào)。當(dāng)釋放了按鍵,那么就不會(huì)重復(fù)啟動(dòng)定時(shí)器,即停止了按鍵重復(fù)事件。
      那就清晰了。我們的驅(qū)動(dòng)程序中,檢測(cè)到了按鍵上升沿中斷后,EV_REP事件在沒(méi)用檢測(cè)到按鍵鍵值改變(也就是下降沿中斷),就默認(rèn)開(kāi)啟內(nèi)核定時(shí)器,便會(huì)一直上報(bào)重復(fù)事件EV_REP了。

      參考資料:https://blog.51cto.com/assassinwu/1080111 (input輸入系統(tǒng)中是如何實(shí)現(xiàn)按鍵重復(fù) )

      posted @ 2024-08-31 20:52  Tyler77  閱讀(114)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产婷婷综合在线视频中文| 国产免费又黄又爽又色毛| 久久爱在线视频在线观看| 亚洲精品乱码久久久久久按摩高清 | 精品国产女同疯狂摩擦2| AV老司机色爱区综合| 欧美色aⅴ欧美综合色| 色五月丁香五月综合五月| 亚洲人成电影网站色mp4| 久久超碰97人人做人人爱| 变态另类视频一区二区三区| 18禁精品一区二区三区| 亚洲欧美综合中文| 日本污视频在线观看| 亚洲一二区在线视频播放| 最新精品国偷自产在线美女足| 污网站在线观看视频| 91精品国产麻豆国产自产| 亚洲国产日韩a在线播放| 久久综合色最新久久综合色| 无码熟妇人妻av影音先锋| 爆乳2把你榨干哦ova在线观看 | 久久精品国产亚洲αv忘忧草| 黄页网站在线观看免费视频| 亚洲一区二区三区啪啪| 国内揄拍国内精品人妻久久| 久久天天躁狠狠躁夜夜婷| 靖江市| 看亚洲黄色不在线网占| 99久久国产福利自产拍| 亚洲一区久久蜜臀av| 亚洲精品成人一二三专区| 麻豆精品久久久久久久99蜜桃| 欧美人与zoxxxx另类| 精品激情视频一区二区三区 | 内射干少妇亚洲69xxx| 国产成人亚洲欧美二区综合| 99亚洲男女激情在线观看| 国产初高中生粉嫩无套第一次| 奇米网777狠狠狠俺| 亚洲最大福利视频网|