Subversion Repositories f9daq

Rev

Rev 19 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
19 f9daq 1
//-------------------------------------------------------------------------
2
// WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
3
// all around irq handling
4
//
5
// (c) 1999-2004 ARW Elektronik
6
//
7
// this source code is published under GPL (Open Source). You can use, redistrubute and 
8
// modify it unless this header   is not modified or deleted. No warranty is given that 
9
// this software will work like expected.
10
// This product is not authorized for use as critical component in life support systems
11
// wihout the express written approval of ARW Elektronik Germany.
12
//
13
// Please announce changes and hints to ARW Elektronik
14
//
15
// $Log: pcivme_i.c,v $
16
// Revision 1.3  2004/07/24 07:07:26  klaus
17
// Update copyright to 2004
18
//
19
// Revision 1.2  2003/11/15 19:12:50  klaus
20
// Update copyright to 2003
21
//
22
// Revision 1.1.1.1  2003/11/14 23:16:33  klaus
23
// First put into repository
24
//
25
// Revision 1.3  2002/10/27 16:17:48  klaus
26
// Typing bug fixed caused at log addition
27
//
28
// Revision 1.2  2002/10/27 16:11:02  klaus
29
// Added CVS log into header
30
//
31
// what                                            who          when
32
// started                                         AR           01.08.1999
33
// first release 1.0                                                       AR                   17.10.1999
34
// IoConnectInterrupt, share vector now true       AR           04.03.2000
35
// changed resource allocation caused by WIN2000   AR           08.06.2002
36
//
37
 
38
//-------------------------------------------------------------------------
39
// COMMENTS
40
//
41
// Each path (file_obj) maintains its own FIFO to hold incoming vector from
42
// hardware acknowledged interrupts. These FIFOs are always accessible for read
43
// while the path is open. In case a path enables its interrupts the link to 
44
// its FIFO is included in a list of "interrupt enabled" FIFOs. The opposite 
45
// happens when a path disables its interrupts.
46
// There are up to MAX_PCIADA lists of "interrupt enabled" FIFOs, each list is
47
// associated to a PCIADA (pciada). 
48
// Each time a pciada receives a interrupt request the software first checks
49
// for a bus error interrupt. This kind of requests are directly associated with
50
// a user initiated access and put forward to the accessor. (Excluding spurious
51
// interrupts). If the request is no bus error request the vector is pushed
52
// into all FIFOs queued for this PCIADA.
53
// After this a DPC call is fired to wake up queued IRPs waiting for a vector.
54
// The DPC call iterates through the list of FIFOs and looks if a queued IRP
55
// exists for this path. If so the vector is pulled off the FIFO and the IRP 
56
// is released.
57
// If a IRP arrives to request a vector the driver checks if there is a vector
58
// stored in the path associated FIFO. If so the IRP returns immediately with
59
// the pulled vector from the FIFO. If not the IRP is queued in a PCIADA 
60
// associated queue of pending IRPs.
61
// When the interrupts for a path are disabled all pending vectors in the FIFO
62
// associated with this path are still available. But if the FIFO is empty
63
// request to get the next vector will block.
64
 
65
//-------------------------------------------------------------------------
66
// INCLUDES
67
//
68
#include <ntddk.h>
69
#include <pcivme_drv.h>
70
#include <pcivme_i.h>
71
#include <pcivme.h>
72
#include <pciif.h>
73
#include <pcivme_fifo.h>
74
 
75
//------------------------------------------------------------------------
76
// DEFINES
77
//
78
#ifndef DWORD
79
#define DWORD ULONG
80
#endif
81
 
82
#ifndef WORD
83
#define WORD USHORT
84
#endif
85
 
86
//------------------------------------------------------------------------
87
// GLOBALS
88
//
89
 
90
//------------------------------------------------------------------------
91
// FUNCTIONS
92
//
93
 
