<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      6.分析request_irq和free_irq函數(shù)如何注冊注銷中斷(詳解)

      上一節(jié)講了如何實(shí)現(xiàn)運(yùn)行中斷,這些都是系統(tǒng)給做好的,當(dāng)我們想自己寫個中斷處理程序,去執(zhí)行自己的代碼,就需要寫irq_desc->action->handler,然后通過request_irq()來向內(nèi)核申請注冊中斷

      本節(jié)目標(biāo):

           分析request_irq()如何申請注冊中斷,free_irq()如何注銷中斷

       

      1.request_irq()位于kernel/irq/ manage .c,函數(shù)原型如下:

      int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)

      參數(shù)說明:

      unsigned int  irq:為要注冊中斷服務(wù)函數(shù)的中斷號,比如外部中斷0就是16,定義在mach/irqs.h

      irq_handler_t  handler:為要注冊的中斷服務(wù)函數(shù),就是(irq_desc+ irq )->action->handler

      unsigned long  irqflags: 觸發(fā)中斷的參數(shù),比如邊沿觸發(fā), 定義在linux/interrupt.h。         

      const char  *devname:中斷程序的名字,使用cat /proc/interrupt 可以查看中斷程序名字

      void  *dev_id:傳入中斷處理程序的參數(shù),注冊共享中斷時(shí)不能為NULL,因?yàn)樾遁d時(shí)需要這個做參數(shù),避免卸載其它中斷服務(wù)函數(shù)

      1.1request_irq代碼如下:

      int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
      {
             struct irqaction *action;
             ... ...
             action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);  //注冊irqaction結(jié)構(gòu)體類型的action
             if (!action)
                         return -ENOMEM;
      
      /* 將帶進(jìn)來的參數(shù)賦給action   */
               action->handler = handler;     
               action->flags = irqflags;
               cpus_clear(action->mask);
               action->name = devname;
               action->next = NULL;
               action->dev_id = dev_id;
      
               select_smp_affinity(irq);
           ... ...
               retval = setup_irq(irq, action);   // 進(jìn)入setup_irq(irq, action),設(shè)置irq_ desc[irq]->action
         
      if (retval) kfree(action); return retval; }

      從上面分析,request_irq()函數(shù)主要注冊了一個irqaction型action,然后把參數(shù)都賦給這個action,最后進(jìn)入setup_irq(irq, action)設(shè)置irq_ desc[irq]->action 

      1.2我們來看看setup_irq(irq, action)如何設(shè)置irq_ desc[irq]->action的:

      int setup_irq(unsigned int irq, struct irqaction *new)
      {
              struct irq_desc *desc = irq_desc + irq;   //根據(jù)中斷號找到irq_ desc[irq]
              ... ...
              p = &desc->action;                 //指向desc->action
              old = *p;
               if (old) {                 //判斷action是否為空
                          /*判斷這個中斷是否支持共享 (IRQF_SHARED)*/
                         if (!((old->flags & new->flags) & IRQF_SHARED) ||
                             ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
                                  old_name = old->name;
                                  goto mismatch;                  //不支持,則跳轉(zhuǎn)
                         }
      
      #if defined(CONFIG_IRQ_PER_CPU)
                         /* All handlers must agree on per-cpuness */
                         if ((old->flags & IRQF_PERCPU) !=
                             (new->flags & IRQF_PERCPU))
                                  goto mismatch;
      #endif
      
                         /*找到action鏈表尾處,后面用于添加 新的中斷服務(wù)函數(shù)(*new) */
                         do {
                                  p = &old->next;
                                  old = *p;
                         } while (old);
                         shared = 1;        //表示該中斷支持共享,添加新的action,否則直接賦值新的action
               }
      
               *p = new;             //指向新的action
      
       ... ...
      
               if (!shared) {                  //若該中斷不支持共享
                         irq_chip_set_defaults(desc->chip);    //更新desc->chip,將為空的成員設(shè)置默認(rèn)值       
      
      #if defined(CONFIG_IRQ_PER_CPU)
                           if (new->flags & IRQF_PERCPU)
                                    desc->status |= IRQ_PER_CPU;
      #endif
      
                         /* Setup the type (level, edge polarity) if configured: */
                         if (new->flags & IRQF_TRIGGER_MASK) {
                           if (desc->chip && desc->chip->set_type)        // desc->chip->set_type設(shè)置為中斷引腳
                                desc->chip->set_type(irq,new->flags & IRQF_TRIGGER_MASK);
                                  else
                                           printk(KERN_WARNING "No IRQF_TRIGGER set_type "
      
                                                  "function for IRQ %d (%s)\n", irq,
      
                                                  desc->chip ? desc->chip->name :
      
                                                  "unknown");
                         } else
                                  compat_irq_chip_set_default_handler(desc);
      
                         desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
                                             IRQ_INPROGRESS);
      
       
                         if (!(desc->status & IRQ_NOAUTOEN)) {
                                  desc->depth = 0;
                                  desc->status &= ~IRQ_DISABLED;
                                  if (desc->chip->startup)
                                           desc->chip->startup(irq);     //開啟中斷
                                  else
                                           desc->chip->enable(irq);     //使能中斷
      
                         } else
      
                                 /* Undo nested disables: */
                                  desc->depth = 1;
               }

      從上面可以看出setup_irq(irq, action)主要是將action中斷服務(wù)函數(shù)放在irq_ desc[irq]->action中,

      然后設(shè)置中斷引腳:   

      desc->chip->set_type(irq,new->flags & IRQF_TRIGGER_MASK);

      最后[開啟/使能]中斷:

       desc->chip->[startup(irq) /enable(irq)];     //[開啟/使能]中斷

      我們以外部中斷0的desc[16]->chip->set_type為例,來看看它是如何初始化中斷引腳的:

      s3c_irqext_type(unsigned int irq, unsigned int type)
      {
               void __iomem *extint_reg;
               void __iomem *gpcon_reg;
               unsigned long gpcon_offset, extint_offset;
               unsigned long newvalue = 0, value;
             if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))    //找到寄存器
               {
                         gpcon_reg = S3C2410_GPFCON;      
                         extint_reg = S3C24XX_EXTINT0;      // EXTINT0對應(yīng)中斷0~中斷7
                         gpcon_offset = (irq - IRQ_EINT0) * 2;    //找到gpcon寄存器的相應(yīng)位偏移量
                         extint_offset = (irq - IRQ_EINT0) * 4;    //找到extint寄存器的相應(yīng)位偏移量
               }
          else if(... ...)                    //找到其它的EINT4~23的寄存器
      
      /*將GPIO引腳設(shè)為中斷引腳*/
      value = __raw_readl(gpcon_reg);  
      value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);  //相應(yīng)位設(shè)置0x02
      switch (type)          //設(shè)置EXTINT0中斷模式
      {
      case IRQT_NOEDGE:            //未指定的中斷模式
                          printk(KERN_WARNING "No edge setting!\n");
                          break; 
      
                 case IRQT_RISING:           //上升沿觸發(fā),設(shè)置EXTINT0相應(yīng)位為0x04
                          newvalue = S3C2410_EXTINT_RISEEDGE;
                          break;
      
                 case IRQT_FALLING:     //下降沿觸發(fā),設(shè)置EXTINT0相應(yīng)位為0x02
                          newvalue = S3C2410_EXTINT_FALLEDGE;
                          break;
       
                 case IRQT_BOTHEDGE:  //雙邊沿觸發(fā),設(shè)置EXTINT0相應(yīng)位為0x06
                          newvalue = S3C2410_EXTINT_BOTHEDGE;
                          break;
      
                 case IRQT_LOW:                   //低電平觸發(fā),設(shè)置EXTINT0相應(yīng)位為0x00
                          newvalue = S3C2410_EXTINT_LOWLEV;
                          break;
      
                 case IRQT_HIGH:                 //高電平觸發(fā),設(shè)置EXTINT0相應(yīng)位為0x01
                          newvalue = S3C2410_EXTINT_HILEV;
                          break;
                 default:          
      }
      
      /*更新EXTINT0相應(yīng)位*/
      value = __raw_readl(extint_reg);
      value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);  //相應(yīng)位設(shè)置
      __raw_writel(value, extint_reg);    //向extint_reg寫入value值
      return 0;
      }

      通過上面分析,就是將action->flags帶入到desc[16]->chip->set_type里面,根據(jù)不同的中斷來設(shè)置寄存器模式

       

      2.request_irq()是注冊中斷,同樣的卸載中斷的函數(shù)是free_irq()

      free_irq()也位于kernel/irq/ manage .c,函數(shù)原型如下:

      free_irq(unsigned int irq, void *dev_id);

      參數(shù)說明:

      unsigned int  irq:要卸載的中斷號

      void  *dev_id:這個是要卸載的中斷action下的哪個服務(wù)函數(shù),

      2.1 free_irq()代碼如下:

      void free_irq(unsigned int irq, void *dev_id)
      {
         struct irq_desc *desc;
         struct irqaction **p;
         unsigned long flags;
         irqreturn_t (*handler)(int, void *) = NULL;
       
         WARN_ON(in_interrupt());
         if (irq >= NR_IRQS)
                return;
      
         desc = irq_desc + irq;                //根據(jù)中斷號,找到數(shù)組
         spin_lock_irqsave(&desc->lock, flags);
         p = &desc->action;          //p指向中斷里的action鏈表
      
         for (;;) {
              struct irqaction *action = *p;
      
                if (action) {        //在action鏈表中找到與參數(shù)dev_id相等的中斷服務(wù)函數(shù)
                      struct irqaction **pp = p;
                      p = &action->next;       
                      if (action->dev_id != dev_id)    //直到找dev_id才執(zhí)行下面,進(jìn)行卸載
                        continue;          
                      *pp = action->next;      //指向下個action成員,將當(dāng)前的action釋放掉
                      #ifdef CONFIG_IRQ_RELEASE_METHOD
                         if (desc->chip->release)   //執(zhí)行chip->release釋放中斷服務(wù)函數(shù)相關(guān)的東西
                               desc->chip->release(irq, dev_id);
                      #endif
                if (!desc->action) {   //判斷當(dāng)前action成員是否為空,表示沒有中斷服務(wù)函數(shù)
                             desc->status |= IRQ_DISABLED;
                             if (desc->chip->shutdown)       //執(zhí)行chip->shutdown關(guān)閉中斷
                    desc->chip->shutdown(irq);
                       else                          //執(zhí)行chip-> disable禁止中斷
                     desc->chip->disable(irq);
                                          }
      
                        spin_unlock_irqrestore(&desc->lock, flags);
                        unregister_handler_proc(irq, action);
                  synchronize_irq(irq);
                  if (action->flags & IRQF_SHARED)
                    handler = action->handler;
                      kfree(action);
                       return;
      
                     }
      
         printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);//沒有找到要卸載的action成員
      
         spin_unlock_irqrestore(&desc->lock, flags);
      
         return;
      
             }
      
      #ifdef CONFIG_DEBUG_SHIRQ
               if (handler) {
      
                         /*
      
                          * It's a shared IRQ -- the driver ought to be prepared for it
      
                          * to happen even now it's being freed, so let's make sure....
      
                          * We do this after actually deregistering it, to make sure that
      
                          * a 'real' IRQ doesn't run in parallel with our fake
      
                          */
                         handler(irq, dev_id);
      
               }
      #endif
      }

      從上面分析,free_irq()函數(shù)主要通過irq和dev_id來找要釋放的中斷action

      若釋放的中斷action不是共享的中斷(為空),則執(zhí)行:

       

      *pp = action->next;      //指向下個action成員,將當(dāng)前的action釋放掉
      desc->chip->release(irq, dev_id);    //執(zhí)行chip->release釋放中斷服務(wù)函數(shù)相關(guān)的東西
      
      desc->status |= IRQ_DISABLED;            //設(shè)置desc[irq]->status標(biāo)志位
      desc->chip->[shutdown(irq)/ desible(irq)];    //關(guān)閉/禁止中斷

       

      若釋放的中斷action是共享的中斷(還有其它中斷服務(wù)函數(shù))的話就只執(zhí)行:

      *pp = action->next;      //指向下個action成員,將當(dāng)前的action釋放掉
      desc->chip->release(irq, dev_id);    //執(zhí)行chip->release釋放中斷服務(wù)函數(shù)相關(guān)的東西

       

      request_irq()和free_irq()分析完畢后,接下來開始編寫中斷方式的按鍵驅(qū)動

       

      posted @ 2017-09-11 19:43  諾謙  閱讀(16222)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲区一区二区激情文学| 国产午夜福利片在线观看| 国产成人啪精品午夜网站| 国产亚洲精品第一综合麻豆 | 波多野结衣久久一区二区| 国产精品国产三级国快看| 亚洲最大成人在线播放| 99久久机热/这里只有精品| 精品久久欧美熟妇www| 国产高清精品一区二区三区| 国产精品不卡区一区二| 福利视频一区二区在线| 人妻出轨av中文字幕| 久久精品国产字幕高潮| 亚洲夜色噜噜av在线观看| 亚洲无线一二三四区手机| 国产自产视频一区二区三区| 新田县| 毛片内射久久久一区| 少妇办公室好紧好爽再浪一点| 亚洲熟女乱色综合亚洲图片| 在线 欧美 中文 亚洲 精品| 最新av中文字幕无码专区| 色久综合色久综合色久综合| 国产午夜精品久久精品电影| 丰满人妻熟妇乱精品视频| 人妻精品动漫H无码中字| 石门县| 国产中文99视频在线观看| 中文字幕国产精品日韩| 人人做人人澡人人人爽| 九九热在线视频观看最新| 欧美成人影院亚洲综合图| 日本道之久夂综合久久爱| 国内永久福利在线视频图片| 日韩精品区一区二区三vr| 狠狠躁夜夜躁人人爽天天古典| 无码国内精品久久人妻蜜桃| 一区二区三区鲁丝不卡| 午夜福利免费视频一区二区| 无码人妻aⅴ一区二区三区69岛|