Subversion Repositories f9daq

Rev

Rev 41 | 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
//
46 f9daq 198
/*
19 f9daq 199
NTSTATUS PCIVMETranslateInterrupts(PDEVICE_OBJECT device_Obj)
200
{
201
        int              i;
202
        NTSTATUS         result = STATUS_SUCCESS;
203
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
204
        int                              nPCIADAs = pDevExt->nPCIADAs;
205
        PCIADA           *pciada  = (PCIADA *) NULL;
206
 
207
    KdPrint(("TranslateInterrupt()\n"));
41 f9daq 208
        if (nPCIADAs) return STATUS_SUCCESS;
19 f9daq 209
 
210
        for (i = 0; i < nPCIADAs; i++)
211
        {
212
                pciada = &pDevExt->pciada[i];
213
 
214
                KdPrint(("In  - Bus:%d, IrqLine:%d\n", pciada->Bus, pciada->Irql));
215
 
216
                if (pciada->Irql)
217
                {
218
                        pciada->Vector = HalGetInterruptVector(PCIBus, pciada->Bus,
219
                                pciada->Irql,
220
                                        pciada->Vector,
221
                                                &pciada->Irql, &pciada->Affinity);
222
                }
223
                else
224
                        result = STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
225
        }
226
 
227
        KdPrint(("Out - Irql:%d, Vector: %d, Affinity:%d\n", pciada->Irql, pciada->Vector, pciada->Affinity));
228
 
229
        return result;
230
}
46 f9daq 231
*/
19 f9daq 232
 
233
//------------------------------------------------------------------------
234
//  connect service routines to all PCIADA interrupts
235
//
236
NTSTATUS PCIVMEConnectInterrupt(PDEVICE_OBJECT device_Obj)
237
{
238
        int              i;
239
        NTSTATUS         result = STATUS_SUCCESS;
240
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
241
        int                              nPCIADAs = pDevExt->nPCIADAs;
242
        PCIADA           *pciada;
243
 
244
    KdPrint(("ConnectInterrupt()\n"));
245
 
246
        // connect the interrupts to service routines
247
        for (i = 0; i < nPCIADAs; i++)
248
        {
249
      pciada = &pDevExt->pciada[i];
250
 
251
          pciada->InterruptObject = NULL;
252
 
253
          if (pciada->Vector)
254
                result = IoConnectInterrupt(&pciada->InterruptObject,
255
                        irq_service,
256
                                (PVOID)pciada,
257
                                        NULL,
258
                                                pciada->Vector,
259
                                                        pciada->Irql,
260
                                                                pciada->Irql,
261
                                                                        LevelSensitive,
262
                                                                                TRUE,
263
                                                                                        pciada->Affinity,
264
                                                                                                FALSE);
265
 
266
          KdPrint(("pIrqObj:0x%08x, VirtVect:%d, Irql:%d, hIrql:%d, Aff:0x%08x, Status:0x%08x\n",
267
          pciada->InterruptObject,
268
                                pciada->Vector, pciada->Irql, pciada->Irql, pciada->Affinity, result));
269
 
270
          if (result != STATUS_SUCCESS) break;
271
        }
272
 
273
        return result;
274
}
275
 
276
//------------------------------------------------------------------------
277
//  dis-connect service routines to all PCIADA interrupts
278
//
279
NTSTATUS PCIVMEDisConnectInterrupt(PDEVICE_OBJECT device_Obj)
280
{
281
        int              i;
282
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
283
        int                              nPCIADAs = pDevExt->nPCIADAs;
284
        PCIADA           *pciada;
285
 
286
    KdPrint(("DisConnectInterrupt()\n"));
287
 
288
        // dis connect the interrupts to service routines
289
        for (i = 0; i < nPCIADAs; i++)
290
        {
291
                pciada = &pDevExt->pciada[i];
292
 
293
                KdPrint(("IrqObj:0x%08x\n", pciada->InterruptObject));
294
 
295
                if (pciada->InterruptObject)
296
                  IoDisconnectInterrupt(pciada->InterruptObject);
297
        }
298
 
299
        return STATUS_SUCCESS;
300
}
301
 
302