diff -r 4816d766a08a -r f345bda72bc4 Symbian3/PDK/Source/GUID-8B7E2A72-B793-5E70-87F0-92AA0A482F23.dita --- a/Symbian3/PDK/Source/GUID-8B7E2A72-B793-5E70-87F0-92AA0A482F23.dita Tue Mar 30 11:42:04 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-8B7E2A72-B793-5E70-87F0-92AA0A482F23.dita Tue Mar 30 11:56:28 2010 +0100 @@ -1,165 +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 - + + + + + +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