94
//------------------------------------------------------------------------
95
// determine which interrupt and evaluates vector
96
//
97
static UCHAR evaluate_vector(PCIADA *pciada)
98
{
99
        USHORT  wIntCSR = READ_REGISTER_USHORT(pciada->pwIntCSR);
100
    USHORT  offset;
101
        USHORT  wCntrl = READ_REGISTER_USHORT(pciada->pwCntrl);
102
 
103
    if (wCntrl & 0x100)   // pciada switched on ?
104
        {
105
                if ((wIntCSR & 0x68) == 0x68)
106
                {
107
                        // it's the pci interrupt # 2
108
 
109
                        // get current Cntrl - and clear interrupt
110
                        wCntrl &= ~0x0100;  // disable
111
                        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
112
                        wCntrl |= 0x0100;   // enable again
113
                        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
114
                        return 1;
115
                }
116
 
117
                if ((wIntCSR & 0x45) == 0x45)
118
                {
119
                        // it's the interrupt # 1
120
                        offset = READ_REGISTER_USHORT(pciada->pwIRQStat);
121
 
122
                        if (offset & 1)
123
                                return 0xff & READ_REGISTER_UCHAR((PUCHAR)pciada->pbVector + offset);
124
                }
125
        }
126
 
127
        return 0;
128
}
129
 
130
//------------------------------------------------------------------------
131
// enable and disable of interrupts
132
//
133
void globalInterruptEnable(PCIADA *pciada)
134
{
135
   WRITE_REGISTER_USHORT(pciada->pwIntCSR, ENABLE_PCIADA_IRQS);
136
}
137
 
138
void globalInterruptDisable(PCIADA *pciada)
139
{
140
   WRITE_REGISTER_USHORT(pciada->pwIntCSR, DISABLE_PCIADA_IRQS);
141
}
142
 
143
//------------------------------------------------------------------------
144
// insert the vector in a queue of interrupts (and rescue waiting IRPs)
145
//
146
static void InsertInIrqQueues(PCIADA *pciada, UCHAR vector)
147
{
148
        FIFO_LIST   *next;
149
        KIRQL           oldIrqlList;
150
        register PLIST_ENTRY pList = &pciada->IrqListList;
151
 
152
        KdPrint(("InsertInIrqQueues\n"));
153
 
154
        // iterate all fifos and insert the vector in each fifo
155
        KeAcquireSpinLock(&pciada->IrqListLock, &oldIrqlList);
156
 
157
        while (pList->Flink != &pciada->IrqListList)
158
        {
159
                pList = pList->Flink;
160
                next = CONTAINING_RECORD(pList, FIFO_LIST, entry);
161
 
162
                KdPrint(("Vector %d pushed\n", vector));
163
 
164
                // push the vector into the fifo
165
                PushElement(next->pIrqListHandle, vector);
166
        }
167
 
168
        KeReleaseSpinLock(&pciada->IrqListLock, oldIrqlList);
169
 
170
        // more handling in the deffered procedure call
171
        KeInsertQueueDpc(&pciada->kDPCobj, (PVOID)pciada, (PVOID)&vector);
172
}
173
 
174
//------------------------------------------------------------------------
175
// main interrupt handler function
176
//
177
BOOLEAN irq_service(PKINTERRUPT Interrupt, PVOID ServiceContext)
178
{
179
        PCIADA *pciada = (PCIADA *)ServiceContext;
180
        UCHAR  vector;
181
        UNREFERENCED_PARAMETER(Interrupt);
182
        vector = evaluate_vector(pciada);
183
        if (!(vector)) return FALSE;
184
 
185
        KdPrint(("irq_service: %d\n", vector & 0xff));
186
 
187
        if ((pciada->pbBusError) && ((vector == 7) || (vector == 1)))
188
                *pciada->pbBusError = TRUE;
189
    else
190
                InsertInIrqQueues(pciada, vector); // insert at top of the queues
191
 
192
        return TRUE;
193
}
194
 
