乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘

       rookie 2012-04-10
      Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(一)

      “小王,醒醒,開(kāi)始上課了,今天咱們開(kāi)始講中斷,這可是高級(jí)東西,錯(cuò)過(guò)不補(bǔ)哈”我使勁推著睡夢(mèng)中的小王。

      “嗯?感情好啊,快點(diǎn),快點(diǎn)”小王一聽(tīng)有新東西講,像打了雞血似的興奮,連我都懷疑起她是不是性格中喜新厭舊。

      不管那么多了,我講我的,她厭她的…

        啥叫中斷?就是指cpu在執(zhí)行過(guò)程中,出現(xiàn)了某些突發(fā)事件時(shí)CPU必須暫停執(zhí)行當(dāng)前的程序,轉(zhuǎn)去處理突發(fā)事件,處理完畢后CPU有返回原程序被中斷的位置并繼續(xù)執(zhí)行。

        中斷的分法不懂,分類(lèi)就不同,向什么內(nèi)外部中斷,可/不可屏蔽中斷…等等亂七八糟一大堆,我這里要說(shuō)明的一點(diǎn)是按照中斷入口跳轉(zhuǎn)方法的不同,可分為向量中 斷和非向量中斷。采用向量中斷的CPU通常為不同的中斷分配不同的中斷號(hào),當(dāng)檢測(cè)到某中斷號(hào)的中斷到來(lái)后,就自動(dòng)跳轉(zhuǎn)到與該中斷號(hào)對(duì)應(yīng)的地址執(zhí)行。不同的 中斷號(hào)有不同的中斷地址(即入口)。而非向量中斷的多個(gè)中斷共享一個(gè)入口地址。進(jìn)入后根據(jù)軟件判斷中斷標(biāo)志來(lái)識(shí)別具體是哪個(gè)中斷。也就是說(shuō),向量中斷是由 硬件提供中斷服務(wù)程序入口地址,非向量中斷由軟件提供中斷服務(wù)程序入口地址。

        我們?cè)诤筮厱?huì)說(shuō)到一個(gè)時(shí)鐘定時(shí)器,它也是通過(guò)中斷來(lái)實(shí)現(xiàn)的。它的原理很簡(jiǎn)單,嵌入式微處理器它接入一個(gè)時(shí)鐘輸入,當(dāng)時(shí)鐘脈沖到來(lái)時(shí),就將目前的計(jì)數(shù)器值加1并和預(yù)先設(shè)置的計(jì)數(shù)值比較,若相等,證明計(jì)數(shù)周期滿,產(chǎn)生定時(shí)器中斷并復(fù)位目前計(jì)數(shù)器值。

                    123

       

       

       

       

       

       

      Linux中斷處理架構(gòu)

      設(shè) 備的中斷會(huì)打斷內(nèi)核中進(jìn)程的正常調(diào)度和運(yùn)行,會(huì)影響系統(tǒng)的性能。為了在中斷執(zhí)行時(shí)間盡可能短和中斷處理需完成大量工作之間找到一個(gè)平衡點(diǎn),Linux將中 斷處理程序分解成兩個(gè)半部:頂半部和底半部。其中頂半部盡可能完成盡可能少的比較緊急的功能。而底半部幾乎做了中斷處理程序所有的事情,而且可以被新的中 斷打斷。

      在linux設(shè)備驅(qū)動(dòng)中,提供了一系列函數(shù)來(lái)幫助設(shè)備實(shí)現(xiàn)中斷的相關(guān)操作:

      1)設(shè)備申請(qǐng)中斷

      int request_irq(unsigned int irq,  //irq是要申請(qǐng)的中斷號(hào)

                          void (*handler)(int irq, void *dev_id, struct pt_regs * *regs),//回調(diào)函數(shù),中斷發(fā)生時(shí),系統(tǒng)會(huì)調(diào)用該函數(shù),

                          unsigned long irqflags,

                          const char *devname,

                          void *dev_id);

      其中irqflags是中斷處理的屬性,若設(shè)置為SA_INTERRUPT,則表示中斷處理程序是快速處理程序,它被調(diào)用時(shí)屏蔽所有中斷。若設(shè)置為SA_SHIRQ,則表示多個(gè)設(shè)備共享中斷,dev_id在中斷共享時(shí)會(huì)用到,一般設(shè)置為這個(gè)設(shè)備的設(shè)備結(jié)構(gòu)體或者NULL.

      該函數(shù)返回0表示成功,返回-INVAL表示中斷號(hào)無(wú)效或處理函數(shù)指針為NULL,返回EBUSY表示中斷已經(jīng)被占用且不能共享。

      2)釋放中斷

      free_irq(unsigned int irq, void *dev_id);

      3)使能和屏蔽中斷

      void disable_irq(int irq);   //這個(gè)會(huì)立即返回

      void disable_irq_nosync(int irq);//等待目前的中斷處理完成再返回。

      void enable_irq(int irq);

      上述三個(gè)函數(shù)作用于可編程中斷處理器,因此對(duì)系統(tǒng)內(nèi)所有的CPU都生效。

      void local_irq_save(unsigned long flags);//會(huì)將目前的中斷狀態(tài)保留在flags中

      void local_irq_disable(void);//直接中斷

      這兩個(gè)將屏蔽本CPU內(nèi)的所有中斷。對(duì)應(yīng)的上邊兩個(gè)中斷的方法如下

      void local_irq_restore(unsigned long flags);

      void local_irq_enable(void);

       

      我們兩邊說(shuō)了Linux系統(tǒng)中中斷是分為頂半部和底半部的,那么在系統(tǒng)實(shí)現(xiàn)方面是具體怎樣實(shí)現(xiàn)的呢,這主要有tasklet,工作隊(duì)列,軟中斷:

      1)tasklet:使用比較簡(jiǎn)單,如下:

      void my_tasklet_function(unsigned long); //定義一個(gè)處理函數(shù)

      DECLARE_TASKLET(my_tasklet, my_tasklet_function, data); //定義了一個(gè)名叫my_tasklet的tasklet并將其與處理函數(shù)綁定,而傳入?yún)?shù)為data

      在需要調(diào)度tasklet的時(shí)候引用一個(gè)tasklet_schedule()函數(shù)就能使系統(tǒng)在適當(dāng)?shù)臅r(shí)候進(jìn)行調(diào)度運(yùn)行:tasklet_schedule(&my_tasklet);

      2)工作隊(duì)列:使用方法和tasklet相似,如下:

      struct work_struct my_wq; //定義一個(gè)工作隊(duì)列

      void my_wq_func(unsigned long);  //定義一個(gè)處理函數(shù)

      通過(guò)INIT_WORK()可以初始化這個(gè)工作隊(duì)列并將工作隊(duì)列與處理函數(shù)綁定,如下:

      INIT_WORK(&my_wq, (void (*)(void *))my_wq_func, NULL);  //初始化工作隊(duì)列并將其與處理函數(shù)綁定

      同樣,使用schedule_work(&my_irq);來(lái)在系統(tǒng)在適當(dāng)?shù)臅r(shí)候需要調(diào)度時(shí)使用運(yùn)行。

      3)軟中斷:使用軟件方式模擬硬件中斷的概念,實(shí)現(xiàn)宏觀上的異步執(zhí)行效果,tasklet也是基于軟中斷實(shí)現(xiàn)的。

      在Linux內(nèi)核中,用softirq_action結(jié)構(gòu)體表征一個(gè)軟中斷,這個(gè)結(jié)構(gòu)體中包含軟中斷處理函數(shù)指針和傳遞給函數(shù)的參數(shù),使用open_softirq()可以注冊(cè)軟中斷對(duì)應(yīng)的處理函數(shù),而raise_softirq()函數(shù)可以觸發(fā)一個(gè)中斷。

      軟中斷和tasklet仍然運(yùn)行與中斷上下文,而工作隊(duì)列則運(yùn)行于進(jìn)程上下文。因此,軟中斷和tasklet的處理函數(shù)不能休眠,但工作隊(duì)列是可以的。

      local_bh_disable()和local_bh_enable()是內(nèi)核用于禁止和使能軟中斷和tasklet底半部機(jī)制的函數(shù)。

       

      下邊咱們?cè)賮?lái)說(shuō)說(shuō)有關(guān)中斷共享的相關(guān)點(diǎn):中斷共享即是多個(gè)設(shè)備共享一根硬件中斷線的情況。Linux2.6內(nèi)核支持中斷共享,使用方法如下:

      *共享中斷的多個(gè)設(shè)備在申請(qǐng)中斷時(shí)都應(yīng)該使用SA_SHIRQ標(biāo)志,而且一個(gè)設(shè)備以SA_SHIRQ申請(qǐng)某中斷成功的前提是之前該中斷的所有設(shè)備也都以SA_SHIRQ標(biāo)志申請(qǐng)?jiān)摻K端

      *盡管內(nèi)核模塊可訪問(wèn)的全局地址都可以作為request_irq(….,void *dev_id)的最后一個(gè)參數(shù)dev_id,但是設(shè)備結(jié)構(gòu)體指針是可傳入的最佳參數(shù)。

      *在中斷帶來(lái)時(shí),所有共享此中斷的中斷處理程序都會(huì)被執(zhí)行,在中斷處理程序頂半部中,應(yīng)迅速根據(jù)硬件寄存器中的信息比照傳入的dev_id參數(shù)判斷是否是被設(shè)備的中斷,如果不是,應(yīng)迅速返回。

       

      結(jié)語(yǔ):在這次講解中說(shuō)了三種Linux系統(tǒng)中中斷的頂/底半部機(jī)制和中斷共享的先關(guān)內(nèi)容,但礙于頁(yè)面空間的原因,沒(méi)有給出例子,我在下次博客中會(huì)專(zhuān)門(mén)來(lái)對(duì)每個(gè)點(diǎn)給出典型的模版.

      Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(二)

      “小濤哥,快醒醒,快醒醒..”小王使勁推著睡夢(mèng)中的我,“你不是說(shuō)今天要講昨天有關(guān)的典型模板實(shí)例嗎…”

      “啊?小姐啊,現(xiàn)在才早上8點(diǎn),還讓人睡覺(jué)不,別吵”我一頭鉆進(jìn)被子里說(shuō)。

      “不管,誰(shuí)讓你昨天不說(shuō)完,還賣(mài)個(gè)小關(guān)子,害我昨天晚上都沒(méi)睡好,想了一晚上…”

      我揉揉蒙蒙的眼說(shuō):“行,權(quán)當(dāng)看在你渴求的心情上,但只此一次,下不為例,我還想好好睡懶覺(jué)呢..”

      昨天我們講了有關(guān)中斷方面的東西,鑒于小王你不太懂,我今天就專(zhuān)門(mén)拿出一章來(lái)說(shuō)說(shuō)前邊中斷的使用典型模版,你照抄也方便不是:

      1)在中斷分類(lèi)中,我們說(shuō)到了有關(guān)向量中斷和非向量中斷,向量中斷就是入口地址不同,進(jìn)不同的地址做不同的事。那非向量中斷則是進(jìn)同一地址,至于區(qū)分就放在了進(jìn)去后用條件判斷,請(qǐng)看下邊的模板:

      irq_handler()
      {
          ...
          int int_src = read_int_status();   //讀硬件的中斷相關(guān)寄存器
           switch(int_src)  //判斷中斷源case DEV_A:
                 dev_a_handler();
                 break;
            case DEV_B:
                 dev_b_handler();
                 break;
            ....
            default:
                 break;
         }
      }

      2)在底半部機(jī)制中,我們講了tasklet,工作隊(duì)列和軟中斷先來(lái)看tasklet

      tasklet使用模版:

      void xxx_do_tasklet(unsigned long);
      DECLARE_TASKLET(XXX_tasklet, xxx_do_tasklet, 0);
      void xxx_do_tasklet(unsigned long)   //中斷處理底半部
      {
          .....
      }
      irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)  //中斷處理頂半部
      {
        ...
        tasklet_schedule(&xxx_tasklet);
      }
      int __init xxx_init(void)   //設(shè)備驅(qū)動(dòng)模塊加載函數(shù)
      {
        ..
        result= request_irq(xxx_irq, xxx_interrupt, SA_INTERRUPT, "XXX",NULL);  //申請(qǐng)中斷
        ...
      }
      void __exit xxx_exit(void)   //設(shè)備驅(qū)動(dòng)卸載模塊
      {
        ..
        free_irq(xxx_irq, xxx_interrupt);   //釋放中斷
        ..
      }
      工作隊(duì)列模版:
      struct work_struct xxx_wq;
      void xxx_do_work(unsigned long);
      void xxx_do_work(unsigned long)   //中斷處理底半部
      {
          .....
      }
      irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)  //中斷處理頂半部
      {
        ...
        schedule_work(&xxx_wq);
      }
      int xxx_init(void)   //設(shè)備驅(qū)動(dòng)模塊加載函數(shù)
      {
        ..
        result= request_irq(xxx_irq, xxx_interrupt, SA_INTERRUPT, "XXX",NULL);  //申請(qǐng)中斷
        ...
        INIT_WORK(&xxx_wq, (void (*)(void *))xxx_do_work, NULL);
          ...
      }
      void __exit xxx_exit(void)   //設(shè)備驅(qū)動(dòng)卸載模塊
      {
        ..
        free_irq(xxx_irq, xxx_interrupt);   //釋放中斷
        ..
      }

      3)在上節(jié)最后我還給你講了有關(guān)中斷共享的東西吧,小王,也把模版給你:

      irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)  //中斷處理頂半部
      {
        ...
        int status = read_int_status();  //獲取終端源
        if(!is_myint(dev_id, status))  //判斷是否是本設(shè)備的中斷
        {
           return  IRQ_NONE://立即返回
        }
        ..
        return IRQ_HANDLED;
      }
      int __init xxx_init(void)   //設(shè)備驅(qū)動(dòng)模塊加載函數(shù)
      {
        ..
        result= request_irq(xxx_irq, xxx_interrupt, SA_SHIRQ, "XXX",xxx_dev);  //申請(qǐng)共享中斷
        ...
      }
      void __exit xxx_exit(void)   //設(shè)備驅(qū)動(dòng)卸載模塊
      {
        ..
        free_irq(xxx_irq, xxx_interrupt);   //釋放中斷
        ..
      }

      共享中斷中,我們仔細(xì)看一下其實(shí)也沒(méi)什么,不是。就是在和前邊中斷中要修改一下中斷標(biāo)志,在中斷處理中判斷一下是否是自己本地的中斷,這個(gè)我都用紅色的標(biāo)識(shí)出來(lái)了。

       

      “小王,看,小濤哥說(shuō)話算數(shù)吧,上邊給出了所有模版,結(jié)合前一篇,相信你可以看的很順利的。好了,我要補(bǔ)補(bǔ)剛的覺(jué)了,中間不許叫我哈,想我也不行”我打打哈欠說(shuō)。

      Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(三)

        晚上7點(diǎn)10分..

      “小濤哥,這章不是叫Linux設(shè)備驅(qū)動(dòng)程序之中斷與時(shí)鐘,前邊你講了中斷,還給了我很多模版,我都看懂了,這次是不是要開(kāi)始講時(shí)鐘了..”

      “真聰明,越來(lái)越喜歡你這聰明的樣子了,說(shuō)的不錯(cuò),今天就要開(kāi)始一個(gè)新的模塊--內(nèi)核時(shí)鐘”我很少夸人,為啥今天夸她呢了,呵呵.

        定時(shí)器,意思大家都明白,我就不說(shuō)了,要是不明白,把它想成個(gè)鬧鐘總可以吧..

        定時(shí)器分為硬件和軟件定時(shí)器,軟件定時(shí)器最終還是要依靠硬件定時(shí)器來(lái)完成。內(nèi) 核在時(shí)鐘中斷發(fā)生后檢測(cè)各定時(shí)器是否到期,到期后的定時(shí)器處理函數(shù)將作為軟中斷在底半部執(zhí)行。實(shí)質(zhì)上,時(shí)鐘中斷處理程序執(zhí)行 update_process_timers函數(shù),該函數(shù)調(diào)用run_local_timers函數(shù),這個(gè)函數(shù)處理TIMER_SOFTIRQ軟中斷,運(yùn) 行當(dāng)前處理上到期的所有定時(shí)器。

      Linux內(nèi)核中定義提供了一些用于操作定時(shí)器的數(shù)據(jù)結(jié)構(gòu)和函數(shù)如下:

      1)timer_list:說(shuō)定時(shí)器,當(dāng)然要來(lái)個(gè)定時(shí)器的結(jié)構(gòu)體

        struct timer_list{
           struct list_head entry;  //定時(shí)器列表
            unsigned long expires;  //定時(shí)器到期時(shí)間
            void (*function)(unsigned long) ;//定時(shí)器處理函數(shù)
            unsigned long data;   //作為參數(shù)被傳入定時(shí)器處理函數(shù)
            struct timer_base_s *base;
      }
      2)初始化定時(shí)器:void init_timer(struct timer_list *timer);經(jīng)過(guò)這個(gè)初始化后,entry的next為NULL,并給base賦值
      3)增加定時(shí)器:void add_timer(struct timer_list *timer); 該函數(shù)用于注冊(cè)內(nèi)核定時(shí)器,并將定時(shí)器加入到內(nèi)核動(dòng)態(tài)定時(shí)器鏈表中。
      4)刪除定時(shí)器:int del_timer(struct timer_list *timer);
        說(shuō)明:del_timer_sync是del_timer的同步版,主要在多處理器系統(tǒng)中使用,如果編譯內(nèi)核時(shí)不支持SMP,del_timer_sync和del_timer等價(jià).
      5)修改定時(shí)器:int mod_timer(struct timer_list *timer, unsigned long expires);
      下邊是一個(gè)使用定時(shí)器的模版:
      struct xxx_dev  /*second設(shè)備結(jié)構(gòu)體*/ 
      {
        struct cdev cdev; /*cdev結(jié)構(gòu)體*/
        ...
        struct timer_list xxx_timer; /*設(shè)備要使用的定時(shí)器*/
      };
      int xxx_func1(...)  //xxx驅(qū)動(dòng)中某函數(shù) 
      {
        struct xxx_dev *dev = filp->private_data;
          ...
        /*初始化定時(shí)器*/
        init_timer(&dev->xxx_timer);
        dev->xxx_timer.function = &xxx_do_handle;
        dev->xxx_timer.data = (unsigned long)dev;
        dev->xxx_timer.expires = jiffies + delay;
        
        add_timer(&dev->xxx_timer); /*添加(注冊(cè))定時(shí)器*/
        ...
        return 0;
      }
      int xxx_func2(...)   //驅(qū)動(dòng)中某函數(shù) 
      {
        ...
        del_timer(&second_devp->s_timer);
        ...
      }
      static void xxx_do_timer(unsigned long arg)  //定時(shí)器處理函數(shù) 
      {
        struct xxx_device *dev = (struct xxx_device *)(arg);
          ...
          //調(diào)度定時(shí)器再執(zhí)行
        dev->xxx_timer.expires = jiffies + delay;
        add_timer(&dev->xxx_timer);
      }

      在定時(shí)器函數(shù)中往往會(huì)在做完具體工作后,延遲expires并將定時(shí)器再次添加到內(nèi)核定時(shí)器鏈表中,以便定時(shí)器能被再次觸發(fā)(這句話我也是從別處抄來(lái)的,別告訴小王哈)。

      在內(nèi)核定時(shí)器中,常常少不了要說(shuō)下內(nèi)核延遲的事,請(qǐng)接著往下看:

      1)短延遲:在linux內(nèi)核中提供了三個(gè)函數(shù)來(lái)分別實(shí)現(xiàn)納秒,微秒,毫秒延遲,原理上是忙等待,它根據(jù)CPU頻率進(jìn)行一定次數(shù)的循環(huán)

      void ndelay(unsigned long nsecs);                   void udelay(unsigned long usecs);                 void mdelay(unsigned long msecs);

      毫秒延遲已經(jīng)相當(dāng)大了,當(dāng)然更秒延遲當(dāng)然要小一些,在內(nèi)核中,為了性能,最好不要用mdelay,這會(huì)耗費(fèi)大量cpu資源,那么咋辦呢,涼拌..

      void msleep(unsigned int millisecs);   unsigned long msleep_interruptible(unsigned int millisecs);   void ssleep(unsigned int seconds);

      這三個(gè)是內(nèi)核專(zhuān)門(mén)提供該我們用來(lái)處理毫秒以上的延遲。上述函數(shù)將使得調(diào)用它的進(jìn)程睡眠參數(shù)指定的秒數(shù),其中第二個(gè)是可以被打斷的,其余的兩個(gè)是不可以的。

      2)長(zhǎng)延遲:內(nèi)核中進(jìn)行延遲最常用的方法就是比較當(dāng)前的jiffies和目標(biāo)jiffies(當(dāng)前的加上時(shí)間間隔的jiffies),直到未來(lái)的jiffies達(dá)到目標(biāo)jiffies。比如:

      unsigned long delay = jiffies + 100;  //延遲100個(gè)jiffies
      while(time_before(jiffies, delay));

      與time_before對(duì)應(yīng)的還有一個(gè)time_after().其實(shí)就是#define time_before(a,b)  time_after(b,a);

      另外兩個(gè)是time_after_eq(a,b)和time_before_eq(a,b)

      3)睡著延遲:這顯然是比忙等待好的方法,因?yàn)樵谖吹絹?lái)之前,進(jìn)程會(huì)處于睡眠狀態(tài),把 CPU空出來(lái),讓CPU可以做別的事情,等時(shí)間到了,調(diào)用schedule_timeout()就可以喚醒它并重新調(diào)度執(zhí)行。msleep和 msleep_interruptible本質(zhì)上都是依靠包含了schedule_timeout的 schedule_timeout_uninterruptible()和schedule_

      timeout_interruptible()實(shí)現(xiàn)。就像下邊這樣:

      void msleep(unsigned int msecs)   
      {
          unsigned long timeout = msecs_to_jiffies(msecs) + 1;
          while(timeout)
               timeout = schedule_timeout_uninterruptible(timeout);
      }
      unsigned long msleep_interruptible(unsigned int msecs)
      {
          unsigned long timeout = msecs_to_jiffies(msecs) + 1;
          while(timeout && !signal_pending(current))
               timeout = schedule_timeout_interruptible(timeout);
          return jiffies_to_msecs(timeout);
      }
      signed long __sched schedule_timeout_interruptible()signed long timeout)
      {
          __set_current_state(TASK_INTERRUPTIBLE);
          return schedule_timeout(timeout);
      }
      signed long __sched schedule_timeout_uninterruptible()signed long timeout)
      {
          __set_current_state(TASK_UNINTERRUPTIBLE);
          return schedule_timeout(timeout);
      }
      另外還有如下:
      time_on_timeout(wait_queue_head_t *q, unsigned long  timeout);
      interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout);
      這兩個(gè)將當(dāng)前進(jìn)程添加到等待隊(duì)列,從而在等待隊(duì)列上睡眠,當(dāng)超時(shí)發(fā)生時(shí),進(jìn)程將被喚醒。
       
      “小王,有關(guān)中斷和系統(tǒng)時(shí)鐘的咱們也講完了,下次就給你來(lái)一個(gè)有關(guān)系統(tǒng)時(shí)鐘的設(shè)備驅(qū)動(dòng)例子,鞏固一下吧,你可要抓緊哦..“

      Linux內(nèi)核開(kāi)發(fā)之中斷與時(shí)鐘(四)

      “小王,小王,今天可是這一章節(jié)最后一節(jié)了,知識(shí)點(diǎn)咱們前邊都講過(guò)了,今天主要是給你用前邊的東西講一個(gè)實(shí)際例子---秒字符設(shè)備驅(qū)動(dòng)程序”

        這個(gè)驅(qū)動(dòng)程序會(huì)在被打開(kāi)的時(shí)候初始化一個(gè)定時(shí)器并將其添加到內(nèi)核定時(shí)器鏈表中,每秒輸出一次當(dāng)前的jiffies,這意味著,定時(shí)器處理函數(shù)中每次都要修改新的expires。不多說(shuō)了,看代碼分析:

      #include …//必要的系統(tǒng)頭文件
      #define SECOND_MAJOR 252    /*預(yù)設(shè)的second的主設(shè)備號(hào)*/
      
      static int second_major = SECOND_MAJOR;
      struct second_dev   /*second設(shè)備結(jié)構(gòu)體*/ 
      {
        struct cdev cdev; /*cdev結(jié)構(gòu)體*/
        atomic_t counter;/* 一共經(jīng)歷了多少秒?*/
        struct timer_list s_timer; /*設(shè)備要使用的定時(shí)器*/
      };
      struct second_dev *second_devp; /*設(shè)備結(jié)構(gòu)體指針*/
      
      static void second_timer_handle(unsigned long arg)   /*定時(shí)器處理函數(shù)*/ 
      {
        mod_timer(&second_devp->s_timer,jiffies + HZ);
        atomic_inc(&second_devp->counter);
        printk(KERN_NOTICE "current jiffies is %ld\n", jiffies);
      }
      
      int second_open(struct inode *inode, struct file *filp)   /*文件打開(kāi)函數(shù)*/ 
      {
        /*初始化定時(shí)器*/
        init_timer(&second_devp->s_timer);
        second_devp->s_timer.function = &second_timer_handle;
        second_devp->s_timer.expires = jiffies + HZ;
        
        add_timer(&second_devp->s_timer); /*添加(注冊(cè))定時(shí)器*/
        
        atomic_set(&second_devp->counter,0); //計(jì)數(shù)清0
        return 0;
      }
      
      int second_release(struct inode *inode, struct file *filp)  /*文件釋放函數(shù)*/ 
      {
        del_timer(&second_devp->s_timer);
        return 0;
      }
      
      static ssize_t second_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)   /*globalfifo讀函數(shù)*/ 
      {  
        int counter;
        
        counter = atomic_read(&second_devp->counter);
        if(put_user(counter, (int*)buf))
        	return - EFAULT;
        else
        	return sizeof(unsigned int);  
      }
      
      static const struct file_operations second_fops =    /*文件操作結(jié)構(gòu)體*/ 
      {
        .owner = THIS_MODULE, 
        .open = second_open, 
        .release = second_release,
        .read = second_read,
      };
      
      static void second_setup_cdev(struct second_dev *dev, int index)   /*初始化并注冊(cè)cdev*/ 
      {
        int err, devno = MKDEV(second_major, index);
      
        cdev_init(&dev->cdev, &second_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &second_fops;
        err = cdev_add(&dev->cdev, devno, 1);
        if (err)
          printk(KERN_NOTICE "Error %d adding LED%d", err, index);
      }
      
      int second_init(void)   /*設(shè)備驅(qū)動(dòng)模塊加載函數(shù)*/ 
      {
        int ret;
        dev_t devno = MKDEV(second_major, 0);
      
        /* 申請(qǐng)?jiān)O(shè)備號(hào)*/
        if (second_major)
          ret = register_chrdev_region(devno, 1, "second");
        else  /* 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào) */
        {
          ret = alloc_chrdev_region(&devno, 0, 1, "second");
          second_major = MAJOR(devno);
        }
        if (ret < 0)
          return ret;
        /* 動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備結(jié)構(gòu)體的內(nèi)存*/
        second_devp = kmalloc(sizeof(struct second_dev), GFP_KERNEL);
        if (!second_devp)    /*申請(qǐng)失敗*/
        {
          ret =  - ENOMEM;
          goto fail_malloc;
        }
        memset(second_devp, 0, sizeof(struct second_dev));
        second_setup_cdev(second_devp, 0);
        return 0;
      
        fail_malloc: unregister_chrdev_region(devno, 1);
      }
      
      void second_exit(void)   /*模塊卸載函數(shù)*/ 
      {
        cdev_del(&second_devp->cdev);   /*注銷(xiāo)cdev*/
        kfree(second_devp);     /*釋放設(shè)備結(jié)構(gòu)體內(nèi)存*/
        unregister_chrdev_region(MKDEV(second_major, 0), 1); /*釋放設(shè)備號(hào)*/
      }
      MODULE_AUTHOR("hanyan225");
      MODULE_LICENSE("Dual BSD/GPL");
      module_param(second_major, int, S_IRUGO);
      module_init(second_init);
      module_exit(second_exit);
      下面是測(cè)試程序:
      #include ..//必要的頭文件
      main()
      {
        int fd;
        int counter = 0;
        int old_counter = 0;
        
        fd = open("/dev/second", O_RDONLY);   /*打開(kāi)/dev/second設(shè)備文件*/ 
        if (fd !=  - 1)
        {
          while (1)
          {
            read(fd,&counter, sizeof(unsigned int));//讀目前經(jīng)歷的秒數(shù)
            if(counter!=old_counter)
            {	
            	printf("seconds after open /dev/second :%d\n",counter);
            	old_counter = counter;
            }	
          }    
        }
        else
        {
          printf("Device open failure\n");
        }
      }
      當(dāng)我們編譯完驅(qū)動(dòng)程序,并運(yùn)行了測(cè)試程序后,會(huì)看到應(yīng)用程序不斷輸出自打開(kāi)/dev/second以來(lái)經(jīng)歷的秒數(shù)。如下:
      #./test
      seconds after open /dev/second 1
      seconds after open /dev/second 2
      ..
      ..
      再帶一個(gè)中斷,看看內(nèi)核輸出操作如下:
      #tar –f /var/logs/message
      current jiffies is 18569
      current jiffies is 18669

      current jiffies is 18769
      ..

      ..

       

      “小王,Linux設(shè)備驅(qū)動(dòng)之中斷與時(shí)鐘也算說(shuō)完了,告一段落了,也不知道你明白沒(méi),沒(méi)明白,也沒(méi)關(guān)系,不是有我嗎,只是不要一早吵醒我就好,下次我們就要開(kāi)始系統(tǒng)內(nèi)存方面的東西了…”我說(shuō)。

      “好,小濤哥,我好好看看,不懂就問(wèn)你,呵呵..”小王銀鈴般笑著還伴著怪臉,真是讓人…




        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多