poll()函數實例

poll函數用於監測多個等待事件,若事件未發生,進程睡眠,放棄CPU控制權,若監測的任何一個事件發生,poll將喚醒睡眠的進程,並判斷是什麼等待事件發生,執行相應的操作。poll函數退出後,struct pollfd變量的所有值被清零,需要重新設置。
示例是使用poll函數來監測按鍵的輸入
----------------------------------------------------------------------------------------------------------

驅動代碼:
  1. #include <linux/config.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/fs.h>
  5. #include <linux/init.h>
  6. #include <linux/devfs_fs_kernel.h>
  7. #include <linux/miscdevice.h>
  8. #include <linux/delay.h>
  9. #include <asm/irq.h>
  10. #include <asm/arch/regs-gpio.h>
  11. #include <asm/hardware.h>
  12. #include <linux/cdev.h>
  13. #include <linux/mm.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/poll.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/ioctl.h>
  18. #include <asm/arch/regs-irq.h>
  19. #include <asm/io.h>

  20. #define key S3C2410_GPF0
  21. #define key_irq IRQ_EINT0 //IRQ_EINT0是中斷號
  22. #define key_cfg S3C2410_GPF0_EINT0 //設置爲外部中斷功能

  23. #define DEVICE_NAME "key" //注意加上雙引號
  24. #define DEVICE_MAJOR major 
  25. #define DEVICE_MINOR 0

  26. static dev_t dev; //dev_t類型用於存放主設備號和次設備號
  27. static int major;

  28. struct cdev *p_cdev; //聲明一個指向字符設備結構的指針

  29. static int key_event=0; //喚醒中斷的條件標記,1時滿足喚醒條件,靜態全局變量
  30. static int key_value=1; //按鍵鍵值
  31. static DECLARE_WAIT_QUEUE_HEAD(wq); //調用宏定義,靜態創建一個名爲wq的等待隊列

  32. static void key_interrupt(void) //中斷處理函數,註冊中斷時已註冊了中斷程序的入口地址
  33. {
  34.  key_value=s3c2410_gpio_getpin(key);
  35.  key_event=1; //喚醒標記置位,表示條件達到,可以喚醒進程繼續執行
  36.  wake_up_interruptible(&wq); //調用宏定義,喚醒標記置位後調用此函數,&wq是隊列入口地址
  37. }

  38. static int key_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
  39. {
  40. // wait_event_interruptible(wq,key_event); //若key_event爲0,從此處將進程放入wq等待隊列休眠,等待中斷;key_event==1時,此宏不執行操作
  41. //調用poll的時候來等待,這裏可以不用wait_event_interrupt()
  42.  key_value=s3c2410_gpio_getpin(key);
  43.  copy_to_user(buff,&key_value,sizeof(key_event)); //將&key_value地址的值從內核空間複製到用戶空間
  44.  key_event=0; //完成中斷操作,將喚醒標記清零,繼續休眠
  45.  return 0;
  46. }

  47. static unsigned int key_poll(struct file *filp,poll_table *wait)
  48. {
  49.  unsigned int mask=0; //用來記錄發生的事件,以unsigned int類型返回
  50.  poll_wait(filp,&wq,wait); //將當前進程添加到wq等待隊列中
  51.  if(key_event==1)mask|=POLLIN|POLLRDNORM; //中斷事件發生,這時有數據可讀,在mask中標記是可讀事件發生
  52.  return mask; //返回事件記錄,返回0則表示等待事件超時
  53. }

  54. //設置寄存器,申請中斷號等在open函數中完成
  55. static int key_open(struct inode *inode,struct file *filp)
  56. {
  57.  int ret;
  58.  s3c2410_gpio_cfgpin(key,key_cfg); //設置引腳功能
  59.  s3c2410_gpio_pullup(key,1); //第二個參數1爲禁止內部上拉
  60.  ret=request_irq(key_irq,(void *)key_interrupt,SA_INTERRUPT,DEVICE_NAME,NULL); //註冊中斷,中斷不共享時最後一個參數爲NULL
  61.  if(ret) {
  62.   printk("Could not register interrupt\n");
  63.   return ret;
  64.  }
  65.  set_irq_type(key_irq,IRQT_BOTHEDGE); //設置中斷方式爲雙邊觸發
  66.  return 0;
  67. }

  68. static int key_close(struct inode *inode,struct file *filp)
  69. {
  70.  free_irq(key_irq,NULL); //中斷無共享時第二個參數爲NULL
  71.  return 0;
  72. }

  73. static struct file_operations key_fops={
  74.  .owner=THIS_MODULE,
  75.  .open=key_open,
  76.  .release=key_close,
  77.  .read=key_read,
  78.  .poll=key_poll,
  79. };

  80. int key_init(void)
  81. {
  82.  int ret;
  83.  ret=alloc_chrdev_region(&dev,DEVICE_MINOR,1,DEVICE_NAME); //採用主設備號動態分配
  84.  if(ret<0){
  85.   printk("Register /dev/key failed!\n");
  86.   return ret;
  87.  }
  88.  else printk("Register /dev/key successfully!\n");
  89.  major=MAJOR(dev); //取得分配到的主設備號
  90.  p_cdev=cdev_alloc(); //申請一個字符設備結構並返回指向它的指針
  91.  cdev_init(p_cdev,&key_fops); //相當於p_cdev->ops=&key_fops
  92.  p_cdev->owner=THIS_MODULE; 
  93.  ret=cdev_add(p_cdev,dev,1); //向系統添加這個字符設備
  94.  if(ret<0){
  95.   printk("Add cdev failed!\n");
  96.   return ret;
  97.  }
  98.  devfs_mk_cdev(dev,S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP,DEVICE_NAME);
  99.  return 0;
  100. }

  101. void key_exit(void)
  102. {
  103.  unregister_chrdev_region(dev,1);
  104.  cdev_del(p_cdev); //刪除字符設備
  105.  devfs_remove(DEVICE_NAME);
  106.  printk("Device unregister!\n");
  107. }

  108. MODULE_LICENSE("GPL");
  109. MODULE_AUTHOR("HJW");
  110. module_init(key_init);
  111. module_exit(key_exit);

  112. ---------------------------------------------------------------------------------------------------

  113. 測試程序代碼:
  114. #include <stdio.h>
  115. #include <stdlib.h>
  116. #include <unistd.h>
  117. #include <sys/ioctl.h>
  118. #include <sys/types.h>
  119. #include <sys/stat.h>
  120. #include <fcntl.h> /*文件控制*/
  121. #include <sys/select.h>
  122. #include <sys/time.h> /*時間方面的函數*/
  123. #include <errno.h> /*有關錯誤方面的宏*/
  124. #include<sys/poll.h> //poll()
  125. #include<fcntl.h>
  126. #include<string.h> //memset()

  127. int main(void)
  128. {
  129.  int fd,key_value,ret;
  130.  struct pollfd event; //創建一個struct pollfd結構體變量,存放文件描述符、要等待發生的事件
  131.  fd=open("/dev/key",O_RDWR); 
  132.  if(fd<0){
  133.   perror("open /dev/key error!\n");
  134.   exit(1);
  135.  }
  136.  printf("open /dev/key sucessfully!\n");
  137.  while(1){ //poll結束後struct pollfd結構體變量的內容被全部清零,需要再次設置
  138.   memset(&event,0,sizeof(event)); //memst函數對對象的內容設置爲同一值
  139.   event.fd=fd; //存放打開的文件描述符
  140.   event.events=POLLIN; //存放要等待發生的事件
  141.   ret=poll((struct pollfd *)&event,1,5000); //監測event,一個對象,等待5000毫秒後超時,-1爲無限等待

  142. //判斷poll的返回值,負數是出錯,0是設定的時間超時,整數表示等待的時間發生
  143.   if(ret<0){
  144.    printf("poll error!\n");
  145.    exit(1);
  146.   }
  147.   if(ret==0){
  148.    printf("Time out!\n");
  149.    continue;
  150.   }
  151.   if(event.revents&POLLERR){ //revents是由內核記錄的實際發生的事件,events是進程等待的事件
  152.    printf("Device error!\n");
  153.    exit(1);
  154.   }
  155.   if(event.revents&POLLIN){
  156.    read(fd,&key_value,sizeof(key_value));
  157.    printf("Key value is '%d'\n",key_value);
  158.   }
  159.  }
  160.  close(fd);
  161.  return 0;
  162. }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章