195
//------------------------------------------------------------------------
196
//  translate interrupt resources for PCIADAs to neutral ones
197
//
198
NTSTATUS PCIVMETranslateInterrupts(PDEVICE_OBJECT device_Obj)
199
{
200
        int              i;
201
        NTSTATUS         result = STATUS_SUCCESS;
202
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
203
        int                              nPCIADAs = pDevExt->nPCIADAs;
204
        PCIADA           *pciada  = (PCIADA *) NULL;
205
 
206
    KdPrint(("TranslateInterrupt()\n"));
41 f9daq 207
        if (nPCIADAs) return STATUS_SUCCESS;
19 f9daq 208
 
209
        for (i = 0; i < nPCIADAs; i++)
210
        {
211
                pciada = &pDevExt->pciada[i];
212
 
213
                KdPrint(("In  - Bus:%d, IrqLine:%d\n", pciada->Bus, pciada->Irql));
214
 
215
                if (pciada->Irql)
216
                {
217
                        pciada->Vector = HalGetInterruptVector(PCIBus, pciada->Bus,
218
                                pciada->Irql,
219
                                        pciada->Vector,
220
                                                &pciada->Irql, &pciada->Affinity);
221
                }
222
                else
223
                        result = STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
224
        }
225
 
226
        KdPrint(("Out - Irql:%d, Vector: %d, Affinity:%d\n", pciada->Irql, pciada->Vector, pciada->Affinity));
227
 
228
        return result;
229
}
230
 
231
//------------------------------------------------------------------------
232
//  connect service routines to all PCIADA interrupts
233
//
234
NTSTATUS PCIVMEConnectInterrupt(PDEVICE_OBJECT device_Obj)
235
{
236
        int              i;
237
        NTSTATUS         result = STATUS_SUCCESS;
238
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
239
        int                              nPCIADAs = pDevExt->nPCIADAs;
240
        PCIADA           *pciada;
241
 
242
    KdPrint(("ConnectInterrupt()\n"));
243
 
244
        // connect the interrupts to service routines
245
        for (i = 0; i < nPCIADAs; i++)
246
        {
247
      pciada = &pDevExt->pciada[i];
248
 
249
          pciada->InterruptObject = NULL;
250
 
251
          if (pciada->Vector)
252
                result = IoConnectInterrupt(&pciada->InterruptObject,
253
                        irq_service,
254
                                (PVOID)pciada,
255
                                        NULL,
256
                                                pciada->Vector,
257
                                                        pciada->Irql,
258
                                                                pciada->Irql,
259
                                                                        LevelSensitive,
260
                                                                                TRUE,
261
                                                                                        pciada->Affinity,
262
                                                                                                FALSE);
263
 
264
          KdPrint(("pIrqObj:0x%08x, VirtVect:%d, Irql:%d, hIrql:%d, Aff:0x%08x, Status:0x%08x\n",
265
          pciada->InterruptObject,
266
                                pciada->Vector, pciada->Irql, pciada->Irql, pciada->Affinity, result));
267
 
268
          if (result != STATUS_SUCCESS) break;
269
        }
270
 
271
        return result;
272
}
273
 
274
//------------------------------------------------------------------------
275
//  dis-connect service routines to all PCIADA interrupts
276
//
277
NTSTATUS PCIVMEDisConnectInterrupt(PDEVICE_OBJECT device_Obj)
278
{
279
        int              i;
280
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
281
        int                              nPCIADAs = pDevExt->nPCIADAs;
282
        PCIADA           *pciada;
283
 
284
    KdPrint(("DisConnectInterrupt()\n"));
285
 
286
        // dis connect the interrupts to service routines
287
        for (i = 0; i < nPCIADAs; i++)
288
        {
289
                pciada = &pDevExt->pciada[i];
290
 
291
                KdPrint(("IrqObj:0x%08x\n", pciada->InterruptObject));
292
 
293
                if (pciada->InterruptObject)
294
                  IoDisconnectInterrupt(pciada->InterruptObject);
295
        }
296
 
297
        return STATUS_SUCCESS;
298
}
299
 
300