在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > Linux驅(qū)動總結(jié)3

            Linux驅(qū)動總結(jié)3

            作者: 時間:2016-12-01 來源:網(wǎng)絡 收藏
            文件操作支持的集合如下:
            /*添加該模塊的基本文件操作支持*/
            static const struct file_operations mem_fops =
            {
            /*結(jié)尾不是分號,注意其中的差別*/
            .owner = THIS_MODULE,
            .llseek = mem_llseek,
            .read = mem_read,
            .write = mem_write,
            .open = mem_open,
            .release = mem_release,
            /*添加新的操作支持*/
            .unlocked_ioctl = mem_ioctl,
            };
            需要注意不是ioctl,而是unlocked_ioctl。
            二、設備的堵塞讀寫方式實現(xiàn),通常采用等待隊列。
            設備的堵塞讀寫方式,默認情況下的讀寫操作都是堵塞型的,具體的就是如果需要讀數(shù)據(jù),當設備中沒有數(shù)據(jù)可讀的時候應該等待設備中有設備再讀,當往設備中寫數(shù)據(jù)時,如果上一次的數(shù)據(jù)還沒有被讀完成,則不應該寫入數(shù)據(jù),就會導致進程的堵塞,等待數(shù)據(jù)可讀寫。但是在應用程序中也可以采用非堵塞型的方式進行讀寫。只要在打開文件的時候添加一個O_NONBLOCK,這樣在不能讀寫的時候就會直接返回,而不會等待。
            因此我們在實際設計驅(qū)動設備的同時需要考慮讀寫操作的堵塞方式。堵塞方式的設計主要是通過等待隊列實現(xiàn),通常是將等待隊列(實質(zhì)就是一個鏈表)的頭作為設備數(shù)據(jù)結(jié)構(gòu)的一部分。在設備初始化過程中初始化等待隊列的頭。最后在設備讀寫操作的實現(xiàn)添加相應的等待隊列節(jié)點,并進行相應的控制。
            等待隊列的操作基本如下:
            1、等待隊列的頭定義并初始化的過程如下:
            方法一:
            struct wait_queue_head_t mywaitqueue;
            init_waitqueue_head(&mywaitqueue);
            方法二:
            DECLARE_WAIT_QUEUE_HEAD(mywaitqueue);
            以上的兩種都能實現(xiàn)定義和初始化等待隊列頭。
            2、創(chuàng)建、移除一個等待隊列的節(jié)點,并添加、移除相應的隊列。
            定義一個等待隊列的節(jié)點:DECLARE_WAITQUEUE(wait,tsk)
            其中tsk表示一個進程,可以采用current當前的進程。
            添加到定義好的等待隊列頭中。
            add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);
            即:add_wait_queue(&mywaitqueue,&wait);
            移除等待節(jié)點
            remove_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);
            即:remove_wait_queue(&mywaitqueue,&wait);
            3、等待事件
            wait_event(queue,condition);當condition為真時,等待隊列頭queue對應的隊列被喚醒,否則繼續(xù)堵塞。這種情況下不能被信號打斷。
            wait_event_interruptible(queue,condition);當condition為真時,等待隊列頭queue對應的隊列被喚醒,否則繼續(xù)堵塞。這種情況下能被信號打斷。
            4、喚醒等待隊列
            wait_up(wait_queue_head_t *q),喚醒該等待隊列頭對應的所有等待。
            wait_up_interruptible(wait_queue_head_t *q)喚醒處于TASK_INTERRUPTIBLE的等待進程。
            應該成對的使用。即wait_event于wait_up,而wait_event_interruptible與wait_up_interruptible。
            wait_event和wait_event_interruptible的實現(xiàn)都是采用宏的方式,都是一個重新調(diào)度的過程,如下所示:
            #define wait_event_interruptible(wq, condition)
            ({
            int __ret = 0;
            if (!(condition))
            __wait_event_interruptible(wq, condition, __ret);
            __ret;
            })
            #define __wait_event_interruptible(wq, condition, ret)
            do {
            /*此處存在一個聲明等待隊列的語句,因此不需要再重新定義一個等待隊列節(jié)點*/
            DEFINE_WAIT(__wait);
            for (;;) {
            /*此處就相當于add_wait_queue()操作,具體參看代碼如下所示*/
            prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);
            if (condition)
            break;
            if (!signal_pending(current)) {
            /*此處是調(diào)度,丟失CPU,因此需要wake_up函數(shù)喚醒當前的進程
            根據(jù)定義可知,如果條件不滿足,進程就失去CPU,能夠跳出for循環(huán)的出口只有
            1、當條件滿足時2、當signal_pending(current)=1時。
            1、就是滿足條件,也就是說wake_up函數(shù)只是退出了schedule函數(shù),
            而真正退出函數(shù)還需要滿足條件
            2、說明進程可以被信號喚醒。也就是信號可能導致沒有滿足條件時就喚醒當前的進程。
            這也是后面的代碼采用while判斷的原因.防止被信號喚醒。
            */
            schedule();
            continue;
            }
            ret = -ERESTARTSYS;
            break;
            }
            finish_wait(&wq, &__wait);
            } while (0)
            #define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
            #define DEFINE_WAIT_FUNC(name, function)
            wait_queue_t name = {
            .private = current,
            .func = function,
            .task_list = LIST_HEAD_INIT((name).task_list),
            }
            void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
            {
            unsigned long flags;
            wait->flags &= ~WQ_FLAG_EXCLUSIVE;
            spin_lock_irqsave(&q->lock, flags);
            if (list_empty(&wait->task_list))
            /*添加節(jié)點到等待隊列*/
            __add_wait_queue(q, wait);
            set_current_state(state);
            spin_unlock_irqrestore(&q->lock, flags);
            }
            喚醒的操作也是類似的。
            #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
            void __wake_up(wait_queue_head_t *q, unsigned int mode,
            int nr_exclusive, void *key)
            {
            unsigned long flags;
            spin_lock_irqsave(&q->lock, flags);
            __wake_up_common(q, mode, nr_exclusive, 0, key);
            spin_unlock_irqrestore(&q->lock, flags);
            }
            static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
            int nr_exclusive, int wake_flags, void *key)
            {
            wait_queue_t *curr, *next;
            list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
            unsigned flags = curr->flags;
            if (curr->func(curr, mode, wake_flags, key) &&
            (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
            break;
            }
            }
            等待隊列通常用在驅(qū)動程序設計中的堵塞讀寫操作,并不需要手動的添加節(jié)點到隊列中,直接調(diào)用即可實現(xiàn),具體的實現(xiàn)方法如下:
            1、在設備結(jié)構(gòu)體中添加等待隊列頭,由于讀寫都需要堵塞,所以添加兩個隊列頭,分別用來堵塞寫操作,寫操作。
            #include
            struct mem_dev
            {
            char *data;
            unsigned long size;
            /*添加一個并行機制*/
            spinlock_t lock;
            /*添加一個等待隊列t頭*/
            wait_queue_head_t rdqueue;
            wait_queue_head_t wrqueue;
            };
            2、然后在模塊初始化中初始化隊列頭:
            /*初始化函數(shù)*/
            static int memdev_init(void)
            {
            ....
            for(i = 0; i < MEMDEV_NR_DEVS; i)
            {
            mem_devp[i].size = MEMDEV_SIZE;
            /*對設備的數(shù)據(jù)空間分配空間*/
            mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
            /*問題,沒有進行錯誤的控制*/
            memset(mem_devp[i].data,0,MEMDEV_SIZE);
            /*初始化定義的互信息量*/
            //初始化定義的自旋鎖ua
            spin_lock_init(&(mem_devp[i].lock));
            /*初始化兩個等待隊列頭,需要注意必須用括號包含起來,使得優(yōu)先級正確*/
            init_waitqueue_head(&(mem_devp[i].rdqueue));
            init_waitqueue_head(&(mem_devp[i].wrqueue));
            }

            關(guān)鍵詞: Linux驅(qū)動總

            評論


            技術(shù)專區(qū)

            關(guān)閉