<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

          作者: 時間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
          文件操作支持的集合如下:
          /*添加該模塊的基本文件操作支持*/
          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。
          二、設(shè)備的堵塞讀寫方式實現(xiàn),通常采用等待隊列。
          設(shè)備的堵塞讀寫方式,默認情況下的讀寫操作都是堵塞型的,具體的就是如果需要讀數(shù)據(jù),當(dāng)設(shè)備中沒有數(shù)據(jù)可讀的時候應(yīng)該等待設(shè)備中有設(shè)備再讀,當(dāng)往設(shè)備中寫數(shù)據(jù)時,如果上一次的數(shù)據(jù)還沒有被讀完成,則不應(yīng)該寫入數(shù)據(jù),就會導(dǎo)致進程的堵塞,等待數(shù)據(jù)可讀寫。但是在應(yīng)用程序中也可以采用非堵塞型的方式進行讀寫。只要在打開文件的時候添加一個O_NONBLOCK,這樣在不能讀寫的時候就會直接返回,而不會等待。
          因此我們在實際設(shè)計驅(qū)動設(shè)備的同時需要考慮讀寫操作的堵塞方式。堵塞方式的設(shè)計主要是通過等待隊列實現(xiàn),通常是將等待隊列(實質(zhì)就是一個鏈表)的頭作為設(shè)備數(shù)據(jù)結(jié)構(gòu)的一部分。在設(shè)備初始化過程中初始化等待隊列的頭。最后在設(shè)備讀寫操作的實現(xiàn)添加相應(yīng)的等待隊列節(jié)點,并進行相應(yīng)的控制。
          等待隊列的操作基本如下:
          1、等待隊列的頭定義并初始化的過程如下:
          方法一:
          struct wait_queue_head_t mywaitqueue;
          init_waitqueue_head(&mywaitqueue);
          方法二:
          DECLARE_WAIT_QUEUE_HEAD(mywaitqueue);
          以上的兩種都能實現(xiàn)定義和初始化等待隊列頭。
          2、創(chuàng)建、移除一個等待隊列的節(jié)點,并添加、移除相應(yīng)的隊列。
          定義一個等待隊列的節(jié)點:DECLARE_WAITQUEUE(wait,tsk)
          其中tsk表示一個進程,可以采用current當(dāng)前的進程。
          添加到定義好的等待隊列頭中。
          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);當(dāng)condition為真時,等待隊列頭queue對應(yīng)的隊列被喚醒,否則繼續(xù)堵塞。這種情況下不能被信號打斷。
          wait_event_interruptible(queue,condition);當(dāng)condition為真時,等待隊列頭queue對應(yīng)的隊列被喚醒,否則繼續(xù)堵塞。這種情況下能被信號打斷。
          4、喚醒等待隊列
          wait_up(wait_queue_head_t *q),喚醒該等待隊列頭對應(yīng)的所有等待。
          wait_up_interruptible(wait_queue_head_t *q)喚醒處于TASK_INTERRUPTIBLE的等待進程。
          應(yīng)該成對的使用。即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 (;;) {
          /*此處就相當(dāng)于add_wait_queue()操作,具體參看代碼如下所示*/
          prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);
          if (condition)
          break;
          if (!signal_pending(current)) {
          /*此處是調(diào)度,丟失CPU,因此需要wake_up函數(shù)喚醒當(dāng)前的進程
          根據(jù)定義可知,如果條件不滿足,進程就失去CPU,能夠跳出for循環(huán)的出口只有
          1、當(dāng)條件滿足時2、當(dāng)signal_pending(current)=1時。
          1、就是滿足條件,也就是說wake_up函數(shù)只是退出了schedule函數(shù),
          而真正退出函數(shù)還需要滿足條件
          2、說明進程可以被信號喚醒。也就是信號可能導(dǎo)致沒有滿足條件時就喚醒當(dāng)前的進程。
          這也是后面的代碼采用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ū)動程序設(shè)計中的堵塞讀寫操作,并不需要手動的添加節(jié)點到隊列中,直接調(diào)用即可實現(xiàn),具體的實現(xiàn)方法如下:
          1、在設(shè)備結(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è)備的數(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)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();