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

Last change on this file since 200 was 159, checked in by sandervl, 24 years ago

irq sharing fix

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