source: sbliveos2/trunk/drv16/irq.cpp@ 302

Last change on this file since 302 was 205, checked in by stevenhl, 18 years ago

Make warnings away - SHL
Use drv16/midi_idc.h only - SHL
Add interrupts 16-23 - MF

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/* $Id: irq.cpp 205 2007-06-14 01:33:51Z stevenhl $ */
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 NumIrqLevels = 24;
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[ NumIrqLevels ] = { 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.
40void far ISR03( void ) { pIrqObject[ 3]->CallHandlers(); }
41void far ISR04( void ) { pIrqObject[ 4]->CallHandlers(); }
42void far ISR05( void ) { pIrqObject[ 5]->CallHandlers(); }
43void far ISR07( void ) { pIrqObject[ 7]->CallHandlers(); }
44void far ISR09( void ) { pIrqObject[ 9]->CallHandlers(); }
45void far ISR10( void ) { pIrqObject[10]->CallHandlers(); }
46void far ISR11( void ) { pIrqObject[11]->CallHandlers(); }
47void far ISR12( void ) { pIrqObject[12]->CallHandlers(); }
48void far ISR13( void ) { pIrqObject[13]->CallHandlers(); }
49void far ISR14( void ) { pIrqObject[14]->CallHandlers(); }
50void far ISR15( void ) { pIrqObject[15]->CallHandlers(); }
51// 13 Jun 07 MF
52void far ISR16( void ) { pIrqObject[16]->CallHandlers(); }
53void far ISR17( void ) { pIrqObject[17]->CallHandlers(); }
54void far ISR18( void ) { pIrqObject[18]->CallHandlers(); }
55void far ISR19( void ) { pIrqObject[19]->CallHandlers(); }
56void far ISR20( void ) { pIrqObject[20]->CallHandlers(); }
57void far ISR21( void ) { pIrqObject[21]->CallHandlers(); }
58void far ISR22( void ) { pIrqObject[22]->CallHandlers(); }
59void far ISR23( void ) { pIrqObject[23]->CallHandlers(); }
60
61// List of handlers here.
62typedef void (NEAR *pfnISR)(void);
63static pfnISR pISR[NumIrqLevels] = {
64 NULL,
65 NULL,
66 NULL,
67 (pfnISR) ISR03,
68 (pfnISR) ISR04,
69 (pfnISR) ISR05,
70 NULL,
71 (pfnISR) ISR07,
72 NULL,
73 (pfnISR) ISR09,
74 (pfnISR) ISR10,
75 (pfnISR) ISR11,
76 (pfnISR) ISR12,
77 (pfnISR) ISR13,
78 (pfnISR) ISR14,
79 (pfnISR) ISR15,
80 // 13 Jun 07 MF
81 (pfnISR) ISR16,
82 (pfnISR) ISR17,
83 (pfnISR) ISR18,
84 (pfnISR) ISR19,
85 (pfnISR) ISR20,
86 (pfnISR) ISR21,
87 (pfnISR) ISR22,
88 (pfnISR) ISR23
89};
90
91
92/**@external pMakeIRQ
93 * Returns a pointer to the IRQ object which manages the IRQ for a given
94 * level.
95 * @param unsigned irq_level - the irq level of interest.
96 * @return IRQ* pIRQ - pointer to the IRQ object for named level.
97 * @notes This routine makes sure that we make exactly one IRQ for an
98 * interrupt level.
99 */
100IRQ* pMakeIRQ( unsigned irq_level )
101{
102 if ( ! pIrqObject[irq_level] )
103 new IRQ( irq_level );
104 return pIrqObject[ irq_level ];
105}
106
107
108IRQ* getIRQ( unsigned irq_level )
109{
110 if ( ! pIrqObject[irq_level] )
111 return 0;
112 return pIrqObject[ irq_level ];
113}
114
115/**@internal IRQ::IRQ
116 * Constructor for an IRQ object.
117 * @notes This method should never be called by a client, the pMakeIRQ()
118 * function should be used instead. pMakeIRQ ensures that we have no
119 * more than one IRQ object per level.
120 */
121IRQ::IRQ( unsigned irq_level )
122{
123 // 13 Jun 07 SHL
124 _fmemset( (PVOID) this, 0, sizeof(IRQ) ); // Set all data to 0.
125 _usIRQLevel = irq_level;
126 pIrqObject[ _usIRQLevel ] = this;
127}
128
129
130IRQ::~IRQ(void)
131{
132 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
133
134 // Remove object from global array.
135 pIrqObject[ _usIRQLevel ] = NULL;
136
137 // Remove all registered handlers. Quit when find NULL
138 // entry. Array is guaranteed to be terminated with a NULL entry.
139 for ( pEntry=_handlerList; pEntry->pfnHandler; ++pEntry )
140 bRemoveHandler( pEntry->pfnHandler );
141}
142
143
144BOOL IRQ::bAddHandler( PFN_InterruptHandler pfn )
145{
146 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
147
148 // If the handler is already registered on this level, done.
149 if ( _pFindHandler( pfn ) )
150 return TRUE;
151
152 pEntry = _pFindHandler( NULL ); // Find an empty slot.
153 if (! pEntry) return FALSE; // None available.
154
155 // Set up new slot. No serialization needed, entry is disabled.
156 pEntry->bEnabled = FALSE; // Sanity check - ensure entry is disabled.
157 pEntry->pfnHandler = pfn; // Save pointer to handler.
158 return TRUE; // Done.
159}
160
161
162BOOL IRQ::bEnableHandler ( PFN_InterruptHandler pfn )
163{
164 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
165
166 pEntry = _pFindHandler( pfn );
167 if (! pEntry) return FALSE; // Can't find it.
168
169 if ( pEntry->bEnabled ) // Already running.
170 return TRUE;
171
172 pEntry->bEnabled = TRUE; // Enable handler.
173 ++ _nEnabled; // Bump count of active handlers.
174
175 // If we just changed from none enabled to 1 enabled, turn on Interrupt.
176 // SvL: TODO: DOES NOT WORK FOR ISA CARDS!!!!!!!!!! (shared irq)
177 if ( _nEnabled == 1 ) {
178 USHORT uResult =
179 DevHelp_SetIRQ( (NPFN) pISR[ _usIRQLevel ],
180 _usIRQLevel,
181 1 ); // first try shared shared
182 if (uResult != 0) { // If error ...
183 uResult = DevHelp_SetIRQ( (NPFN) pISR[ _usIRQLevel ],
184 _usIRQLevel,
185 0 ); // failed, so try exclusive instead
186
187 if (uResult != 0) { // If error ...
188 -- _nEnabled;
189 pEntry->bEnabled = FALSE;
190 return FALSE;
191 }
192 }
193 }
194
195 return TRUE;
196}
197
198BOOL IRQ::bDisableHandler ( PFN_InterruptHandler pfn )
199{
200 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
201
202 pEntry = _pFindHandler( pfn );
203 if (! pEntry) return FALSE; // Can't find it.
204
205 if (! pEntry->bEnabled ) // Already disabled.
206 return TRUE;
207
208 pEntry->bEnabled = FALSE; // Disable handler.
209 -- _nEnabled; // Bump down count of active handlers.
210
211 // If we just changed from 1 enabled to 0 enabled, turn off Interrupt.
212 if ( _nEnabled == 0 )
213 DevHelp_UnSetIRQ( _usIRQLevel );
214
215 return TRUE;
216}
217
218
219
220BOOL IRQ::bRemoveHandler( PFN_InterruptHandler pfn )
221{
222 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
223 ISR_Entry* pLastEntry; // Points to last handler entry in array.
224
225 pEntry = _pFindHandler( pfn );
226 if (! pEntry) return FALSE;
227 if (! bDisableHandler( pfn )) return FALSE;
228
229 /* If this is the last entry in the array, just zero the slot. If this
230 ; entry is in the middle of the array, then move the last entry in the
231 ; list into this slot that is being freed. We guarantee that the ISR's
232 ; are contiguous in the array and cannot put a NULL entry in the middle.
233 */
234
235 // Find last entry in the array.
236 for ( pLastEntry=pEntry; pLastEntry->pfnHandler; ++pLastEntry )
237 ;
238 --pLastEntry;
239
240 // If 'pfn' wasn't at end of the list, move end of list into this slot.
241 if ( pLastEntry != pEntry) {
242 // If we don't cli/sti here, we could lose an interrupt.
243 cli();
244 *pEntry = *pLastEntry; // Copy down entry.
245 pLastEntry->bEnabled = 0; // Disable last slot.
246 pLastEntry->pfnHandler = NULL; // Zero out last slot.
247 sti();
248 } else { // Else the entry selected for deletion is the
249 // last entry in list; no need to move anything.
250 pEntry->bEnabled = FALSE; // Disable this slot (redundant to DisableHandler).
251 pEntry->pfnHandler = NULL; // Zero out the slot.
252 }
253 return TRUE;
254}
255
256
257ISR_Entry* IRQ::_pFindHandler( PFN_InterruptHandler pfn )
258/*
259; Finds named handler in __handlerList[]. Returns pointer to ISR_Entry
260; if found, NULL otherwise.
261*/
262{
263 ISR_Entry* pEntry; // Pointer into array of int handlers for this IRQ.
264
265 // Walk array, looking for named handler function.
266 for ( pEntry=_handlerList;
267 pEntry != &_handlerList[MAX_HandlersPerIRQLevel]; ++pEntry )
268 if ( pfn == pEntry->pfnHandler )
269 return pEntry;
270
271 // If we got here, we didn't find the entry. Return NULL.
272 return NULL;
273}
274
275
276void IRQ::CallHandlers ( void )
277/*
278; Receives interrupt from ISR, then calls out to registered handlers.
279; Runs in interrupt context.
280*/
281{
282 USHORT i; // Indexes through ISR's in _handlerList.
283 USHORT retry; // Retry count.
284
285 for (retry=0; retry < _nEnabled; ++retry) {
286 // Call all enabled handlers. Stop when find NULL entry (end of list).
287 for ( i=0; _handlerList[i].pfnHandler; ++i ) {
288 if ( _handlerList[i].bEnabled ) { // If handler enabled...
289 if (_handlerList[i].pfnHandler(_usIRQLevel)) { // Call handler.
290 cli();
291 // We've cleared all service requests. Send EOI and clear
292 // the carry flag (tells OS/2 kernel that Int was handled).
293 DevHelp_EOI( _usIRQLevel );
294 clc();
295 sti();
296 return;
297 }
298 }
299 }
300 }
301 // Indicate Interrupt not serviced by setting carry flag before
302 // returning to OS/2 kernel. OS/2 will then shut down the interrupt!
303 // NOTE: Make sure interrupts are not turned on again when this irq isn't ours!
304 stc();
305}
306
307
Note: See TracBrowser for help on using the repository browser.