[linux-kernel] 實現支持poll的驅動設備

ldd3上已經講了如何開發linux下的驅動程序,怎麼讓該設備支持poll(和epoll),但是不夠詳細,這裏給個例子。假設實現一個misc設備,爲了實現poll,當然要有個wait_queue,注意,是dev帶wait_queue,我一疏忽把wait_queue帶到file上去了,調了半天才發現這個低級錯誤。


struct sample_dev

{

    struct miscdevice       misc;

    wait_queue_head_t    wait;

};


static struct sample_dev    s_dev;


s_dev這個設備現在既可以當miscdevice用,同時又有了wait_queue


struct file_operations sample_fops =

{

    .owner       = THIS_MODULE,

    .read         = sample_read,

    .write        = sample_write,

    .poll           = sample_poll,

};


static int __init init_sample(void)

{

    s_dev.misc.minor = MISC_DYNAMIC_MINOR;

    s_dev.misc.name = "poll_device_sample";

    s_dev.misc.fops  = &sample_fops;

    init_waitqueue_head(&s_dev.wait);

    return misc_register(&s_dev.misc);

}


static void __exit exit_sample(void)

{

    misc_unregister(&s_dev.misc);

}


這是設備的註冊和註銷。下面看sample_poll的做法,和ldd3上說的一樣:


unsigned int sample_poll(struct file* file, poll_table* wait)

{

    unsigned int    mask = 0;


    poll_wait(file, &s_dev.wait, wait);


    /* if have something to read (代碼省略)*/

        mask |= POLLIN;

    /* if have something to write (代碼省略)*/

        mask |= POLLOUT;

    /* if some error occur (代碼省略)*/

        mask |= POLLERR;


    return mask;

}


poll_wait是linux內核提供的,標準做法,所以最好這麼用。在poll_wait裏,current進程掛在了s_dev的wait_queue裏,只有兩種情況讓他醒來:一個是poll系統調用超時(poll_table負責),另一個是讀寫喚醒他(後面的代碼)。


sszie_t    sample_read(struct file* file, char __user* buff, loff_t* pos)

{

    /* do what you want to read(代碼省略)*/

    wake_up_interruptible(&s_dev.wait); 

}


由於讀走了一些數據,緩衝區(代碼沒有詳細寫)有位置了,可以往裏面寫了,上面標紅的行便喚醒隨眠的進程,他(進程)醒來後就到了poll_wait語句的後面,開始查看緩衝區並置mask,最後返回。sample_write也是同樣的實現方式。


以上代碼只是例子,並不完整,但原理已經充分。這樣實現的設備已經可以支持poll和epoll調用,當然,epoll的原理更爲複雜。




http://www.360doc.com/content/11/1214/23/1317564_172324612.shtml

發佈了25 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章