source: cmedia/trunk/Drv16/irq.cpp

Last change on this file was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 9.9 KB
Line 
1/* $Id: irq.cpp,v 1.3 2001/03/13 20:11:06 sandervl Exp $ */
2
3/* SCCSID = %W% %E% */
4/****************************************************************************
5 * *
6 * Copyright (c) IBM Corporation 1994 - 1997. *
7 * *
8 * The following IBM OS/2 source code is provided to you solely for the *
9 * the purpose of assisting you in your development of OS/2 device drivers. *
10 * You may use this code in accordance with the IBM License Agreement *
11 * provided in the IBM Device Driver Source Kit for OS/2. *
12 * *
13 ****************************************************************************/
14/**@internal %W%
15 * IRQ object implementation.
16 * @version %I%
17 * @context
18 * Unless otherwise noted, all interfaces are Ring-0, 16-bit, kernel stack.
19 * @notes
20 * Refer to .HPP file for interface rules.
21 * @history
22 */
23
24#include <devhelp.h>
25#include <include.h>
26#include <string.h> // memset()
27#include "irq.hpp" // Object definition
28
29const int NumIrqSlots = 4;
30
31
32// We need a global array to keep track of the IRQ objects that have been created.
33// The interrupt-time ISR uses this array to find the object associated with
34// interrupt level "i". IRQ "i" is at position "i" in array.
35
36static IRQ* pIrqObject[ NumIrqSlots ] = { 0 };
37
38// These are the ISR's that take the interrupt from the kernel. We've
39// defined handlers only for the IRQ's supported by this sound card.
40/*
41void far ISR03( void ) { pIrqObject[ 3]->CallHandlers(); }
42void far ISR04( void ) { pIrqObject[ 4]->CallHandlers(); }
43void far ISR05( void ) { pIrqObject[ 5]->CallHandlers(); }
44void far ISR07( void ) { pIrqObject[ 7]->CallHandlers(); }
45void far ISR09( void ) { pIrqObject[ 9]->CallHandlers(); }
46void far ISR10( void ) { pIrqObject[10]->CallHandlers(); }
47void far ISR11( void ) { pIrqObject[11]->CallHandlers(); }
48void far ISR12( void ) { pIrqObject[12]->CallHandlers(); }
49void far ISR13( void ) { pIrqObject[13]->CallHandlers(); }
50void far ISR14( void ) { pIrqObject[14]->CallHandlers(); }
51void far ISR15( void ) { pIrqObject[15]->CallHandlers(); }
52*/
53
54
55void far ISR00( void ) { pIrqObject[0]->CallHandlers(); }
56void far ISR01( void ) { pIrqObject[1]->CallHandlers(); }
57void far ISR02( void ) { pIrqObject[2]->CallHandlers(); }
58void far ISR03( void ) { pIrqObject[3]->CallHandlers(); }
59
60
61// List of handlers here.
62
63static NPFN pISR[NumIrqSlots] = {
64 (NPFN) ISR00,
65 (NPFN) ISR01,
66 (NPFN) ISR02,
67 (NPFN) ISR03,
68};
69
70
71/**@external pMakeIRQ
72 * Returns a pointer to the IRQ object which manages the IRQ for a given
73 * level.
74 * @param unsigned irq_level - the irq level of interest.
75 * @return IRQ* pIRQ - pointer to the IRQ object for named level.
76 * @notes This routine makes sure that we make exactly one IRQ for an
77 * interrupt level.
78 */
79IRQ* pMakeIRQ( unsigned irq_level )
80{
81 int i;
82 IRQ* pIRQ = getIRQ(irq_level);
83
84 if( !pIRQ )
85 {
86 for( i = 0; i < NumIrqSlots; i++ )
87 if( !pIrqObject[i] ) return new IRQ( irq_level, i );
88 }
89
90 return pIRQ;
91}
92
93
94IRQ* getIRQ( unsigned irq_level )
95{
96 int i;
97 IRQ* pIRQ;
98
99 for( i = 0; i < NumIrqSlots; i++ )
100 {
101 pIRQ = pIrqObject[i];
102 if( pIRQ && pIRQ->QueryLevel() == irq_level ) return pIRQ;
103 }
104
105 return NULL;
106}
107
108/**@internal IRQ::IRQ
109 * Constructor for an IRQ object.
110 * @notes This method should never be called by a client, the pMakeIRQ()
111 * function should be used instead. pMakeIRQ ensures that we have no
112 * more than one IRQ object per level.
113 */
114IRQ::IRQ( unsigned irq_level, unsigned slot_no )
115{
116 memset( (void *)this, 0, sizeof(IRQ) ); // Set all data to 0.
117 _usIRQLevel = irq_level;
118 _usSlotNo = slot_no;
119 pIrqObject[slot_no] = this;
120}
121
122
123IRQ::~IRQ(void)
124{
125 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
126
127 // Remove object from global array.
128 pIrqObject[ _usSlotNo ] = NULL;
129
130 // Remove all registered handlers. Quit when find NULL
131 // entry. Array is guaranteed to be terminated with a NULL entry.
132 for ( pEntry=_handlerList; pEntry->pfnHandler; ++pEntry )
133 bRemoveHandler( pEntry->pfnHandler );
134}
135
136
137BOOL IRQ::bAddHandler( PFN_InterruptHandler pfn, unsigned long userdata )
138{
139 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
140
141 // If the handler is already registered on this level, done.
142 if ( _pFindHandler( pfn ) )
143 return TRUE;
144
145 pEntry = _pFindHandler( NULL ); // Find an empty slot.
146 if (! pEntry) return FALSE; // None available.
147
148 // Set up new slot. No serialization needed, entry is disabled.
149 pEntry->bEnabled = FALSE; // Sanity check - ensure entry is disabled.
150 pEntry->pfnHandler = pfn; // Save pointer to handler.
151 pEntry->ulParam = userdata;
152 return TRUE; // Done.
153}
154
155
156BOOL IRQ::bEnableHandler ( PFN_InterruptHandler pfn )
157{
158 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
159
160 pEntry = _pFindHandler( pfn );
161 if (! pEntry) return FALSE; // Can't find it.
162
163 if ( pEntry->bEnabled ) // Already running.
164 return TRUE;
165
166 pEntry->bEnabled = TRUE; // Enable handler.
167 ++ _nEnabled; // Bump count of active handlers.
168
169 // If we just changed from none enabled to 1 enabled, turn on Interrupt.
170 // SvL: TODO: DOES NOT WORK FOR ISA CARDS!!!!!!!!!! (shared irq)
171 if ( _nEnabled == 1 ) {
172 USHORT uResult =
173 DevHelp_SetIRQ( pISR[ _usSlotNo ],
174 _usIRQLevel,
175 1 ); // first try shared shared
176 if (uResult != 0) { // If error ...
177 uResult = DevHelp_SetIRQ( pISR[ _usSlotNo ],
178 _usIRQLevel,
179 0 ); // failed, so try exclusive instead
180
181 if (uResult != 0) { // If error ...
182 -- _nEnabled;
183 pEntry->bEnabled = FALSE;
184 return FALSE;
185 }
186 }
187 }
188
189 return TRUE;
190}
191
192BOOL IRQ::bDisableHandler ( PFN_InterruptHandler pfn )
193{
194 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
195
196 pEntry = _pFindHandler( pfn );
197 if (! pEntry) return FALSE; // Can't find it.
198
199 if (! pEntry->bEnabled ) // Already disabled.
200 return TRUE;
201
202 pEntry->bEnabled = FALSE; // Disable handler.
203 -- _nEnabled; // Bump down count of active handlers.
204
205 // If we just changed from 1 enabled to 0 enabled, turn off Interrupt.
206 if ( _nEnabled == 0 )
207 DevHelp_UnSetIRQ( _usIRQLevel );
208
209 return TRUE;
210}
211
212
213
214BOOL IRQ::bRemoveHandler( PFN_InterruptHandler pfn )
215{
216 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
217 ISR_Entry* pLastEntry; // Points to last handler entry in array.
218
219 pEntry = _pFindHandler( pfn );
220 if (! pEntry) return FALSE;
221 if (! bDisableHandler( pfn )) return FALSE;
222
223 /* If this is the last entry in the array, just zero the slot. If this
224 ; entry is in the middle of the array, then move the last entry in the
225 ; list into this slot that is being freed. We guarantee that the ISR's
226 ; are contiguous in the array and cannot put a NULL entry in the middle.
227 */
228
229 // Find last entry in the array.
230 for ( pLastEntry=pEntry; pLastEntry->pfnHandler; ++pLastEntry )
231 ;
232 --pLastEntry;
233
234 // If 'pfn' wasn't at end of the list, move end of list into this slot.
235 if ( pLastEntry != pEntry) {
236 // If we don't cli/sti here, we could lose an interrupt.
237 cli();
238 *pEntry = *pLastEntry; // Copy down entry.
239 pLastEntry->bEnabled = 0; // Disable last slot.
240 pLastEntry->pfnHandler = NULL; // Zero out last slot.
241 sti();
242 } else { // Else the entry selected for deletion is the
243 // last entry in list; no need to move anything.
244 pEntry->bEnabled = FALSE; // Disable this slot (redundant to DisableHandler).
245 pEntry->pfnHandler = NULL; // Zero out the slot.
246 }
247 return TRUE;
248}
249
250
251ISR_Entry* IRQ::_pFindHandler( PFN_InterruptHandler pfn )
252/*
253; Finds named handler in __handlerList[]. Returns pointer to ISR_Entry
254; if found, NULL otherwise.
255*/
256{
257 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
258
259 // Walk array, looking for named handler function.
260 for ( pEntry=_handlerList;
261 pEntry != &_handlerList[MAX_HandlersPerIRQLevel]; ++pEntry )
262 if ( pfn == pEntry->pfnHandler )
263 return pEntry;
264
265 // If we got here, we didn't find the entry. Return NULL.
266 return NULL;
267}
268
269
270void IRQ::CallHandlers ( void )
271/*
272; Receives interrupt from ISR, then calls out to registered handlers.
273; Runs in interrupt context.
274*/
275{
276 USHORT i; // Indexes through ISR's in _handlerList.
277 USHORT retry; // Retry count.
278
279 for (retry=0; retry < _nEnabled; ++retry) {
280 // Call all enabled handlers. Stop when find NULL entry (end of list).
281 for ( i=0; _handlerList[i].pfnHandler; ++i ) {
282 if ( _handlerList[i].bEnabled ) { // If handler enabled...
283 if (_handlerList[i].pfnHandler(_usIRQLevel,
284 _handlerList[i].ulParam )) { // Call handler.
285 cli();
286 // We've cleared all service requests. Send EOI and clear
287 // the carry flag (tells OS/2 kernel that Int was handled).
288 DevHelp_EOI( _usIRQLevel );
289// Rudi: done by DevHelp_EOI clc();
290// Rudi: avoid interrupt nesting sti();
291 return;
292 }
293 }
294 }
295 }
296 // Indicate Interrupt not serviced by setting carry flag before
297 // returning to OS/2 kernel. OS/2 will then shut down the interrupt!
298 // NOTE: Make sure interrupts are not turned on again when this irq isn't ours!
299 stc();
300}
301
302
Note: See TracBrowser for help on using the repository browser.