Adaptation/GUID-2E54DA7D-1094-41C6-AFB0-9999471991F8.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-2E54DA7D-1094-41C6-AFB0-9999471991F8" xml:lang="en"><title>Interrupt Implementation Guide</title><shortdesc>Describes how to implement the Interrupt class.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    13 <section id="GUID-514E76B0-009C-48D4-935C-FBE48FDD3631-GENID-1-2-1-10-1-5-1-7-1-1-9-1-4-1-3-1"><title>Introduction</title>             <p>Interrupt handling is implemented by writing platform
       
    14 specific versions of the structures and functions of the Interrupt
       
    15 class. The details of the implementation depend on hardware and the
       
    16 architecture of the device. This document describes a simple implementation
       
    17 of the structures and functions and then discusses more elaborate
       
    18 strategies required with the use of device specific interrupts , chained
       
    19 interrupts and multiple interrupt sources. It also covers implementation
       
    20 on unicore platforms only. The SMP version of the  kernel now implements
       
    21 support for the ARM Generic Interrupt Controller and relies on its
       
    22 use.</p><ul>
       
    23 <li><p>Chained interrupts are interrupts which are output by one controller
       
    24 and input to another. They need to be distinguished in the ISR table
       
    25 and require extensions to the handler functions.</p></li>
       
    26 <li><p>Multiple interrupt sources to the same ISR require the use
       
    27 of pseudo-interrupts.</p></li>
       
    28 <li><p>When a Symbian port is split into an ASSP and variant (common
       
    29 and device specific) layer, the variant may include additional interrupt
       
    30 sources. Their API is defined by the port. Device specific interrupts
       
    31 are sometimes used to handle interrupts from peripherals: another
       
    32 technique is to route peripheral interrupts to a GPIO pin. Peripheral
       
    33 interrupts cannot be specified as part of the ASSP layer.</p></li>
       
    34 </ul><p>The Template Baseport provides a skeleton implementation for
       
    35 developers to modify at <filepath>kernelhwsrv/bsptemplate/asspandvariant/template_assp/interrupts.cpp</filepath>.</p>         </section>
       
    36 <section id="GUID-35383FC7-4099-4048-B4B8-F84D10259036"><title>The
       
    37 ISR table</title><p>The ISR table is a data structure which pairs
       
    38 each ISR with the interrupt source to which it will be bound. It must
       
    39 have enough space for each interrupt source on the device. It is implemented
       
    40 as an array of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-B864263D-7682-3938-9180-030C3D123174"><apiname>Interrupt::SInterruptHander</apiname></xref> of size <xref href="GUID-2A04B9AF-92F3-3A5C-93AD-3DD52E20A6D3.dita"><apiname>KINterruptSourceCount</apiname></xref> in which the interrupt Id is used
       
    41 as an index to the table. This example code assumes a size of 32.</p><codeblock xml:space="preserve">...
       
    42 const TInt KInterruptSourceCount = 32;
       
    43 SInterruptHandler IsrHandlers[KInterruptSourceCount];
       
    44 ...</codeblock></section>
       
    45 <section id="GUID-393C43D1-6A48-473F-AE6F-E3E6F474762B"><title>DisableAndClearAll()</title><p>Interrupts must be disabled and cleared with a call to <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-3486EC50-55C5-366B-8BE2-E1180F52AB05"><apiname>Interrupt::DisableAndClearAll()</apiname></xref> before the call to <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-41FEFEA2-27C8-33F3-8781-89C092AE41B6"><apiname>Interrupt::Init1()</apiname></xref> at the start of initialization. Implementation
       
    46 of this function is entirely hardware dependent.</p></section>
       
    47 <section id="GUID-7CD1BE2F-CDDC-46DC-95CE-4ADF909F0494"><title>Init1()</title><p>The kernel is initialized in phases, interrupts being involved
       
    48 in the first phase and sometimes the third. The Init1() function should
       
    49 be implemented to</p><ul>
       
    50 <li><p>Initialize the ISR table, binding all ISRs to the spurious
       
    51 interrupts handler.</p></li>
       
    52 <li><p>Register the dispatcher functions.</p></li>
       
    53 <li><p>Bind ISRs which handle chained or pseudo interrupts.</p></li>
       
    54 </ul><p>Interrupts must be disabled during first phase initialization.</p><p>This example code illustrates initialization of the ISR table.</p><codeblock xml:space="preserve">...
       
    55 const TInt KInterruptSourceCount = 32;
       
    56 SInterruptHandler IsrHandlers[KInterruptSourceCount];
       
    57 ...
       
    58 
       
    59 for( TInt i = 0; i &lt; KInterruptSourceCount; ++i )
       
    60     {
       
    61     IsrHandlers[i].iIsr = SpuriousHandler;
       
    62     IsrHandlers[i].iPtr = (TAny*)i;
       
    63     }</codeblock><p>This example code illustrates an implementation
       
    64 of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-41FEFEA2-27C8-33F3-8781-89C092AE41B6"><apiname>Interrupt::Init1()</apiname></xref> after the point at which
       
    65 the ISR table has been initialized.</p><codeblock xml:space="preserve">void TemplateInterrupt::Init1()
       
    66     {
       
    67      //
       
    68      // need to hook the ARM IRQ and FIQ handlers as early as possible
       
    69      // and disable and clear all interrupt sources
       
    70      //
       
    71      ... 
       
    72      DisableAndClearAll();
       
    73      Arm::SetIrqHandler((TLinAddr)TemplateInterrupt::IrqDispatch);
       
    74      Arm::SetFiqHandler((TLinAddr)TemplateInterrupt::FiqDispatch);
       
    75     }
       
    76 </codeblock></section>
       
    77 <section id="GUID-3FCBCFFC-C3E6-4439-86A4-4845B21CF3CF"><title>Init3()</title><p>Third phase initialization involves initializing various interrupt
       
    78 handlers and sources which can only be initialized when the kernel
       
    79 is fully functional. This is done with a call to <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-D77022E6-FA45-3C00-95A3-B62792359997"><apiname>Interrupt::Init3()</apiname></xref>.</p><p>It is important to remember that interrupts are enabled during
       
    80 third phase initialization.</p></section>
       
    81 <section id="GUID-C4CD4CA8-175B-4995-8DC3-7D7F7D62E3FB"><title>Spurious()</title><p>Interrupts not bound to a real ISR must be bound to a 'spurious'
       
    82 handler function <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-701CE497-EF6D-3557-8558-5C9354C1039B"><apiname>Interrupt::Spurious()</apiname></xref> which returns
       
    83 an error with the number of the interrupt.</p></section>
       
    84 <section id="GUID-D5367FEE-AC77-4317-B0CA-A8F0690AACD1"><title>Bind()</title><p>The <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> function binds ISRs to
       
    85 interrupt sources.</p><p>The argument <codeph>aId</codeph> is the
       
    86 Id of an interrupt source and is used to index an entry in the ISR
       
    87 table. Set the <codeph>iPtr</codeph> and <codeph>iIsr</codeph> members
       
    88 of that entry (ISR parameter and ISR pointer) to the passed in values <codeph>aPtr</codeph> and <codeph>aIsr</codeph>.</p><p>The implementation
       
    89 should perform some preliminary checks.</p><ul>
       
    90 <li><p>The interrupt Id must be checked for validity</p></li>
       
    91 <li><p>The ISR must not already be bound to a real interrupt. It should
       
    92 have been bound to the spurious interrupt handler at initialization.</p></li>
       
    93 </ul><p>All interrupts must be disabled during binding.</p><p>This
       
    94 example code provides a basic implementation.</p><codeblock xml:space="preserve">EXPORT_C TInt Interrupt::Bind(TInt aId, TIsr aIsr, TAny* aPtr)
       
    95     {
       
    96        TInt r = KErrNone;
       
    97     If(TUint(aId)&gt;=TUint(KInterruptSourceCount))
       
    98         {
       
    99         r = KErrArgument; // Illegal interrupt number
       
   100         }
       
   101        else 
       
   102         {
       
   103            SInterruptHandler&amp; h = IsrHandlers[aId];
       
   104         TInt irq = NKern::DisableAllInterrupts();
       
   105         if (h.iIsr != &amp;SpuriousHandler)
       
   106             {
       
   107             r = KErrInUse; // Already bound to an ISR
       
   108             }
       
   109            else
       
   110             {
       
   111             h.iPtr = aPtr; // The ISR parameter
       
   112             h.iIsr = aIsr; // Pointer to the ISR
       
   113             }
       
   114         NKern::RestoreInterrupts(irq);
       
   115         }
       
   116     return r;
       
   117     }
       
   118 </codeblock><p>The implementation of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> can be more complicated in the case of chained interrupts, multiple
       
   119 interrupt sources, pseudo interrupt sources and device interrupts:
       
   120 see the discussion of those topics.</p></section>
       
   121 <section id="GUID-BEB323CF-9DDC-4486-AD32-682B78AF2072"><title>Unbind()</title><p>The <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> function unbinds ISRs
       
   122 from interrupt sources.</p><p>The argument <codeph>aId</codeph> is
       
   123 the Id of an interrupt source and is used to index an entry in the
       
   124 ISR table. Reset the entry in the ISR table to reference the spurious
       
   125 handler function.</p><p>The implementation should perform some preliminary
       
   126 checks.</p><ul>
       
   127 <li><p>The interrupt Id must be checked for validity</p></li>
       
   128 <li><p>The ISR must not already be unbound (that is, bound to the
       
   129 spurious interrupt handler).</p></li>
       
   130 </ul><p>All interrupts must be disabled during unbinding.</p><p>This
       
   131 example code provides a basic implementation.</p><codeblock xml:space="preserve">EXPORT_C TInt Interrupt::Unbind(TInt aId)
       
   132     {
       
   133        TInt r = KErrNone;
       
   134        if (TUint(aId) &gt;= TUint(KInterruptSourceCount))
       
   135         {
       
   136         r = KErrArgument;    // Illegal interrupt number
       
   137         }
       
   138        else
       
   139         {
       
   140         SInterruptHandler&amp; h = IsrHandlers[aId];
       
   141         TInt irq = NKern::DisableAllInterrupts();
       
   142         if (h.iIsr == &amp;SpuriousHandler)
       
   143             {
       
   144             r = KErrGeneral; // Already unbound
       
   145             }
       
   146         else
       
   147             {
       
   148             h.iPtr =(TAny*)aId;
       
   149             h.iIsr = SpuriousHandler;  // Replace with spurious handler
       
   150             // NOTE: at this point it may be wise to
       
   151             // force the hardware interrupt source to disabled.
       
   152             }
       
   153         NKern::RestoreInterrupts(irq);
       
   154         }
       
   155     return r;
       
   156        }
       
   157 </codeblock><p>The implementation of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> can be more complicated in the case of chained interrupts, multiple
       
   158 interrupt sources, pseudo interrupt sources and device interrupts:
       
   159 see the discussion of those topics below.</p></section>
       
   160 <section id="GUID-F8859FAE-9FA3-494E-A294-0ACF7158BD40"><title>Enable()</title><p>Device drivers call the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-BB169E6E-D8F9-3762-899D-6DBA4B29CF87"><apiname>Interrupt::Enable()</apiname></xref> function to enable the interrupt source identified by the argument <codeph>anId</codeph> in the interrupt controller hardware. </p><p>The implementation
       
   161 is entirely hardware dependent.</p><p>This example involves a check
       
   162 for chained interrupts, which are discussed in their own section below.</p><codeblock xml:space="preserve">EXPORT_C TInt Interrupt::Enable(TInt anId)
       
   163     {
       
   164      TInt r=KErrNone;
       
   165      // if ID indicates a chained interrupt, call variant...
       
   166      if (anId&lt;0 &amp;&amp; ((((TUint)anId)&gt;&gt;16)&amp;0x7fff)&lt;(TUint)KNumTemplateInts)
       
   167          r=TemplateAssp::Variant-&gt;InterruptEnable(anId);
       
   168      else if ((TUint)anId&gt;=(TUint)KNumTemplateInts)
       
   169          r=KErrArgument;
       
   170      else if (TemplateInterrupt::Handlers[anId].iIsr==TemplateInterrupt::Spurious)
       
   171          r=KErrNotReady;
       
   172      else
       
   173          {
       
   174          //
       
   175          // TO DO: (mandatory)
       
   176          //
       
   177          // Enable the corresponding Hardware Interrupt source
       
   178          //
       
   179          }
       
   180      return r;
       
   181     }
       
   182 </codeblock></section>
       
   183 <section id="GUID-A508AA5E-E81A-4FC0-97DD-41543FF458E6"><title>Disable()</title><p>Device drivers call the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-2D14E023-E6ED-39BF-8B31-6FA510957A8A"><apiname>Interrupt::Disable()</apiname></xref> function to disable the interrupt source identified by the argument <codeph>anId</codeph>  in the interrupt controller hardware. The implementation
       
   184 is entirely hardware dependent.</p></section>
       
   185 <section id="GUID-53F6AAE1-3AE7-49E6-845D-135E43449F9F"><title>Clear()</title><p>Device drivers call the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-DB641A23-82B2-373E-A514-E11118CB6E69"><apiname>Interrupt::Clear()</apiname></xref> function
       
   186 to acknowledge that they have serviced the interrupt and cleared the
       
   187 pending flag in the interrupt controller hardware. The implementation
       
   188 is entirely hardware dependent.</p><p><xref href="GUID-5BCEAABF-D060-3F29-A8AE-0C14A8DFC1D2.dita"><apiname>Clear()</apiname></xref> is
       
   189 a useful function in cases where an interrupt must be cleared explicitly
       
   190 rather than as a side effect of I/O register access: for instance
       
   191 in PC card and MMC controller code.</p></section>
       
   192 <section id="GUID-3EB891CD-91C7-4B66-B41F-6F19CAF717CF"><title>SetPriority()</title><p>The <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-FA4CFED7-D694-399C-8F84-FA9FE3C3A171"><apiname>Interrupt::SetPriority()</apiname></xref> function associates
       
   193 a priority value (passed as a<codeph> TInt</codeph>) with an  interrupt
       
   194 Id. The meaning of the priority value is entirely hardware dependent.</p><p>Priority is a property of interrupts on some hardware, an example
       
   195 being OMAP. Where the hardware is of this type, <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-FA4CFED7-D694-399C-8F84-FA9FE3C3A171"><apiname>Interrupt::SetPriority()</apiname></xref> can be used to modify priorities in hardware. A simple use is to
       
   196 determine whether an interrupt generates an IRQ or an FIQ. If priority
       
   197 adjustment is not supported or not specified, the function should
       
   198 simply return <codeph>KErrNotSupported</codeph>.</p><p>The implementation
       
   199 is entirely hardware dependent.</p></section>
       
   200 <section id="GUID-ABE454D5-E219-48D0-A38C-7A63FBB0C088"><title>IrqDispatch()
       
   201 and FiqDispatch()</title><p>The functions <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-9CD4CECF-9DF9-3E94-BF17-45F387228A76"><apiname>Interrupt::IrqDispatch()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-B12F9319-11D6-3E43-AE66-6654DF15D1E3"><apiname>Interrupt::FiqDispatch()</apiname></xref> dispatch an interrupt
       
   202 by calling the associated ISR. Interrupts are either IRQ or FIQ interrupts
       
   203 and separate dispatch functions must be provided for each type. What
       
   204 follows refers to IRQs but applies equally to FIQs as the distinction only operates at the level of hardware and the two
       
   205 dispatch functions look the same.</p><p>In the simplest implementation,
       
   206 the interrupt Id is used as an index into the ISR table. The <codeph>iIsr</codeph> member of the entry is called as a function with the <codeph>iPtr</codeph> member as its argument. The interrupt Id is taken from
       
   207 a list of pending IRQs as in this example code.</p><codeblock xml:space="preserve">void IrqDispatch()
       
   208     {
       
   209     TUint32 pendingIrqs = TheAssp::IrqPendingRegister();
       
   210     // for the purposes of this example we assume that reading
       
   211     // this register also clears the pending flags
       
   212 
       
   213     TInt index = 0;
       
   214     while( pendingIrqs )
       
   215         {
       
   216         // while there is at least one pending IRQ
       
   217         if( pendingIrqs &amp; 1 )
       
   218             {
       
   219             // the next interrupt is pending - dispatch it
       
   220             (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr);
       
   221             }
       
   222         ++index;
       
   223         pendingIrqs &gt;&gt;= 1;
       
   224         }
       
   225     }
       
   226 </codeblock><p>This code is a simplified example which assumes that</p><ul>
       
   227 <li><p>The interrupt controller provides 32 interrupt sources and
       
   228 has a 32 bit pending interrupt register where a 1 indicates a pending
       
   229 interrupt and all ones are cleared when the register is read.</p></li>
       
   230 <li><p>The interrupt source represented by the low order bit in the
       
   231 pending interrupt register is represented by interrupt Id 0 and so
       
   232 on.</p></li>
       
   233 </ul><p>Implementation will be more complex where chained interrupts
       
   234 and multiple interrupt sources are involved, as discussed below.</p><p>Dispatch functions are time critical. You will probably write
       
   235 an initial implementation in C++ to get them working and then rewrite
       
   236 in assembler for maximum efficiency.</p><codeblock xml:space="preserve"/></section>
       
   237 <section id="GUID-457E3092-8FE3-4CB4-8910-11E03DD8C82D"><title>Chained
       
   238 interrupts</title><p>A platform often has multiple interrupt controllers
       
   239 of higher and lower priority (higher and lower level controllers),
       
   240 organized so that the output of a lower level controller is one of
       
   241 the inputs to a higher level controller. Interrupt sources organized
       
   242 in this way are called chained interrupts.</p><p>In a system with
       
   243 chained interrupts, the ISR table must be structured so that interrupts
       
   244 from higher and lower level controllers can be distinguished by their
       
   245 Ids.</p><p>The <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> functions are the same whether interrupts are chained or not.</p><p>In a system with chained interrupts it can be desirable to write
       
   246 the <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-BB169E6E-D8F9-3762-899D-6DBA4B29CF87"><apiname>Interrupt::Enable()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-2D14E023-E6ED-39BF-8B31-6FA510957A8A"><apiname>Interrupt::Disable()</apiname></xref> functions so as to disable not the interrupt itself but a the higher
       
   247 level interrupt on the controller to which it is the input.</p><p>The <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-9CD4CECF-9DF9-3E94-BF17-45F387228A76"><apiname>Interrupt::IrqDispatch()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-B12F9319-11D6-3E43-AE66-6654DF15D1E3"><apiname>Interrupt::FiqDispatch()</apiname></xref> functions need to be extended in a system with chained interrupts.
       
   248 There are two techniques for doing this, both of which involve a separate
       
   249 second level dispatch function, but which differ in the way it is
       
   250 called. </p><ul>
       
   251 <li><p>In one technique, the main interrupt dispatcher calls the second
       
   252 level dispatcher if the relevant condition is satisfied. </p></li>
       
   253 <li><p>In the other technique, the second level dispatcher is bound
       
   254 directly to an interrupt source as its ISR. </p></li>
       
   255 </ul><p>The first technique works well in cases where there is only
       
   256 a main and a secondary interrupt controller. It does not scale well
       
   257 in cases which make use of multiple controllers chained to substantial
       
   258 depth.</p><p>You need to allocate locations in your ISR table for
       
   259 the secondary controllers so that the interrupt Id identifies which
       
   260 hardware controller the input is on. For example, if each interrupt
       
   261 controller handles 32 interrupt sources, you could allocate the first
       
   262 32 Ids to the highest level controller, the next 32 to a second level
       
   263 controller and so on.</p><p>This example code illustrates a main dispatcher
       
   264 which calls a second level dispatcher.</p><codeblock xml:space="preserve">void IrqDispatch()
       
   265     {
       
   266     TUint32 pendingIrqs = TheAssp::IrqPendingRegister();
       
   267 
       
   268     TInt index = 0;
       
   269     while( pendingIrqs )
       
   270         {
       
   271         if( pendingIrqs &amp; 1 )
       
   272             {
       
   273             if( index == EMainIntChainIrq )
       
   274                 {
       
   275                 // second-level controller is signalling
       
   276                 SecondLevelIrqDispatch();
       
   277                 }
       
   278             else
       
   279                 {
       
   280                 // call ISR
       
   281                 (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr);
       
   282                 }
       
   283             }
       
   284         ++index;
       
   285         pendingIrqs &gt;&gt;= 1;
       
   286         }
       
   287     }
       
   288 </codeblock><p>This example code illustrates a second level dispatcher
       
   289 bound directly to an interrupt source.</p><codeblock xml:space="preserve">void IrqDispatch()
       
   290     // MAIN IRQ DISPATCHER, FIRST-LEVEL INTERRUPT
       
   291     {
       
   292     TUint32 pendingIrqs = TheAssp::IrqPendingRegister();
       
   293 
       
   294     TInt index = 0;
       
   295     while( pendingIrqs )
       
   296         {
       
   297         if( pendingIrqs &amp; 1 )
       
   298             {
       
   299             (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr);
       
   300             }
       
   301         ++index;
       
   302         pendingIrqs &gt;&gt;= 1;
       
   303         }
       
   304     }
       
   305 void SecondLevelIrqDispatch( TAny* /* aParam */ )
       
   306     {
       
   307     TUint32 pendingIrqs = TheAssp::SecondLevelIrqPendingRegister();
       
   308  
       
   309     TInt index = EStartOfSecondLevelIntId;
       
   310     while( pendingIrqs )
       
   311         {
       
   312         if( pendingIrqs &amp; 1 )
       
   313             {
       
   314             (IsrHandlers[index].iIsr)(IsrHandlers[index].iPtr);
       
   315             }
       
   316         ++index;
       
   317         pendingIrqs &gt;&gt;= 1;
       
   318         }
       
   319     }
       
   320 void InitialiseSecondLevelDispatch()
       
   321     // Bind and enable the second-level dispatcher
       
   322     {
       
   323     Interrupt::Bind(EMainIntChainIrq,SecondLevelIrqDispatch,NULL);
       
   324     Interrupt::Enable( EMainIntChainIrq );
       
   325     }
       
   326 </codeblock><p>This example assumes an ISR table in which the second
       
   327 level interrupt ISRs begin at location 32 (<codeph>EStartOfSecondLevelIntId</codeph>). <codeph>EMainIntChainIrq</codeph> is the interrupt Id of the chained
       
   328 interrupt source to the main interrupt controller. The second level
       
   329 dispatcher is itself an ISR with an argument <codeph>TAny</codeph>* which is not needed in this example (possible uses are to distinguish
       
   330 between core and device specific ISR tables or to point to I/O addresses).</p></section>
       
   331 <section id="GUID-8953F8D5-8EA7-46B2-9030-A2932F06032F"><title>Multiple
       
   332 interrupt sources</title><p>In cases where multiple  peripherals are
       
   333 connected to the same interrupt source, multiple sources may generate
       
   334 the same interrupt which will then require a different ISR depending
       
   335 on the specific source. However, EKA2 does not allow binding of multiple
       
   336 ISRs to the same interrupt. There are two strategies for solving this
       
   337 problem, both of which involve assigning the multiple ISRs not to
       
   338 the real interrupt but to pseudo-interrupt Ids. In one strategy the
       
   339 dispatcher examines the hardware to determine where the interrupt
       
   340 originated and calls the appropriate ISR. In the other strategy, the
       
   341 ISRs are written so that they examine their peripheral hardware and
       
   342 only run if it is actually signalling an interrupt: in this strategy
       
   343 the dispatcher calls all the ISRs bound to the real interrupt but
       
   344 only one of them runs.</p><p>There is no requirement to extend the
       
   345 implementation of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-CCC9A397-608C-3EAF-830F-A59800C2E8E5"><apiname>Interrupt::Unbind()</apiname></xref> where multiple interrupt sources are
       
   346 involved.</p><p>Multiple interrupt sources require you to extend the
       
   347 implementation of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-BB169E6E-D8F9-3762-899D-6DBA4B29CF87"><apiname>Interrupt::Enable()</apiname></xref> and <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-2D14E023-E6ED-39BF-8B31-6FA510957A8A"><apiname>Interrupt::Disable()</apiname></xref> to enable and disable the true interrupt
       
   348 source.</p><p>The dispatch functions should be extended in the same
       
   349 way as with chained interrupts, using one of the two techniques described
       
   350 for that case.</p><p>The ISR table should be structured so that the
       
   351 interrupt Id identifies the hardware controller the interrupt is on.
       
   352 For instance the first 32 Ids might refer to the highest level controller,
       
   353 the next 32 to a second level controller and so on.</p></section>
       
   354 <section id="GUID-26850469-13E9-4A50-B6B0-946E317085AD"><title>Device
       
   355 specific interrupts</title><p>Interrupts generated by peripherals
       
   356 are sometimes routed to a GPIO pin and sometimes included in a variant
       
   357 layer. Where they are part of the variant layer, they must be listed
       
   358 in a separate ISR table which is part of the device implementation.
       
   359 However, we want device drivers to be able to use the Interrupt class
       
   360 functions on interrupts of either type. The solution is to write separate
       
   361 device specific functions derived from those of the core class. Core
       
   362 class functions are then written in such a way as to identify device
       
   363 specific interrupts and pass them on to the derived functions.</p><p>A recommended way of labelling interrupts as being device specific
       
   364 is to assign negative numbers as their Ids. The core functions can
       
   365 then identify negative Ids as belonging to device specific interrupts
       
   366 and pass them to the device specific derived functions. The device
       
   367 specific functions can convert them to positive numbers which serve
       
   368 as indexes to the device specific ISR table.</p><p>This example code
       
   369 illustrates device specific interrupt handling.</p><codeblock xml:space="preserve">EXPORT_C TInt Interrupt::Bind(TInt aId, TIsr aIsr, TAny* aPtr)
       
   370     {
       
   371     TInt r = KErrNone;
       
   372     if(aId &lt; 0 )
       
   373         {
       
   374         return MyAsic-&gt;VariantBind( aId, aIsr, aPtr ); // Device specific ID, call variant
       
   375         }
       
   376     else if (aId &gt;= KInterruptSourceCount)
       
   377             {
       
   378             r = KErrArgument; // Illegal interrupt number
       
   379             }
       
   380         else
       
   381             {
       
   382             SInterruptHandler&amp; h = IsrHandlers[aId];
       
   383             TInt irq = NKern::DisableAllInterrupts();
       
   384             if (h.iIsr != SpuriousHandler)
       
   385                 {
       
   386                 r = KErrInUse; // Already bound to an ISR
       
   387                 }
       
   388             else
       
   389                 {
       
   390                 h.iPtr = aPtr;
       
   391                 h.iIsr = anIsr;
       
   392                 }
       
   393             NKern::RestoreInterrupts(irq);
       
   394             }
       
   395     return r;
       
   396     }
       
   397 
       
   398 SInterruptHandler VariantHandlers[KNumVariantInts];
       
   399 EXPORT_C TInt TMyVariant::VariantBind(TInt aId, TIsr aIsr, TAny* aPtr)
       
   400     {
       
   401     TInt r = KErrNone;
       
   402     aId = (-aId)-1;    // convert to positive number &gt;=0
       
   403     If (aId &gt;= KInterruptSourceCount || aId &lt; 0)
       
   404         {
       
   405         r = KErrArgument; // Illegal interrupt number
       
   406         }
       
   407     else
       
   408         {
       
   409         SInterruptHandler&amp; h = VariantHandlers[aId];
       
   410         TInt irq = NKern::DisableAllInterrupts();
       
   411         if (h.iIsr != VariantSpuriousHandler)
       
   412             {
       
   413             r = KErrInUse; // Already bound to an ISR
       
   414             }
       
   415         else
       
   416             {
       
   417             h.iPtr = aPtr;
       
   418             h.iIsr = anIsr;
       
   419             }
       
   420         NKern::RestoreInterrupts(irq);
       
   421         }
       
   422     return r;
       
   423     }</codeblock><p>The example provides a version of <xref href="GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3.dita#GUID-E7A7083C-97B9-39B9-A147-4A6E314EE3A3/GUID-4E3CB472-3525-32F8-9BC4-8ECFEE931E7B"><apiname>Interrupt::Bind()</apiname></xref> which calls a variant layer function<codeph> VariantBind()</codeph> to process device specific interrupts (here assigned negative Ids)
       
   424 to ISRs held in the variant specific table <codeph>VariantHandlers</codeph>.</p></section>
       
   425 </conbody><related-links>
       
   426 <link href="GUID-654A788A-526A-4C3F-838C-05B09F0D5445.dita"><linktext>Interrupt
       
   427 Technology Guide</linktext></link>
       
   428 <link href="GUID-D0F5D40A-28D2-4A2E-9B40-180537E60F56.dita"><linktext>Interrupt
       
   429 Client Interface Guide</linktext></link>
       
   430 </related-links></concept>