arm驅(qū)動Linux內(nèi)核開發(fā)之阻塞非阻塞IO輪詢操作
一、概念:Poll是非阻塞IO----輪詢操作
非阻塞 I/O 的應用程序常常使用 poll, select, 和 epoll 系統(tǒng)調(diào)用. poll, select 和 epoll 本質(zhì)上有相同的功能: 每個允許一個進程來決定它是否可讀或者寫一個或多個文件而不阻塞.
Tip:select()和poll(),epoll查詢是否可對設備進行無阻塞的訪問,這幾個系統(tǒng)調(diào)用最終又會引發(fā)設備驅(qū)動中的poll()函數(shù)被執(zhí)行
PS:看到這感覺暈了,暫且不理會
二、使用場景:
它們常常用在必須使用多輸入輸出流的應用程序(如調(diào)用read,write字符設備驅(qū)動文件/dev/****)。因為這些調(diào)用也可阻塞進程直到任何一個給定集合的文件描述符可用來讀或?qū)?
三、相關函數(shù)
1、內(nèi)核函數(shù)
內(nèi)核驅(qū)動函數(shù)一)a)poll()函數(shù)原型:
unsigned int (*poll) (struct file *filp, poll_table *wait);
作用:調(diào)用poll_wait(),將可能引起設備文件狀態(tài)變化的等待隊列頭添加到poll_table.
返回值:返回是否能對設備進行無阻塞讀寫訪問的掩碼
放回值mask常量及函數(shù)
常量 說明
POLLIN 普通或優(yōu)先級帶數(shù)據(jù)可讀
POLLRDNORM 普通數(shù)據(jù)可讀
POLLRDBAND 優(yōu)先級帶數(shù)據(jù)可讀
POLLPRI 高優(yōu)先級數(shù)據(jù)可讀
POLLOUT 普通數(shù)據(jù)可寫
POLLWRNORM 普通數(shù)據(jù)可寫
POLLWRBAND 優(yōu)先級帶數(shù)據(jù)可寫
POLLERR 發(fā)生錯誤
POLLHUP 發(fā)生掛起
POLLNVAL 描述字不是一個打開的文件
內(nèi)核驅(qū)動函數(shù)二)b)poll_wait()函數(shù)原型:
void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);
作用:將可能引起設備文件狀態(tài)變化的等待隊列頭添加到poll_table
2、應用程序poll函數(shù)
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
a)參數(shù):
fds 指向 struct pollfd 數(shù)組
nfds 指定 pollfd 數(shù)組元素的個數(shù),也就是要監(jiān)測幾個 pollfd
timeout 時間參數(shù),單位ms,1000ms=1s
Tip:fds可以是很多個文件(如網(wǎng)卡,按鍵),poll可以論尋fds[n]
b)結(jié)構(gòu)體pollfd
struct pollfd {
int fd;
short events;
short revents;
};
3、總結(jié):從應用程序的調(diào)用來看,并不需要理會內(nèi)核函數(shù)中的參數(shù)poll_table *wait是什么,只需要調(diào)用poll_wait()
四、使用模板
模板一)a)內(nèi)核程序模板
static DECLARE_WAIT_QUEUE_HEAD(waitq);//定義結(jié)構(gòu)體名稱為waitq
poll(struct file *file, poll_table *wait){//返回mask
unsigned int mask = 0;
poll_wait(file, &waitq, wait);
if(...)//可讀
{
mask |= POLLIN | POLLRDNORM; //標識數(shù)據(jù)可獲得
}
if(...)//可寫
{
mask |= POLLOUT | POLLRDNORM; //標識數(shù)據(jù)可寫入
}
return mask;
}
模板二)b)測試程序模板
struct pollfd fds[n];
fds[0].fd = fd;
fds[0].events = POLLIN;
poll(fds, n, 5000);
c)再次理解下面幾句
fds 指向 struct pollfd 數(shù)組
nfds 指定 pollfd 數(shù)組元素的個數(shù),也就是要監(jiān)測幾個 pollfd
timeout 時間參數(shù),單位ms,1000ms=1s
Tip:fds可以是很多個文件(如網(wǎng)卡,按鍵),poll可以論尋fds[n]
實例一)五、案例jz2440中斷非阻塞驅(qū)動實例
1、 非阻塞內(nèi)核按鍵驅(qū)動。
//“irq_drv”,"irq_","irq"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//定義結(jié)構(gòu)體名稱為button_waitq
static struct class *irq_class;
static struct class_device *irq_class_dev;
static int ev_press = 0;
static unsigned char key_val;
struct pin_desc{
unsigned int pin;
unsigned int key_val;
};
struct pin_desc pins_desc[3] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
};
static irqreturn_t irq_handle(int irq, void *dev__id){
//printk("irq = %dn", irq);
int pinval;
struct pin_desc *pindesc = (struct pin_desc *)dev__id;
pinval = s3c2410_gpio_getpin(pindesc->pin);
if(!pinval){//按下
key_val = pindesc->key_val;
}else{//松開
key_val = 0x80 | pindesc->key_val;
}
ev_press = 1;
wake_up_interruptible(&button_waitq);
return IRQ_RETVAL(IRQ_HANDLED);//warn:返回IRQ_HANDLED
}
static unsigned irq_drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait); // 不會立即休眠
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static int irq_drv_open(struct inode *inode, struct file *file)
{
printk("irq_dev readn");
// request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char * devname, void * dev_id); dev_id隨意
request_irq(IRQ_EINT0, irq_handle, IRQ_TYPE_EDGE_BOTH, "s2", &pins_desc[0]);
request_irq(IRQ_EINT2, irq_handle, IRQ_TYPE_EDGE_BOTH, "s3", &pins_desc[1]);
request_irq(IRQ_EINT11, irq_handle, IRQ_TYPE_EDGE_BOTH, "s4", &pins_desc[2]);
return 0;
}
static ssize_t irq_drv_read (struct file *file, char __user *buf, size_t count, loff_t *ppos){
if(count != 1)return -EINVAL;
wait_event_interruptible(button_waitq, ev_press);//ev_press標志(if!(ev_press)),那么一直休眠
copy_to_user(buf, &key_val, 1);//一個 char 0xff
ev_press = 0;
return 1;//warn :return the size of val
}
static ssize_t irq_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk("irq_dev writen");
return 0;
}
static ssize_t irq_drv_release(struct inode *inode, struct file *file){
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
return 0;
}
static struct file_operations irq_drv_fops = {
.owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創(chuàng)建的__this_module變量 */
.open = irq_drv_open,
.write = irq_drv_write,
.read = irq_drv_read,
.release = irq_drv_release,
.poll = irq_drv_poll,
};
int major;
static int irq_drv_init(void)
{
major = register_chrdev(0, "irq_drv", &irq_drv_fops); // 注冊, 告訴內(nèi)核
if (major < 0) {
printk(" cant register major numbern");
return major;
}
irq_class = class_create(THIS_MODULE, "irq_drv");
if (IS_ERR(irq_class))
return PTR_ERR(irq_class);
irq_class_dev = class_device_create(irq_class, NULL, MKDEV(major, 0), NULL, "irq"); /* /dev/xyz */
if (IS_ERR(irq_class_dev))
return PTR_ERR(irq_class_dev);
return 0;
}
static void irq_drv_exit(void)
{
unregister_chrdev(major, "irq_drv"); // 卸載
class_device_unregister(irq_class_dev);
class_destroy(irq_class);
}
module_init(irq_drv_init);
module_exit(irq_drv_exit);
MODULE_LICENSE("GPL");
2、測試應用程序
#include
#include
#include
#include
#include
#include
/* irq
*/
int main(int argc, char **argv)
{
int fd;
unsigned char key_val;
int cnt = 0;
int ret;
struct pollfd fds[1];
fd = open("/dev/irq", O_RDWR);
if (fd < 0)
{
printf("cant open!n");
exit(1);
}
fds[0].fd = fd;
fds[0].events = POLLIN;
while (1)
{
ret = poll(fds, 1, 5000);
if(ret == 0){
printf("time out!n");
}else{
read(fd, &key_val, 1);
printf("key_Vals = 0x%xn", key_val);
}
}
return 0;
}
Makefile
#myirq.bin
objs := $(patsubst %c, %o, $(shell ls *.c))
myarmgcc := /workspacearm/armlinuxgcc2626/bin/arm-linux-gcc
myirq.bin:$(objs)
$(myarmgcc) -o $@ $^
cp *.bin /opt/fsmini/
%.o:%.c
$(myarmgcc) -c -o $@ $<
clean:
rm -f *.bin *.o
Curtiss Falcon
評論