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

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM Linux中斷機(jī)制之中斷的申請(qǐng)

          ARM Linux中斷機(jī)制之中斷的申請(qǐng)

          作者: 時(shí)間:2016-11-10 來(lái)源:網(wǎng)絡(luò) 收藏
          底層硬件操作方法

          每一條中斷線都有一個(gè)底層硬件操作函數(shù)集struct irq_chip 。大多數(shù)控制方法都是重復(fù)的 ,基本上只要有中斷響應(yīng) 、 中斷屏蔽 、 中斷開啟 、 中斷觸發(fā)類型設(shè)置等方法就可以滿足要求了。其他各種方法基本上和這些相同。

          本文引用地址:http://www.ex-cimer.com/article/201611/317088.htm

          這些操作方法的實(shí)現(xiàn)在文件linux/arch/arm/plat-s3c24xx/irq.c中。

          例如外部中斷 IRQ_EINT0 ~ IRQ_EINT3都用以下操作函數(shù)集:

          static struct irq_chip s3c_irq_eint0t4 = {
          .name= "s3c-ext0",
          .ack= s3c_irq_ack,
          .mask= s3c_irq_mask,
          .unmask= s3c_irq_unmask,
          .set_wake= s3c_irq_wake,
          .set_type= s3c_irqext_type,
          };

          /********************中斷響應(yīng)******************************/

          static inline void
          s3c_irq_ack(unsigned int irqno)
          {
          unsigned long bitval = 1UL << (irqno - IRQ_EINT0);

          __raw_writel(bitval, S3C2410_SRCPND);
          __raw_writel(bitval, S3C2410_INTPND);
          }

          /********************中斷屏蔽******************************/

          static void
          s3c_irq_mask(unsigned int irqno)
          {
          unsigned long mask;

          irqno -= IRQ_EINT0;

          mask = __raw_readl(S3C2410_INTMSK);
          mask |= 1UL << irqno;
          __raw_writel(mask, S3C2410_INTMSK);
          }

          /********************中斷開啟******************************/

          static void
          s3c_irq_unmask(unsigned int irqno)
          {
          unsigned long mask;

          if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
          irqdbf2("s3c_irq_unmask %dn", irqno);

          irqno -= IRQ_EINT0;

          mask = __raw_readl(S3C2410_INTMSK);
          mask &= ~(1UL << irqno);
          __raw_writel(mask, S3C2410_INTMSK);
          }

          /********************中斷觸發(fā)類型設(shè)置******************************/

          int
          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;
          gpcon_offset = (irq - IRQ_EINT0) * 2;
          extint_offset = (irq - IRQ_EINT0) * 4;
          }
          。。。。。。

          __raw_writel(value, gpcon_reg);//將對(duì)應(yīng)管腳配置成中斷功能


          switch (type)
          {
          case IRQ_TYPE_NONE:
          printk(KERN_WARNING "No edge setting!n");
          break;

          case IRQ_TYPE_EDGE_RISING:
          newvalue = S3C2410_EXTINT_RISEEDGE;
          break;

          case IRQ_TYPE_EDGE_FALLING:
          newvalue = S3C2410_EXTINT_FALLEDGE;
          break;

          case IRQ_TYPE_EDGE_BOTH:
          newvalue = S3C2410_EXTINT_BOTHEDGE;
          break;

          case IRQ_TYPE_LEVEL_LOW:
          newvalue = S3C2410_EXTINT_LOWLEV;
          break;

          case IRQ_TYPE_LEVEL_HIGH:
          newvalue = S3C2410_EXTINT_HILEV;
          break;

          default:
          printk(KERN_ERR "No such irq type %d", type);
          return -1;
          }

          value = __raw_readl(extint_reg);
          value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
          __raw_writel(value, extint_reg);//設(shè)置中斷的觸發(fā)方式。

          return 0;
          }

          中斷申請(qǐng)函數(shù)

          //中斷申請(qǐng)函數(shù)request_irq()只是函數(shù)request_threaded_irq()的包裝而已
          request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
          const char *name, void *dev)
          {
          return request_threaded_irq(irq, handler, NULL, flags, name, dev);
          }

          int request_threaded_irq(unsigned int irq, irq_handler_t handler,
          irq_handler_t thread_fn, unsigned long irqflags,
          const char *devname, void *dev_id)
          {
          struct irqaction *action;
          struct irq_desc *desc;
          int retval;

          //中斷類型標(biāo)識(shí)IRQF_SHARED和IRQF_DISABLED不應(yīng)當(dāng)被同時(shí)設(shè)置。
          if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
          (IRQF_SHARED|IRQF_DISABLED)) {
          pr_warning(
          "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQsn",
          irq, devname);
          }

          #ifdef CONFIG_LOCKDEP
          /*
          * Lockdep wants atomic interrupt handlers:
          */
          irqflags |= IRQF_DISABLED;
          #endif
          /*
          * Sanity-check: shared interrupts must pass in a real dev-ID,
          * otherwise well have trouble later trying to figure out
          * which interrupt is which (messes up the interrupt freeing
          * logic etc).
          */
          if ((irqflags & IRQF_SHARED) && !dev_id)
          return -EINVAL;

          desc = irq_to_desc(irq);//根據(jù)中斷號(hào)獲取中斷線描述符結(jié)構(gòu)體
          if (!desc)
          return -EINVAL;

          if (desc->status & IRQ_NOREQUEST)
          return -EINVAL;
          if (!handler)
          return -EINVAL;

          //分配一個(gè)中斷服務(wù)例程結(jié)構(gòu)體action并初始化它的各字段。

          action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
          if (!action)
          return -ENOMEM;

          action->handler = handler;
          action->thread_fn = thread_fn; //為NULL
          action->flags = irqflags;
          action->name = devname;

          //對(duì)于共享中斷 , 此特定值用來(lái)區(qū)分各中斷,以便從共享中斷線的諸多中斷處理程序中刪除指定的那一個(gè)。
          action->dev_id = dev_id;

          //將該例程添加到單向鏈表desc->action上,并啟動(dòng)該例程。

          retval = __setup_irq(irq, desc, action);
          if (retval)
          kfree(action);

          。。。。。。
          return retval;
          }

          static int
          __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
          {
          struct irqaction *old, **old_ptr;
          const char *old_name = NULL;
          unsigned long flags;
          int shared = 0;
          int ret;

          。。。。。。


          old_ptr = &desc->action;//獲取中斷處理例程單向鏈表上的第一個(gè)例程,如果它為NULL說(shuō)明該中斷線是第一次被觸發(fā)。
          old = *old_ptr;
          if (old) { //


          。。。。。。

          //如果該中斷線上存在中斷服務(wù)例程則讓old_ptr指向該例程鏈表的尾部,以便加入新的服務(wù)例程
          do {
          old_ptr = &old->next;
          old = *old_ptr;
          } while (old);
          shared = 1;
          }

          if (!shared) {

          //將操作函數(shù)集desc->chip的一些未設(shè)置的字段設(shè)為默認(rèn)值。
          irq_chip_set_defaults(desc->chip);

          init_waitqueue_head(&desc->wait_for_threads);

          /*

          函數(shù)__irq_set_trigger()的主要工作是調(diào)用函數(shù)chip->set_type(irq, flags);設(shè)置外部中斷的觸發(fā)方式。

          中斷觸發(fā)方式在文件linuxincludeirq.h中定義

          #define IRQ_TYPE_NONE0x00000000/* Default, unspecified type */
          #define IRQ_TYPE_EDGE_RISING0x00000001/* Edge rising type */
          #define IRQ_TYPE_EDGE_FALLING0x00000002/* Edge falling type */
          #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
          #define IRQ_TYPE_LEVEL_HIGH0x00000004/* Level high type */
          #define IRQ_TYPE_LEVEL_LOW0x00000008/* Level low type */
          #define IRQ_TYPE_SENSE_MASK0x0000000f/* Mask of the above */

          IRQF_TRIGGER_MASK在文件interrupt.h中定義

          #define IRQF_TRIGGER_NONE0x00000000
          #define IRQF_TRIGGER_RISING0x00000001
          #define IRQF_TRIGGER_FALLING0x00000002
          #define IRQF_TRIGGER_HIGH0x00000004
          #define IRQF_TRIGGER_LOW0x00000008
          #define IRQF_TRIGGER_MASK(IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW |
          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)


          可以看出只要外部中斷設(shè)置了觸發(fā)方式函數(shù)__irq_set_trigger()就會(huì)執(zhí)行。

          */
          if (new->flags & IRQF_TRIGGER_MASK)
          ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);

          if (ret)
          goto out_thread;
          } else
          compat_irq_chip_set_default_handler(desc);

          // desc->status的標(biāo)志IRQ_NOAUTOEN 在中斷初始化函數(shù) s3c24xx_init_irq()中調(diào)用函數(shù)set_irq_flags()設(shè)置。

          if (!(desc->status & IRQ_NOAUTOEN)) {
          desc->depth = 0;
          desc->status &= ~IRQ_DISABLED;
          desc->chip->startup(irq);//開啟中斷線
          } else
          desc->depth = 1;

          。。。。。。
          }

          *old_ptr = new; //將新加入的中斷處理例程添加到鏈表中

          。。。。。。

          //在proc文件系統(tǒng)中創(chuàng)建目錄。

          new->irq = irq;
          register_irq_proc(irq, desc);
          new->dir = NULL;
          register_handler_proc(irq, new);

          。。。。。。
          return ret;
          }

          中斷卸載函數(shù)free_irq().。

          如果指定的中斷線不是共享的 , 那么 , 該函數(shù)刪除處理程序的同時(shí)將禁用這條中斷線 。 如果
          中斷線是共享的,則僅刪除 dev_id 所對(duì)應(yīng)的處理程序,而這條中斷線本身只有在刪除了最
          后一個(gè)處理程序時(shí)才會(huì)被禁用。由此可以看出為什么惟一的 dev_ id 如此重要。對(duì)于共享的
          中斷線,需要一個(gè)惟一的信息來(lái)區(qū)分其上面的多個(gè)處理程序,并讓 free_irq() 僅僅刪除指定
          的處理程序。如果 dev_id 非空,它都必須與需要?jiǎng)h除的處理程序相匹配。非共享中斷,該
          域可以為空,但需要和注冊(cè)時(shí)使用的指針一致。

          static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
          {
          struct irq_desc *desc = irq_to_desc(irq);
          struct irqaction *action, **action_ptr;
          struct task_struct *irqthread;
          unsigned long flags;

          if (!desc)
          return NULL;


          action_ptr = &desc->action;
          for (;;) {
          action = *action_ptr;

          /*

          根據(jù) dev_id在中斷處理例程單項(xiàng)鏈表中找出一個(gè)要卸載的中斷例程。

          在單項(xiàng)鏈表中如果卸載了中間的一個(gè)還得將前一個(gè)和后一個(gè)連接起來(lái)。在這里用了一個(gè)小技巧。

          指針**action_ptr中存儲(chǔ)了兩個(gè)對(duì)象,一個(gè)是&action->next,另一個(gè)是action->next。

          比如鏈表中有三個(gè)action,我們要卸載的是第二個(gè),此時(shí)指針action_ptr中存放的是第一個(gè)action中的成員next的地址&action->next。

          *action_ptr存放的是第一個(gè)action的action->next所指向的對(duì)象,即第二個(gè)action。此時(shí)的action->next即是第三個(gè)action。

          只要*action_ptr = action->next;就將第一個(gè)action的action->next指向了第三個(gè)action。

          */

          if (action->dev_id == dev_id)
          break;
          action_ptr = &action->next;
          }

          *action_ptr = action->next;

          。。。。。。
          if (!desc->action) {// 無(wú)其他中斷使用該中斷線則禁止
          desc->status |= IRQ_DISABLED;
          if (desc->chip->shutdown)
          desc->chip->shutdown(irq);
          else
          desc->chip->disable(irq);
          }

          。。。。。。。


          return action;//返回中斷處理例程結(jié)構(gòu)體
          }
          //在函數(shù)free_irq中將函數(shù)__free_irq返回的中斷處理例程結(jié)構(gòu)體釋放掉。

          void free_irq(unsigned int irq, void *dev_id)
          {
          kfree(__free_irq(irq, dev_id));
          }



          關(guān)鍵詞: ARMLinux中斷機(jī)制申

          評(píng)論


          技術(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); })();