diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-8B7E2A72-B793-5E70-87F0-92AA0A482F23.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-8B7E2A72-B793-5E70-87F0-92AA0A482F23.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,165 @@ + + + + + +Interrupt::Bind() +and Interrupt::Unbind() Describes two types of configuration used in the implementation +of bind and unbind functions. +

The functions Interrupt::Bind() and Interrupt::Unbind() provide +device drivers with a way of binding ISRs to interrupt sources, and unbinding +ISRs from interrupt sources. The implementation of these functions follows +a standard pattern that can be re-used in most cases.

+

The implementation can be different if there is a single Variant DLL, or +if there is also an ASSP extension.

+
Variant DLL only configuration

The following example +implementation of Interrupt::Bind() assumes that all ISRs +in the ISR table have been bound, by default, to the spurious interrupts handler function as done in initialising +the table. To bind an interrupt source, the spurious interrupts handler +is replaced with the provided ISR. The implementation prevents an ISR from +being bound to an interrupt source that is already bound, by assuming that +an unbound interrupt source is bound to the spurious interrupts handler.

The +implementation shows the basic idea but may need to be extended, especially +where chained +interrupts and/or multiple +interrupt sources and pseudo interrupt sources are involved.

EXPORT_C TInt Interrupt::Bind(TInt aId, TIsr aIsr, TAny* aPtr) + { + TInt r = KErrNone; + If(TUint(aId)>=TUint(KInterruptSourceCount)) + { + r = KErrArgument; // Illegal interrupt number + } + else + { + SInterruptHandler& h = IsrHandlers[aId]; + TInt irq = NKern::DisableAllInterrupts(); + if (h.iIsr != &SpuriousHandler) + { + r = KErrInUse; // Already bound to an ISR + } + else + { + h.iPtr = aPtr; // The ISR parameter + h.iIsr = aIsr; // Pointer to the ISR + } + NKern::RestoreInterrupts(irq); + } + return r; + } +

Interrupt::Unbind() is the logical opposite +of Bind(), replacing the ISR with the spurious handler function. +The following code is the matching example implementation.

EXPORT_C TInt Interrupt::Unbind(TInt aId) + { + TInt r = KErrNone; + if (TUint(aId) >= TUint(KInterruptSourceCount)) + { + r = KErrArgument; // Illegal interrupt number + } + else + { + SInterruptHandler& h = IsrHandlers[aId]; + TInt irq = NKern::DisableAllInterrupts(); + if (h.iIsr == &SpuriousHandler) + { + r = KErrGeneral; // Already unbound + } + else + { + h.iPtr =(TAny*)aId; + h.iIsr = SpuriousHandler; // Replace with spurious handler + // NOTE: at this point it may be wise to + // force the hardware interrupt source to disabled. + } + NKern::RestoreInterrupts(irq); + } + return r; + } +

Note that functions in the Interrupt class +can be called from anywhere in kernel-side code, including ISRs, DFCs and +IDFCs, and kernel threads. You need to ensure that if you are manipulating +the ISR table, or any other structure that is shared, you need to disable interrupts +to prevent corruption of the data. Interrupts are disabled and re-enabled +using NKern::DisableAllInterrupts() and NKern::RestoreInterrupts().

+
ASSP Extension and Variant DLL configuration

When +a common ASSP extension is used, the Variant DLL may have to implement extra +interrupt binding and dispatch functions for the device-specific interrupts.

The +following code is an example of an implementation of Interrupt::Bind() in +the ASSP layer, where negative Interrupt IDs represent device specific interrupts.

EXPORT_C TInt Interrupt::Bind(TInt aId, TIsr aIsr, TAny* aPtr) + { + TInt r = KErrNone; + if(aId < 0 ) + { + return MyAsic->VariantBind( aId, aIsr, aPtr ); // Device specific ID, call variant + } + else if (aId >= KInterruptSourceCount) + { + r = KErrArgument; // Illegal interrupt number + } + else + { + SInterruptHandler& h = IsrHandlers[aId]; + TInt irq = NKern::DisableAllInterrupts(); + if (h.iIsr != SpuriousHandler) + { + r = KErrInUse; // Already bound to an ISR + } + else + { + h.iPtr = aPtr; + h.iIsr = anIsr; + } + NKern::RestoreInterrupts(irq); + } + return r; + }

The default device specific implementation of the VariantBind() function +might be as follows:

TInt TMyAsic::VariantBind( TInt aId, TIsr aIsr, TAny* aPtr ) + // Default implementation when device specific layer does not override + // and this is therefore an illegal aId. + { + return KErrArgument; + } +

The device specific implementation of VariantBind() would +follow the same general pattern as for the Interrupt::Bind() function +in the ASSP layer. The main difference is that the code refers to the device +specific ISR table, VariantHandlers[], defined within the +device specific layer, and the interrupt ID is converted to a positive number +so that it can be used as an index into this table:

SInterruptHandler VariantHandlers[KNumVariantInts]; EXPORT_C TInt TMyVariant::VariantBind(TInt aId, TIsr aIsr, TAny* aPtr) + { + TInt r = KErrNone; + aId = (-aId)-1; // convert to positive number >=0 + If (aId >= KInterruptSourceCount || aId < 0) + { + r = KErrArgument; // Illegal interrupt number + } + else + { + SInterruptHandler& h = VariantHandlers[aId]; + TInt irq = NKern::DisableAllInterrupts(); + if (h.iIsr != VariantSpuriousHandler) + { + r = KErrInUse; // Already bound to an ISR + } + else + { + h.iPtr = aPtr; + h.iIsr = anIsr; + } + NKern::RestoreInterrupts(irq); + } + return r; + }

Now you need a way of dispatching the interrupts and +since this is really a chained interrupt, the dispatch function can be packaged +as an ISR and bound to the core interrupt source it chains from. See IRQ and FIQ Dispatchers in +general and Dealing +with chained interrupts in particular.

+
+ +Interrupts in the split ASSP/Variant Configuration + +
\ No newline at end of file