poll函數用於監測多個等待事件,若事件未發生,進程睡眠,放棄CPU控制權,若監測的任何一個事件發生,poll將喚醒睡眠的進程,並判斷是什麼等待事件發生,執行相應的操作。poll函數退出後,struct pollfd變量的所有值被清零,需要重新設置。 示例是使用poll函數來監測按鍵的輸入 ---------------------------------------------------------------------------------------------------------- 驅動代碼: #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/irq.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> #include <linux/cdev.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/poll.h> #include <asm/uaccess.h> #include <asm/ioctl.h> #include <asm/arch/regs-irq.h> #include <asm/io.h> #define key S3C2410_GPF0 #define key_irq IRQ_EINT0 //IRQ_EINT0是中斷號 #define key_cfg S3C2410_GPF0_EINT0 //設置為外部中斷功能 #define DEVICE_NAME "key" //注意加上雙引號 #define DEVICE_MAJOR major #define DEVICE_MINOR 0 static dev_t dev; //dev_t類型用於存放主設備號和次設備號 static int major; struct cdev *p_cdev; //聲明一個指向字符設備結構的指針 static int key_event=0; //喚醒中斷的條件標記,1時滿足喚醒條件,靜態全局變量 static int key_value=1; //按鍵鍵值 static DECLARE_WAIT_QUEUE_HEAD(wq); //調用宏定義,靜態創建一個名為wq的等待隊列 static void key_interrupt(void) //中斷處理函數,注冊中斷時已注冊了中斷程序的入口地址 { key_value=s3c2410_gpio_getpin(key); key_event=1; //喚醒標記置位,表示條件達到,可以喚醒進程繼續執行 wake_up_interruptible(&wq); //調用宏定義,喚醒標記置位後調用此函數,&wq是隊列入口地址 } static int key_read(struct file *filp,char __user *buff,size_t count,loff_t *offp) { //wait_event_interruptible(wq,key_event); //若key_event為0,從此處將進程放入wq等待隊列休眠,等待中斷;key_event==1時,此宏不執行操作 //調用poll的時候來等待,這裡可以不用wait_event_interrupt() key_value=s3c2410_gpio_getpin(key); copy_to_user(buff,&key_value,sizeof(key_event)); //將&key_value地址的值從內核空間復制到用戶空間 key_event=0; //完成中斷操作,將喚醒標記清零,繼續休眠 return 0; } static unsigned int key_poll(struct file *filp,poll_table *wait) { unsigned int mask=0; //用來記錄發生的事件,以unsigned int類型返回 poll_wait(filp,&wq,wait); //將當前進程添加到wq等待隊列中 if(key_event==1)mask|=POLLIN|POLLRDNORM; //中斷事件發生,這時有數據可讀,在mask中標記是可讀事件發生 return mask; //返回事件記錄,返回0則表示等待事件超時 } //設置寄存器,申請中斷號等在open函數中完成 static int key_open(struct inode *inode,struct file *filp) { int ret; s3c2410_gpio_cfgpin(key,key_cfg); //設置引腳功能 s3c2410_gpio_pullup(key,1); //第二個參數1為禁止內部上拉 ret=request_irq(key_irq,(void *)key_interrupt,SA_INTERRUPT,DEVICE_NAME,NULL); //注冊中斷,中斷不共享時最後一個參數為NULL if(ret) { printk("Could not register interrupt/n"); return ret; } set_irq_type(key_irq,IRQT_BOTHEDGE); //設置中斷方式為雙邊觸發 return 0; } static int key_close(struct inode *inode,struct file *filp) { free_irq(key_irq,NULL); //中斷無共享時第二個參數為NULL return 0; } static struct file_operations key_fops={ .owner=THIS_MODULE, .open=key_open, .release=key_close, .read=key_read, .poll=key_poll, }; int key_init(void) { int ret; ret=alloc_chrdev_region(&dev,DEVICE_MINOR,1,DEVICE_NAME); //采用主設備號動態分配 if(ret<0){ printk("Register /dev/key failed!/n"); return ret; } else printk("Register /dev/key successfully!/n"); major=MAJOR(dev); //取得分配到的主設備號 p_cdev=cdev_alloc(); //申請一個字符設備結構並返回指向它的指針 cdev_init(p_cdev,&key_fops); //相當於p_cdev->ops=&key_fops p_cdev->owner=THIS_MODULE; ret=cdev_add(p_cdev,dev,1); //向系統添加這個字符設備 if(ret<0){ printk("Add cdev failed!/n"); return ret; } devfs_mk_cdev(dev,S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP,DEVICE_NAME); return 0; } void key_exit(void) { unregister_chrdev_region(dev,1); cdev_del(p_cdev); //刪除字符設備 devfs_remove(DEVICE_NAME); printk("Device unregister!/n"); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("HJW"); module_init(key_init); module_exit(key_exit); --------------------------------------------------------------------------------------------------- 測試程序代碼: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /*文件控制*/ #include <sys/select.h> #include <sys/time.h> /*時間方面的函數*/ #include <errno.h> /*有關錯誤方面的宏*/ #include<sys/poll.h> //poll() #include<fcntl.h> #include<string.h> //memset() int main(void) { int fd,key_value,ret; struct pollfd event; //創建一個struct pollfd結構體變量,存放文件描述符、要等待發生的事件 fd=open("/dev/key",O_RDWR); if(fd<0){ perror("open /dev/key error!/n"); exit(1); } printf("open /dev/key sucessfully!/n"); while(1){ //poll結束後struct pollfd結構體變量的內容被全部清零,需要再次設置 memset(&event,0,sizeof(event)); //memst函數對對象的內容設置為同一值 event.fd=fd; //存放打開的文件描述符 event.events=POLLIN; //存放要等待發生的事件 ret=poll((struct pollfd *)&event,1,5000); //監測event,一個對象,等待5000毫秒後超時,-1為無限等待 //判斷poll的返回值,負數是出錯,0是設定的時間超時,整數表示等待的時間發生 if(ret<0){ printf("poll error!/n"); exit(1); } if(ret==0){ printf("Time out!/n"); continue; } if(event.revents&POLLERR){ //revents是由內核記錄的實際發生的事件,events是進程等待的事件 printf("Device error!/n"); exit(1); } if(event.revents&POLLIN){ read(fd,&key_value,sizeof(key_value)); printf("Key value is '%d'/n",key_value); } } close(fd); return 0; } 將上面的測試程序命名為polltest.c,進行編譯; 將該源文件與 Android.mk 一塊放於/android/package/apps/poll/下面,進行make LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := polltest #LOCAL_MODULE := librdstest LOCAL_SRC_FILES := polltest.c LOCAL_LDLIBS := -llog -lm -lc LOCAL_SHARED_LIBRARIES := liblog libcutils LOCAL_PRELINK_MODULE := false LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \ ../includewww.2cto.com #include $(BUILD_SHARED_LIBRARY) //編譯可執行程序 include $(BUILD_EXECUTABLE) 生成polltest 然後將其放於目標設備上,運行: 在adb push polltest /polltest chmod 777 /polltest ./polltest 即可以看見結果 。