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
// the ioctl functions
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_io.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:51  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.6  2002/10/27 18:30:57  klaus
26
// simpel typing correction
27
//
28
// Revision 1.5  2002/10/27 18:29:56  klaus
29
// honor backward compatibilty with non-extended modifier addressing
30
//
31
// Revision 1.4  2002/10/27 17:02:30  klaus
32
// File addressing bug > 2 Gbtye circumvent
33
//
34
// Revision 1.3  2002/10/27 16:17:48  klaus
35
// Typing bug fixed caused at log addition
36
//
37
// Revision 1.2  2002/10/27 16:11:02  klaus
38
// Added CVS log into header
39
//
40
// what                                            who          when
41
// started                                         AR           03.07.1999
42
// first release 1.0                                                                     AR                           17.10.1999
43
// changed resource allocation caused by WIN2000   AR           08.06.2002
44
//
45
 
46
//-------------------------------------------------------------------------
47
// INCLUDES
48
//
49
#include <ntddk.h>
50
#include <devioctl.h>
51
#include <pcivme_drv.h>
52
#include <pcivme.h>
53
#include <pcivme_v.h>
54
#include <pcivme_io.h>
55
#include <pciif.h>
56
#include <pcivme_i.h>
57
#include <pcivme_fifo.h>
58
 
59
//------------------------------------------------------------------------
60
// DEFINES
61
//
62
 
63
// buffers usage must match the corresponding ioctl code!
64
#define SET_BUFFERS_METHOD_OUT_DIRECT \
65
{\
66
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
67
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
68
        pInputBuffer  = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
69
        pOutputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
70
}
71
 
72
#define SET_BUFFERS_METHOD_IN_DIRECT \
73
{\
74
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
75
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
76
        pInputBuffer  = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
77
        pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
78
}
79
 
80
#define SET_BUFFERS_METHOD_BUFFERED \
81
{\
82
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
83
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
84
        pInputBuffer  = pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
85
}
86
 
87
#define COMPLETE_REQUEST \
88
{\
89
        if (Status != STATUS_PENDING)\
90
        {\
91
                Irp->IoStatus.Status      = Status; \
92
                Irp->IoStatus.Information = irp_info; \
93
                IoCompleteRequest(Irp,IO_NO_INCREMENT); \
94
        }\
95
}
96
 
97
// compatibilty issues to WIN95 driver calls
98
#ifndef WORD
99
#define WORD USHORT
100
#endif
101
 
102
#ifndef DWORD
103
#define DWORD ULONG
104
#endif
105
 
106
#ifndef BYTE
107
#define BYTE UCHAR
108
#endif
109
 
110
#ifndef BOOL
111
#define BOOL BOOLEAN
112
#endif
113
 
114
#define MODIFIER_MASK     0x3F // mask for address modifier
115
 
116
//-------------------------------------------------------------------------
117
// GLOBALS
118
//
119
const PCIVME_INIT_ELEMENT init_element[] =
120
         {{LCR,  WORD_ACCESS, 0x4c,       DISABLE_PCIADA_IRQS}, // disable interrupts
121
          {LCR,  WORD_ACCESS, 0x50,       RELEASE_VMEMM},       // enable interface
122
 
123
          {VIC,  BYTE_ACCESS, (WORD)0x03, 0xf8+1},    // VIICR
124
 
125
          {VIC,  BYTE_ACCESS, (WORD)0x07, 0x78+1},    // VICR1
126
          {VIC,  BYTE_ACCESS, (WORD)0x0b, 0x78+2},
127
          {VIC,  BYTE_ACCESS, (WORD)0x0f, 0x78+3},
128
          {VIC,  BYTE_ACCESS, (WORD)0x13, 0x78+4},
129
          {VIC,  BYTE_ACCESS, (WORD)0x17, 0x78+5},
130
          {VIC,  BYTE_ACCESS, (WORD)0x1b, 0x78+6},
131
          {VIC,  BYTE_ACCESS, (WORD)0x1f, 0x78+7},    // VICR7
132
 
133
          {VIC,  BYTE_ACCESS, (WORD)0x23, 0xf8+0},    // DSICR
134
 
135
          {VIC,  BYTE_ACCESS, (WORD)0x27, 0xf8+1},    // LICR1
136
          {VIC,  BYTE_ACCESS, (WORD)0x2b, 0xf8+2},
137
          {VIC,  BYTE_ACCESS, (WORD)0x2f, 0xf8+3},
138
          {VIC,  BYTE_ACCESS, (WORD)0x33, 0xf8+4},
139
          {VIC,  BYTE_ACCESS, (WORD)0x37, 0xf8+5},
140
          {VIC,  BYTE_ACCESS, (WORD)0x3b, 0x38+6},
141
          {VIC,  BYTE_ACCESS, (WORD)0x3f, 0x38+7},    // LICR7
142
 
143
          {VIC,  BYTE_ACCESS, (WORD)0x43, 0xf8+2},    // ICGS
144
          {VIC,  BYTE_ACCESS, (WORD)0x47, 0xf8+3},    // ICMS
145
 
146
          {VIC,  BYTE_ACCESS, (WORD)0x4b, 0xf8+6},    // EGICR
147
 
148
          {VIC,  BYTE_ACCESS, (WORD)0x4f, 0x08},      // ICGS-IVBR (!)
149
          {VIC,  BYTE_ACCESS, (WORD)0x53, 0x0c},      // ICMS-IVBR (!)
150
 
151
          {VIC,  BYTE_ACCESS, (WORD)0x57, 0x00},      // LIVBR (!)
152
 
153
          {VIC,  BYTE_ACCESS, (WORD)0x5b, 0x10},      // EGIVBR (!)
154
 
155
          {VIC,  BYTE_ACCESS, (WORD)0x5f, 0x00},      // ICSR
156
 
157
          {VIC,  BYTE_ACCESS, (WORD)0x63, 0x00},      // ICR0
158
          {VIC,  BYTE_ACCESS, (WORD)0x67, 0x00},
159
          {VIC,  BYTE_ACCESS, (WORD)0x6b, 0x00},
160
          {VIC,  BYTE_ACCESS, (WORD)0x6f, 0x00},
161
          {VIC,  BYTE_ACCESS, (WORD)0x73, 0x00},      // ICR4
162
 
163
          {VIC,  BYTE_ACCESS, (WORD)0x83, 0xfe},      // VIRSR
164
 
165
          {VIC,  BYTE_ACCESS, (WORD)0x87, 0x0f},      // VIVR1
166
          {VIC,  BYTE_ACCESS, (WORD)0x8b, 0x0f},
167
          {VIC,  BYTE_ACCESS, (WORD)0x8f, 0x0f},
168
          {VIC,  BYTE_ACCESS, (WORD)0x93, 0x0f},
169
          {VIC,  BYTE_ACCESS, (WORD)0x97, 0x0f},
170
          {VIC,  BYTE_ACCESS, (WORD)0x9b, 0x0f},
171
          {VIC,  BYTE_ACCESS, (WORD)0x9f, 0x0f},      // VIVR7
172
 
173
          {VIC,  BYTE_ACCESS, (WORD)0xa3, 0x3c},      // TTR
174
 
175
          {VIC,  BYTE_ACCESS, (WORD)0xb3, 0x40},      // ARCR
176
          {VIC,  BYTE_ACCESS, (WORD)0xb7, 0x29},      // AMSR
177
          {VIC,  BYTE_ACCESS, (WORD)0xd3, 0x00},      // RCR
178
 
179
          {IFR,  LONG_ACCESS, (WORD)ADRHL, 0xF0F0F0F0},  // ADR-H, ADR-L
180
          {IFR,  WORD_ACCESS, (WORD)CSR  , 0x0000},      // Contr-Reg
181
 
182
          {VIC,  BYTE_ACCESS, (WORD)0x7f, 0x80},         // ICR7
183
 
184
          {LCR,  WORD_ACCESS, 0x4c, DISABLE_PCIADA_IRQS},// disable interrupts
185
 
186
          {STOP, WORD_ACCESS, 0,     0}};
187
 
188
const PCIVME_INIT_ELEMENT deinit_element_pre[] =
189
         {{VIC,  BYTE_ACCESS, (WORD)0x7f, 0x00},         // ICR7 - sysfail
190
          {LCR,  WORD_ACCESS, 0x4c, DISABLE_PCIADA_IRQS},// disable interrupts
191
          {STOP, WORD_ACCESS, 0,    0}};
192
 
193
const PCIVME_INIT_ELEMENT deinit_element_post[] =
194
         {{LCR,  WORD_ACCESS, 0x50, INHIBIT_VMEMM},      // disable interface
195
          {STOP, WORD_ACCESS, 0,    0}};
196
 
197
 
198
//--------------------------------------------------------------------------
199
// LOCAL FUNCTIONS
200
//
201
 
202
//--------------------------------------------------------------------------
203
// fast read or write functions - portable -
204
static void readByte(void *to, ULONG dwLength, void *from)
205
{
206
        READ_REGISTER_BUFFER_UCHAR((PUCHAR)from, (PUCHAR)to, dwLength);
207
}
208
 
209
static void readWord(void *to, ULONG dwLength, void *from)
210
{
211
        dwLength >>= 1;
212
        READ_REGISTER_BUFFER_USHORT((PUSHORT)from, (PUSHORT)to, dwLength);
213
}
214
 
215
static void readLong(void *to, ULONG dwLength, void *from)
216
{
217
        dwLength >>= 2;
218
        READ_REGISTER_BUFFER_ULONG((PULONG)from, (PULONG)to, dwLength);
219
}
220
 
221
static void writeByte(void *to, ULONG dwLength, void *from)
222
{
223
        WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)to, (PUCHAR)from, dwLength);
224
}
225
 
226
static void writeWord(void *to, ULONG dwLength, void *from)
227
{
228
        dwLength >>= 1;
229
        WRITE_REGISTER_BUFFER_USHORT((PUSHORT)to, (PUSHORT)from, dwLength);
230
}
231
 
232
static void writeLong(void *to, ULONG dwLength, void *from)
233
{
234
        dwLength >>= 2;
235
        WRITE_REGISTER_BUFFER_ULONG((PULONG)to, (PULONG)from, dwLength);
236
}
237
 
238
//------------------------------------------------------------------------
239
// insert the irq queue into the linked list of queues
240
static NTSTATUS insertQueueInList(PFILE_OBJ pFile_obj, PCIADA *pciada)
241
{
242
        NTSTATUS        Status    = STATUS_SUCCESS;
243
        FIFO_LIST   *next;
244
        KIRQL           OldIrql;
245
 
246
        KdPrint(("insertQueueInList()\n"));
247
 
248
        if (pFile_obj->bQueueIrq)  // still enabled and in list
249
                return Status;
250
 
251
        // allocate memory to hold the list and its container
252
        next = (FIFO_LIST *)ExAllocatePool(NonPagedPool, sizeof(FIFO_LIST));
253
        if(next == (FIFO_LIST *)NULL)
254
                return STATUS_INSUFFICIENT_RESOURCES;
255
        else
256
        {
257
                // fill contents in entry
258
                next->pFile_obj                 = pFile_obj;
259
                next->pIrqListHandle    = pFile_obj->pIrqListHandle;
260
 
261
                // insert the entry in the list
262
                KeAcquireSpinLock(&pciada->IrqListLock, &OldIrql);
263
                KdPrint(("InsertHeadList(0x%08x, 0x%08x)\n", &pciada->IrqListList, &next->entry));
264
                InsertHeadList(&pciada->IrqListList, &next->entry);
265
                KeReleaseSpinLock(&pciada->IrqListLock, OldIrql);
266
 
267
                // show and mark it
268
                pFile_obj->bQueueIrq = TRUE;
269
        }
270
 
271
        return Status;
272
}
273
 
274
//------------------------------------------------------------------------
275
// remove the irq queue from the linked list of queues
276
NTSTATUS removeQueueFromList(PFILE_OBJ pFile_obj, PCIADA *pciada)
277
{
278
        NTSTATUS        Status    = STATUS_SUCCESS;
279
        FIFO_LIST   *next;
280
        PLIST_ENTRY pList;
281
        KIRQL           OldIrql;
282
 
283
        KdPrint(("removeQueueFromList(0x%08x, 0x%08x)\n", pFile_obj, pciada));
284
 
285
        pList = &pciada->IrqListList;  
286
 
287
        if ((pFile_obj == (FILE_OBJ *)NULL) || (pciada == (PCIADA *)NULL)) return Status;
288
 
289
        // search for coincidence of pFile_obj in the list
290
        KeAcquireSpinLock(&pciada->IrqListLock, &OldIrql);
291
        while (pList->Flink != &pciada->IrqListList)
292
        {
293
                pList = pList->Flink;
294
                next = CONTAINING_RECORD(pList, FIFO_LIST, entry);
295
                if (next->pFile_obj == pFile_obj)   // found
296
                {
297
                        KdPrint(("RemoveEntryList(0%08x)\n", pList));
298
                        RemoveEntryList(pList);
299
                        ExFreePool((PVOID)next);
300
                        break;
301
                }
302
        }
303
        KeReleaseSpinLock(&pciada->IrqListLock, OldIrql);
304
 
305
        // in every case switch it off (again)
306
        pFile_obj->bQueueIrq = FALSE;
307
 
308
        KdPrint(("removeQueueFromList OK\n"));
309
        return Status;
310
}
311
 
312
//--------------------------------------------------------------------------
313
// parsing of user supplied input for validy
314
static BOOLEAN check_command(const PCIVME_INIT_ELEMENT *psInitElement)
315
{
316
  USHORT range;
317
  USHORT access_size;
318
 
319
  switch (psInitElement->range)
320
  {
321
    case LCR: range = 0x54;     break;
322
    case IFR: range = 0x0c;     break;
323
    case VIC: range = 0xe4;
324
              if ((psInitElement->offset & 3) != 3)
325
                return FALSE;
326
              break;
327
    default:  range = 0;        break;
328
  }
329
 
330
  switch (psInitElement->type)
331
  {
332
    case LONG_ACCESS: if (psInitElement->offset & 3)
333
                        return FALSE;
334
                      access_size = sizeof(ULONG);
335
                      break;
336
    case WORD_ACCESS: if (psInitElement->offset & 1)
337
                        return FALSE;
338
                      access_size = sizeof( USHORT);
339
                      break;
340
    case BYTE_ACCESS: access_size = sizeof( UCHAR); break;
341
    default         : access_size = 0xFFFF;        break;
342
  }
343
 
344
  if ((psInitElement->offset + access_size) > range)
345
    return FALSE;       // ignore it
346
 
347
  return TRUE;
348
}
349
 
350
//------------------------------------------------------------------------
351
// iterate through all commands
352
static VOID CmdMachine(const PCIVME_INIT_ELEMENT *psInitElement,
353
                                                 PVOID pvLcr, PVOID pvIfr)
354
{
355
  PVOID adr;
356
 
357
  // standard initialisierungen  
358
  while (psInitElement->range != STOP)
359
  {
360
    /*
361
        KdPrint(("CmdMachine: %d %d 0x%02x 0x%02x\n",
362
                psInitElement->range,  psInitElement->type,
363
                psInitElement->offset, psInitElement->value));
364
    */
365
 
366
    if (check_command(psInitElement))
367
    {
368
      switch (psInitElement->range)
369
      {
370
        case LCR: adr = pvLcr; break;
371
        case VIC: adr = (PVOID)((ULONG)pvIfr + (USHORT)VICBASE); break;
372
        case IFR:
373
        default:  adr = pvIfr; break;  
374
      }
375
 
376
      switch (psInitElement->type)
377
      {
378
        case LONG_ACCESS:
379
                  WRITE_REGISTER_ULONG((ULONG *)((UCHAR *)adr + psInitElement->offset),  
380
                                                                     psInitElement->value);
381
          break;
382
        case WORD_ACCESS:
383
                  WRITE_REGISTER_USHORT((USHORT *)((UCHAR *)adr + psInitElement->offset),
384
                                                             (USHORT)psInitElement->value);
385
          break;
386
        case BYTE_ACCESS:
387
        default:
388
                  WRITE_REGISTER_UCHAR((UCHAR *)((UCHAR *)adr + psInitElement->offset),  
389
                                                              (UCHAR)psInitElement->value);
390
          break;
391
      }
392
    }
393
    psInitElement++;
394
  }
395
}
396
 
397
//------------------------------------------------------------------------
398
// init the interface with build in and user supplied constants
399
static BOOLEAN InitInterface(const PCIVME_INIT_COMMAND *psInitCmd,
400
                                                    PVOID pvLcr, PVOID pvIfr)
401
{
402
  PCIVME_INIT_ELEMENT *psVie;
403
 
404
  if ((psInitCmd == (PCIVME_INIT_COMMAND *)BOGUSADDRESS) ||
405
      (psInitCmd == (PCIVME_INIT_COMMAND *)NULL)         ||
406
          (pvLcr         == (PVOID)BOGUSADDRESS)                 ||
407
      (pvLcr     == (PVOID)NULL)                         ||
408
          (pvIfr         == (PVOID)BOGUSADDRESS)                 ||
409
          (pvIfr     == (PVOID)NULL))
410
    return FALSE;
411
 
412
  psVie = (PCIVME_INIT_ELEMENT *)psInitCmd->sVie;
413
  CmdMachine(init_element , pvLcr, pvIfr);    // standard initialisierungen  
414
  CmdMachine(psVie,         pvLcr, pvIfr);    // benutzer initialisierungen
415
 
416
  return TRUE;
417
}
418
 
419
// deinit the interface with user supplied and build in constants
420
static BOOLEAN DeInitInterface(const PCIVME_INIT_COMMAND *psDeInitCmd,
421
                                                   PVOID pvLcr, PVOID pvIfr)
422
{
423
  PCIVME_INIT_ELEMENT *psVie;
424
 
425
  if ((psDeInitCmd == (PCIVME_INIT_COMMAND *)BOGUSADDRESS) ||
426
      (psDeInitCmd == (PCIVME_INIT_COMMAND *)NULL)         ||
427
          (pvLcr           == (PVOID)BOGUSADDRESS)                 ||
428
      (pvLcr       == (PVOID)NULL)                         ||
429
          (pvIfr           == (PVOID)BOGUSADDRESS)                 ||
430
          (pvIfr       == (PVOID)NULL))
431
    return FALSE;
432
 
433
  psVie = (PCIVME_INIT_ELEMENT *)psDeInitCmd->sVie;
434
  CmdMachine(deinit_element_pre,   pvLcr, pvIfr); // standard de-initialisierungen  
435
  CmdMachine(psVie,                pvLcr, pvIfr); // benutzer de-initialisierungen
436
  CmdMachine(deinit_element_post , pvLcr, pvIfr); // disable interface
437
 
438
  return TRUE;
439
}
440
 
441
//------------------------------------------------------------------------
442
// a inserter into a user managed queue of IRPs
443
//
444
void InsertIRPtoQueue(PDEVICE_OBJECT device_Obj, PIRP Irp)
445
{
446
        DEVICE_EXT *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
447
        KIRQL           oldIrql;
448
 
449
    KdPrint(("InsertIRPtoQueue(0x%08x)\n", Irp));
450
 
451
        KeAcquireSpinLock(&pDevExt->IRPLock, &oldIrql);
452
        InsertHeadList(&pDevExt->IRPList, &Irp->Tail.Overlay.ListEntry);
453
        KeReleaseSpinLock(&pDevExt->IRPLock, oldIrql);
454
}
455
 
456
//------------------------------------------------------------------------
457
// a remover out of a user managed queue of IRPs
458
//
459
PIRP RemoveIRPfromQueue(PDEVICE_OBJECT device_Obj, FILE_OBJ *pFile_obj)
460
{
461
        DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
462
        KIRQL           oldIrql;
463
        register PLIST_ENTRY pList = &pDevExt->IRPList;
464
        PIRP        Irp;
465
        PIRP        pIrp = (PIRP)NULL;
466
        FILE_OBJ        *file_obj;
467
 
468
    KdPrint(("RemoveIRPfromQueue()\n"));
469
 
470
        KeAcquireSpinLock(&pDevExt->IRPLock, &oldIrql);
471
 
472
        while (pList->Flink != &pDevExt->IRPList)  // until the end is reached
473
        {
474
                pList = pList->Flink;
475
                Irp  = CONTAINING_RECORD(pList, IRP, Tail.Overlay.ListEntry);
476
                file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
477
 
478
                KdPrint(("pList 0x%08x, pList->Flink 0x%08x, Irp 0x%08x, file_obj 0x%08x\n", pList, pList->Flink, Irp, file_obj));
479
 
480
                if ((file_obj == pFile_obj) && (pFile_obj != (FILE_OBJ *)NULL))
481
                {
482
                        RemoveEntryList(pList);
483
                        pIrp = Irp;
484
                        break;
485
                }
486
        }
487
 
488
        KeReleaseSpinLock(&pDevExt->IRPLock, oldIrql);
489
 
490
    KdPrint(("return RemoveIRPfromQueue(0x%08x)\n", pIrp));
491
 
492
        return pIrp;
493
}
494
 
495
//------------------------------------------------------------------------
496
// a remover out of a user managed queue of IRPs
497
//
498
PIRP RemoveIRPfromQueueByIrp(PDEVICE_OBJECT device_Obj, PIRP pIrpIn)
499
{
500
        DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
501
        KIRQL           oldIrql;
502
        register PLIST_ENTRY pList = &pDevExt->IRPList;
503
        PIRP        Irp;
504
        PIRP        pIrp = (PIRP)NULL;
505
 
506
    KdPrint(("RemoveIRPfromQueueByIrp()\n"));
507
 
508
        KeAcquireSpinLock(&pDevExt->IRPLock, &oldIrql);
509
 
510
        while (pList->Flink != &pDevExt->IRPList)  // until the end is reached
511
        {
512
                pList = pList->Flink;
513
                Irp  = CONTAINING_RECORD(pList, IRP, Tail.Overlay.ListEntry);
514
 
515
                KdPrint(("pList 0x%08x, pList->Flink 0x%08x, Irp 0x%08x\n", pList, pList->Flink, Irp));
516
 
517
                if (pIrpIn == Irp)
518
                {
519
                        RemoveEntryList(pList);
520
                        pIrp = Irp;
521
                        break;
522
                }
523
        }
524
 
525
        KeReleaseSpinLock(&pDevExt->IRPLock, oldIrql);
526
 
527
    KdPrint(("return RemoveIRPfromQueueByIrp(0x%08x)\n", pIrp));
528
 
529
        return pIrp;
530
}
531
 
532
//------------------------------------------------------------------------
533
// the default cancel routine for an queued Irp 
534
//
535
void CancelRequest(PDEVICE_OBJECT device_Obj, PIRP Irp)
536
{
537
        PIRP pIrpCancel = RemoveIRPfromQueueByIrp(device_Obj, Irp);
538
 
539
        if (pIrpCancel == (PIRP)NULL)
540
        {
541
                IoReleaseCancelSpinLock(Irp->CancelIrql);
542
                KdPrint(("Nothing to do: CancelRequest(0x%08x)\n", Irp));
543
                return;
544
        }
545
        else
546
        {
547
                IoReleaseCancelSpinLock(Irp->CancelIrql);
548
 
549
                KdPrint(("Done: CancelRequest(0x%08x)\n", Irp));
550
 
551
                Irp->IoStatus.Status = STATUS_CANCELLED;
552
                Irp->IoStatus.Information = 0;
553
 
554
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
555
        }
556
}
557
 
558
 
559
//------------------------------------------------------------------------
560
// the custom deffered routine to finish blocking io on read_vector
561
void fMyDefferedRoutine(PKDPC Dpc, PVOID pvDevice_object,
562
                                                                         PVOID pvPciada, PVOID pvVector)
563
{
564
        NTSTATUS Status = STATUS_SUCCESS;
565
        ULONG irp_info  = sizeof(PCIVME_VECTOR_RESPONSE);
566
    PIRP  Irp = (PIRP)NULL;
567
        PDEVICE_OBJECT device_Obj = (PDEVICE_OBJECT)pvDevice_object;
568
        PCIADA *pciada = (PCIADA *)pvPciada;
569
        FIFO_LIST               *next;
570
        KIRQL                   oldIrqlCancel;
571
        KIRQL                   oldIrqlList;
572
        register PLIST_ENTRY pList = &pciada->IrqListList;
573
        UNREFERENCED_PARAMETER(pvVector);
574
        UNREFERENCED_PARAMETER(Dpc);
575
    KdPrint(("fMyDefferedRoutine()\n"));
576
 
577
        // beware off damage due to intercept with cancel of thread
578
    IoAcquireCancelSpinLock(&oldIrqlCancel);
579
        KeAcquireSpinLock(&pciada->IrqListLock, &oldIrqlList);
580
 
581
        while (pList->Flink != &pciada->IrqListList)  // until the end is reached
582
        {
583
                pList = pList->Flink;
584
                KeReleaseSpinLock(&pciada->IrqListLock, oldIrqlList); // shorten block
585
 
586
                next = CONTAINING_RECORD(pList, FIFO_LIST, entry);
587
 
588
                // get my associated packet
589
                Irp = RemoveIRPfromQueue(device_Obj, next->pFile_obj);
590
 
591
                if (Irp != (PIRP)NULL)
592
                {
593
                        PCIVME_VECTOR_REQUEST  *pVectorRequest  = (PCIVME_VECTOR_REQUEST  *)(Irp->AssociatedIrp.SystemBuffer);
594
                        PCIVME_VECTOR_RESPONSE *pVectorResponse = (PCIVME_VECTOR_RESPONSE *)pVectorRequest;
595
                        USHORT wRequestCount = pVectorRequest->wRequestCount;
596
                        UCHAR  *pbVector     = &pVectorResponse->bStatusID;
597
                        FILE_OBJ *file_obj   = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
598
                        UCHAR  bNumberOfElements = (UCHAR) NumberOfElements(file_obj->pIrqListHandle);
599
 
600
                        // pull the vectors off the fifo
601
                        pVectorResponse->wCount = 0;
602
                        while ((bNumberOfElements) && (wRequestCount--))
603
                        {
604
                                bNumberOfElements   = (UCHAR) PullElement(file_obj->pIrqListHandle,
605
                                                                        (void *)pbVector);
606
                                pbVector++;
607
                                pVectorResponse->wCount++;
608
                        }
609
                        pVectorResponse->wPendingCount = bNumberOfElements;
610
                        pVectorResponse->bOverflow     = CheckAndClearOverflow(file_obj->pIrqListHandle);
611
                        irp_info = sizeof(PCIVME_VECTOR_RESPONSE) +
612
                                     sizeof(UCHAR) * (pVectorResponse->wCount - 1);
613
 
614
                        // release the cancel routine from this Irp
615
                        IoSetCancelRoutine(Irp, NULL);
616
 
617
                        COMPLETE_REQUEST;
618
                }
619
 
620
                KeAcquireSpinLock(&pciada->IrqListLock, &oldIrqlList);
621
        }
622
 
623
        // release the spin locks
624
        KeReleaseSpinLock(&pciada->IrqListLock, oldIrqlList);
625
        IoReleaseCancelSpinLock(oldIrqlCancel);
626
}
627
 
628
//------------------------------------------------------------------------
629
// all functions called from ioctl jump table
630
//
631
 
632
//------------------------------------------------------------------------
633
// initialize all hardware associated to a given wModuleNumber
634
static NTSTATUS ioctl_init_hardware(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
635
{
636
        NTSTATUS        Status    = STATUS_SUCCESS;
637
        ULONG           irp_info  = 0;
638
        PVOID           pInputBuffer,pOutputBuffer;
639
        ULONG           InputLength, OutputLength;
640
        DEVICE_EXT      *pDevExt;
641
        PCIVME_INIT_COMMAND *pInitCommand;
642
        PCIADA      *pciada;
643
        FILE_OBJ        *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
644
 
645
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
646
 
647
        SET_BUFFERS_METHOD_BUFFERED;
648
 
649
        // do what must be here in between --- start ---
650
        pInitCommand = (PCIVME_INIT_COMMAND *)pInputBuffer;
651
 
652
    KdPrint(("ioctl_init_hardware(%d)\n", file_obj->uwAssociatedVMEMM));
653
 
654
        pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
655
 
656
        if (pciada != NULL)
657
        {
658
                KIRQL oldIrql;
659
 
660
                if (pciada->dwLinkCount == 1)
661
                {
662
                        // lock other users out
663
                        KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
664
 
665
                        if (InitInterface(pInitCommand, pciada->pvVirtLcr, pciada->pvVirtIfr))
666
                        {
667
                                // fill cache for page and modifier
668
                                pciada->dwVMEPage = READ_REGISTER_ULONG(pciada->pdwVMEAdr)  & ~VME_ADR_MASK;
669
                                pciada->bModifier = READ_REGISTER_UCHAR(pciada->pbModifier) & MODIFIER_MASK;
670
                        }
671
                        else
672
                                Status = STATUS_UNSUCCESSFUL;
673
 
674
                        // release the lock
675
                        KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
676
                }
677
                else
678
                        Status = STATUS_UNSUCCESSFUL;
679
        }
680
        else
681
                Status = STATUS_UNSUCCESSFUL;
682
 
683
        // do what must be here in between --- end ---
684
 
685
        COMPLETE_REQUEST;
686
 
687
    KdPrint(("ioctl_init_hardware(), Status = 0x%08x\n", Status));
688
 
689
        return Status;
690
}
691
 
692
//------------------------------------------------------------------------
693
// De-initialise all hardware associated to a given wModuleNumber 
694
static NTSTATUS ioctl_deinit_hardware(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
695
{
696
        NTSTATUS        Status    = STATUS_SUCCESS;
697
        ULONG           irp_info  = 0;
698
        PVOID           pInputBuffer,pOutputBuffer;
699
        ULONG           InputLength, OutputLength;
700
        DEVICE_EXT      *pDevExt;
701
        PCIVME_INIT_COMMAND *pInitCommand;
702
        PCIADA      *pciada;
703
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
704
    KdPrint(("ioctl_deinit_hardware()\n"));
705
 
706
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
707
 
708
        SET_BUFFERS_METHOD_BUFFERED;
709
 
710
        // do what must be hier in between --- start ---
711
        pInitCommand = (PCIVME_INIT_COMMAND *)pInputBuffer;
712
 
713
    KdPrint(("ioctl_deinit_hardware(%d)\n", file_obj->uwAssociatedVMEMM));
714
 
715
        pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
716
 
717
        if (pciada != NULL)
718
        {
719
                KIRQL oldIrql;
720
 
721
                if (pciada->dwLinkCount == 1)
722
                {
723
                        // lock other users out
724
                        KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
725
 
726
                        if (DeInitInterface(pInitCommand, pciada->pvVirtLcr, pciada->pvVirtIfr))
727
                                globalInterruptDisable(pciada);
728
                        else
729
                                Status = STATUS_UNSUCCESSFUL;
730
 
731
                        // everyone likes to have PCIVME
732
                        KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
733
                }
734
                else
735
                        Status = STATUS_UNSUCCESSFUL;
736
        }
737
        else
738
                Status = STATUS_UNSUCCESSFUL;
739
        // do what must be hier in between --- end ---
740
 
741
        COMPLETE_REQUEST;
742
 
743
    KdPrint(("ioctl_deinit_hardware(), Status = 0x%08x\n", Status));
744
 
745
        return Status;
746
}
747
 
748
//------------------------------------------------------------------------
749
// a dummy entry because of compatibiltiy (near) WIN95 driver
750
static NTSTATUS ioctl_dummy(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
751
{
752
        NTSTATUS        Status    = STATUS_SUCCESS;
753
        ULONG           irp_info  = 0;
754
        PVOID           pInputBuffer,pOutputBuffer;
755
        ULONG           InputLength, OutputLength;
756
        PCIVME_INIT_COMMAND *pInitCommand;
757
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
758
 
759
        SET_BUFFERS_METHOD_BUFFERED;
760
        UNREFERENCED_PARAMETER(device_Obj);
761
#ifndef _DEBUG
762
        UNREFERENCED_PARAMETER(file_obj);
763
#endif
764
        pInitCommand = (PCIVME_INIT_COMMAND *)pInputBuffer;
765
 
766
    KdPrint(("ioctl_dummy(%d)\n", file_obj->uwAssociatedVMEMM));
767
 
768
        // do what must be here in between -----------
769
 
770
        // do what must be here in between --- end ---
771
 
772
        COMPLETE_REQUEST;
773
 
774
    KdPrint(("ioctl_dummy(), Status = 0x%08x\n", Status));
775
 
776
        return Status;
777
}
778
 
779
//------------------------------------------------------------------------
780
// requests fixed unchangeable information - not compatible to WIN95 driver
781
static NTSTATUS ioctl_get_static_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
782
{
783
        NTSTATUS        Status    = STATUS_SUCCESS;
784
        ULONG           irp_info  = sizeof(PCIVME_STATIC_STATUS);
785
        PVOID           pInputBuffer,pOutputBuffer;
786
        ULONG           InputLength, OutputLength;
787
        PCIADA      *pciada;
788
        DEVICE_EXT      *pDevExt;
789
        PCIVME_STATIC_STATUS *pStaticStatus;
790
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
791
 
792
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
793
 
794
        SET_BUFFERS_METHOD_BUFFERED;
795
 
796
    KdPrint(("ioctl_get_static_status(%d)\n", file_obj->uwAssociatedVMEMM));
797
 
798
        // do what must be here in between -----------
799
        if (OutputLength >= sizeof(PCIVME_STATIC_STATUS))
800
        {
801
                pStaticStatus = (PCIVME_STATIC_STATUS *)pOutputBuffer;
802
 
803
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
804
 
805
                pStaticStatus->dwInterface              = file_obj->uwAssociatedVMEMM;  
806
 
807
                pStaticStatus->wNumMemWindows   = 3;      
808
                pStaticStatus->wNumIOPorts              = 2;
809
                pStaticStatus->wNumIRQs                 = 1;
810
                pStaticStatus->wNumDMAs                 = 0;
811
 
812
                pStaticStatus->dwLinkCount              = pciada->dwLinkCount;
813
 
814
                pStaticStatus->wModuleType              = pciada->wModuleType;
815
                pStaticStatus->wFPGAVersion             = pciada->wFPGAVersion;
816
                pStaticStatus->wModuleNumber    = pciada->wModuleNumber;
817
                pStaticStatus->wWordMode                = pciada->bWordMode;
818
 
819
                pStaticStatus->wSysControl              = pciada->bSysControl;
820
                pStaticStatus->wConnected               = pciada->bConnected;
821
 
822
                pStaticStatus->pvLcr                    = pciada->pvPhysLcr;
823
                pStaticStatus->pvIfr                    = pciada->pvPhysIfr;
824
 
825
                pStaticStatus->dwDriverVersion  = DRIVER_VERSION;
826
                pStaticStatus->dwDriverVariant  = DRIVER_VARIANT;
827
        }
828
        else
829
                Status = STATUS_BUFFER_TOO_SMALL;
830
        // do what must be here in between --- end ---
831
 
832
        COMPLETE_REQUEST;
833
 
834
    KdPrint(("ioctl_get_static_status(), Status = 0x%08x\n", Status));
835
 
836
        return Status;
837
}
838
 
839
//------------------------------------------------------------------------
840
// requests changeable status
841
static NTSTATUS ioctl_get_dynamic_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
842
{
843
        NTSTATUS        Status    = STATUS_SUCCESS;
844
        ULONG           irp_info  = sizeof(PCIVME_DYNAMIC_STATUS);
845
        PVOID           pInputBuffer,pOutputBuffer;
846
        ULONG           InputLength, OutputLength;
847
        PCIADA      *pciada;
848
        DEVICE_EXT      *pDevExt;
849
        PCIVME_DYNAMIC_STATUS *pDynamicStatus;
850
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
851
 
852
        SET_BUFFERS_METHOD_BUFFERED;
853
 
854
    KdPrint(("ioctl_get_dynamic_status(%d)\n", file_obj->uwAssociatedVMEMM));
855
 
856
        // do what must be here in between -----------
857
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
858
 
859
        SET_BUFFERS_METHOD_BUFFERED;
860
 
861
    KdPrint(("ioctl_get_static_status(%d)\n", file_obj->uwAssociatedVMEMM));
862
 
863
        // do what must be here in between -----------
864
        if (OutputLength >= sizeof(PCIVME_DYNAMIC_STATUS))
865
        {
866
                USHORT temp;
867
 
868
                pDynamicStatus = (PCIVME_DYNAMIC_STATUS *)pOutputBuffer;
869
 
870
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
871
 
872
                pDynamicStatus->dwInterface     = file_obj->uwAssociatedVMEMM;
873
 
874
                temp = READ_REGISTER_USHORT(pciada->pwCntrl);
875
                pDynamicStatus->wVMEMM_enable           = ((temp & 0x0180) == 0x0180) ? 1 : 0;
876
                pDynamicStatus->wVMEMM_connected        = ((temp & 0x0c00) == 0x0800) ? 1 : 0;
877
                temp = READ_REGISTER_USHORT(pciada->pwIntCSR);
878
                pDynamicStatus->wPCIADAIrq                      = (temp & 0x0004) ? 1 : 0;
879
                pDynamicStatus->wVMEMMIrq                       = (temp & 0x0020) ? 1 : 0;
880
        }
881
        else
882
                Status = STATUS_BUFFER_TOO_SMALL;
883
 
884
        // do what must be here in between --- end ---
885
 
886
        COMPLETE_REQUEST;
887
 
888
    KdPrint(("ioctl_get_dynamic_status(), Status = 0x%08x\n", Status));
889
 
890
        return Status;
891
}
892
 
893
//------------------------------------------------------------------------
894
// get the next vector out of the vector queue
895
static NTSTATUS ioctl_read_vector(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
896
{
897
        NTSTATUS        Status    = STATUS_SUCCESS;
898
        ULONG           irp_info  = sizeof(PCIVME_VECTOR_RESPONSE);
899
        PVOID           pInputBuffer,pOutputBuffer;
900
        ULONG           InputLength, OutputLength;
901
        PCIVME_VECTOR_RESPONSE *pVectorResponse;
902
        PCIVME_VECTOR_REQUEST  *pVectorRequest;
903
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
904
    KIRQL       oldIrql;
905
        BOOLEAN     bPoll;
906
        USHORT      wRequestCount;
907
 
908
        SET_BUFFERS_METHOD_BUFFERED;
909
 
910
    KdPrint(("ioctl_read_vector(%d)\n", file_obj->uwAssociatedVMEMM));
911
 
912
        pVectorRequest  = (PCIVME_VECTOR_REQUEST  *)pInputBuffer;
913
        pVectorResponse = (PCIVME_VECTOR_RESPONSE *)pOutputBuffer;
914
 
915
        // check the available room for vectors and correct if too less
916
        if (OutputLength <
917
                   (sizeof(PCIVME_VECTOR_RESPONSE) +
918
                       (pVectorRequest->wRequestCount - 1) * sizeof(UCHAR)))
919
                pVectorRequest->wRequestCount =
920
                    (USHORT)OutputLength - sizeof(PCIVME_VECTOR_RESPONSE) + sizeof(UCHAR);
921
 
922
        // empty the inputbuffer as early as possible
923
        wRequestCount = pVectorRequest->wRequestCount;
924
        bPoll             = pVectorRequest->bPoll;
925
 
926
        // do what must be here in between -----------
927
    if (OutputLength >= sizeof(PCIVME_VECTOR_RESPONSE)) // at least room for one
928
        {
929
                UCHAR  bNumberOfElements;
930
                UCHAR  *pbVector = &pVectorResponse->bStatusID;
931
 
932
                pVectorResponse->dwInterface = file_obj->uwAssociatedVMEMM;                    
933
 
934
                bNumberOfElements = (UCHAR) NumberOfElements(file_obj->pIrqListHandle);
935
 
936
                if ((bNumberOfElements) || (bPoll))
937
                {
938
                        KdPrint(("Direct return (%d)\n", bNumberOfElements));
939
 
940
                        pVectorResponse->wCount = 0;
941
                        while ((bNumberOfElements) && (wRequestCount--))
942
                        {
943
                                bNumberOfElements   = (UCHAR) PullElement(file_obj->pIrqListHandle,
944
                                                                        (void *)pbVector);
945
                                pbVector++;
946
                                pVectorResponse->wCount++;
947
                        }
948
                        pVectorResponse->wPendingCount = bNumberOfElements;
949
                        pVectorResponse->bOverflow     = CheckAndClearOverflow(file_obj->pIrqListHandle);
950
                        irp_info = sizeof(PCIVME_VECTOR_RESPONSE) +
951
                                     sizeof(UCHAR) * (pVectorResponse->wCount - 1);
952
                }
953
                else                    // go in wait queue for an irq
954
                {
955
                        IoAcquireCancelSpinLock(&oldIrql);
956
 
957
                        if (Irp->Cancel)    // cancel while doing
958
                        {
959
                                KdPrint(("Canceld return (%d)\n", bNumberOfElements));
960
                                Status = STATUS_CANCELLED;
961
                        }
962
                        else
963
                        {
964
                                KdPrint(("Blocking return (%d)\n", bNumberOfElements));
965
 
966
                                InsertIRPtoQueue(device_Obj, Irp);
967
 
968
                                Status = STATUS_PENDING;
969
 
970
                                // mark irp as pending and return
971
                                IoMarkIrpPending(Irp);
972
                                IoSetCancelRoutine(Irp, CancelRequest);
973
                        } // if (Irp->Cancel) ...
974
 
975
                        IoReleaseCancelSpinLock(oldIrql);
976
                }
977
        }
978
        else
979
                Status = STATUS_BUFFER_TOO_SMALL;
980
 
981
        // do what must be here in between --- end ---
982
 
983
        COMPLETE_REQUEST;
984
 
985
    KdPrint(("ioctl_read_vector(), Status = 0x%08x\n", Status));
986
 
987
        return Status;
988
}
989
 
990
//------------------------------------------------------------------------
991
// control or read the VIC68A on the VMEMM
992
static NTSTATUS ioctl_access_VIC68A(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
993
{
994
        NTSTATUS        Status    = STATUS_SUCCESS;
995
        ULONG           irp_info  = sizeof(PCIVME_VIC68A_ACTION);
996
        PVOID           pInputBuffer,pOutputBuffer;
997
        ULONG           InputLength, OutputLength;
998
        PCIADA      *pciada;
999
        DEVICE_EXT      *pDevExt;
1000
        PCIVME_VIC68A_ACTION *pVIC68A_action_in;
1001
        PCIVME_VIC68A_ACTION *pVIC68A_action_out;
1002
        FILE_OBJ        *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
1003
 
1004
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
1005
 
1006
        SET_BUFFERS_METHOD_BUFFERED;
1007
 
1008
    KdPrint(("ioctl_access_VIC68A(%d)\n", file_obj->uwAssociatedVMEMM));
1009
 
1010
        // do what must be here in between -----------
1011
        pVIC68A_action_in       = (PCIVME_VIC68A_ACTION *)pInputBuffer;
1012
        pVIC68A_action_out      = (PCIVME_VIC68A_ACTION *)pOutputBuffer;
1013
 
1014
        if ((pVIC68A_action_in->wRegisterAddress <= (USHORT)SRR)    &&
1015
                        ((pVIC68A_action_in->wRegisterAddress & 0x03) == 3) &&
1016
                                (OutputLength >= sizeof(PCIVME_VIC68A_ACTION)))
1017
        {
1018
                PUCHAR  pbAddress;
1019
                UCHAR   bByte=0;
1020
                KIRQL   oldIrql;
1021
 
1022
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
1023
 
1024
                pVIC68A_action_out      = pVIC68A_action_in;  // copy it  
1025
 
1026
                pbAddress = (PUCHAR)((ULONG)(pciada->pvVirtIfr) + VICBASE + pVIC68A_action_in->wRegisterAddress);
1027
 
1028
                // lock other users out
1029
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
1030
 
1031
                switch(pVIC68A_action_in->wAccessMode)
1032
                {
1033
                        case VIC68A_WRITE:      WRITE_REGISTER_UCHAR(pbAddress, pVIC68A_action_in->bContent);
1034
                                                                bByte      = READ_REGISTER_UCHAR(pbAddress);
1035
                                                                break;
1036
                        case VIC68A_WRITE_ONLY:
1037
                                                                WRITE_REGISTER_UCHAR(pbAddress, pVIC68A_action_in->bContent);
1038
                                                                break;
1039
                        case VIC68A_OR:         bByte      = READ_REGISTER_UCHAR(pbAddress);
1040
                                                                bByte     |= pVIC68A_action_in->bContent;
1041
                                                                WRITE_REGISTER_UCHAR(pbAddress, bByte);
1042
                                                                bByte      = READ_REGISTER_UCHAR(pbAddress);
1043
                                                                break;
1044
                        case VIC68A_AND:        bByte      = READ_REGISTER_UCHAR(pbAddress);
1045
                                                                bByte     &= pVIC68A_action_in->bContent;
1046
                                                                WRITE_REGISTER_UCHAR(pbAddress, bByte);
1047
                                                                bByte      = READ_REGISTER_UCHAR(pbAddress);
1048
                                                                break;
1049
                        default:                        Status = STATUS_ILLEGAL_INSTRUCTION;
1050
                        case VIC68A_READ:       bByte      = READ_REGISTER_UCHAR(pbAddress);
1051
                                                                break;
1052
                }
1053
                // free lock
1054
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
1055
 
1056
                pVIC68A_action_out->bContent = bByte;
1057
        }
1058
        else
1059
                Status = STATUS_ILLEGAL_INSTRUCTION;
1060
        // do what must be here in between --- end ---
1061
 
1062
        COMPLETE_REQUEST;
1063
 
1064
    KdPrint(("ioctl_access_VIC68A(), Status = 0x%08x\n", Status));
1065
 
1066
        return Status;
1067
}
1068
 
1069
 
1070
//------------------------------------------------------------------------
1071
// if the interrupt is disabled for a blocking path, cancel the block 
1072
static void ReleaseBlockingIrp(PDEVICE_OBJECT device_Obj, PCIADA *pciada, PFILE_OBJ pFile_obj)
1073
{
1074
        NTSTATUS Status = STATUS_CANCELLED;
1075
        PIRP                    Irp;
1076
        KIRQL                   oldIrqlCancel;
1077
        KIRQL                   oldIrqlList;
1078
 
1079
        // beware off damage due to intercept with cancel of thread
1080
        IoAcquireCancelSpinLock(&oldIrqlCancel);
1081
        KeAcquireSpinLock(&pciada->IrqListLock, &oldIrqlList);
1082
 
1083
        // get my associated packet
1084
        Irp = RemoveIRPfromQueue(device_Obj, pFile_obj);
1085
 
1086
        if (Irp != (PIRP)NULL)
1087
        {
1088
                PCIVME_VECTOR_REQUEST  *pVectorRequest  = (PCIVME_VECTOR_REQUEST  *)(Irp->AssociatedIrp.SystemBuffer);
1089
                PCIVME_VECTOR_RESPONSE *pVectorResponse = (PCIVME_VECTOR_RESPONSE *)pVectorRequest;
1090
                ULONG irp_info  = sizeof(PCIVME_VECTOR_RESPONSE);
1091
 
1092
                // pull the vectors off the fifo
1093
                pVectorResponse->wCount            = 0;
1094
                pVectorResponse->wPendingCount = 0;
1095
                pVectorResponse->bOverflow     = FALSE;
1096
                irp_info = sizeof(PCIVME_VECTOR_RESPONSE);
1097
 
1098
                // release the cancel routine from this Irp
1099
                IoSetCancelRoutine(Irp, NULL);
1100
 
1101
                COMPLETE_REQUEST;
1102
        }
1103
 
1104
        // release the spin locks
1105
        KeReleaseSpinLock(&pciada->IrqListLock, oldIrqlList);
1106
        IoReleaseCancelSpinLock(oldIrqlCancel);
1107
}
1108
 
1109
 
1110
//------------------------------------------------------------------------
1111
// switch the filling of the interrupt vector queue on or off, check the queue
1112
static NTSTATUS ioctl_control_interrupts(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
1113
{
1114
        NTSTATUS        Status    = STATUS_SUCCESS;
1115
        ULONG           irp_info  = sizeof(PCIVME_IRQ_CONTROL);
1116
        PVOID           pInputBuffer,pOutputBuffer;
1117
        ULONG           InputLength, OutputLength;
1118
        PCIADA      *pciada;
1119
        DEVICE_EXT      *pDevExt;
1120
        PCIVME_IRQ_CONTROL *pIrqControlIn;
1121
        PCIVME_IRQ_CONTROL *pIrqControlOut;
1122
        PFILE_OBJ pFile_obj = (PFILE_OBJ)Irp->Tail.Overlay.OriginalFileObject->FsContext;
1123
 
1124
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
1125
 
1126
        SET_BUFFERS_METHOD_BUFFERED;
1127
 
1128
    KdPrint(("ioctl_control_interrupts(%d)\n", pFile_obj->uwAssociatedVMEMM));
1129
 
1130
        pIrqControlIn  = (PCIVME_IRQ_CONTROL *)pInputBuffer;
1131
        pIrqControlOut = (PCIVME_IRQ_CONTROL *)pOutputBuffer;
1132
 
1133
        pciada = pDevExt->vmemm[pFile_obj->uwAssociatedVMEMM];
1134
 
1135
        // do what must be here in between -----------
1136
        if (pIrqControlIn->wEnable)
1137
        {
1138
                Status = insertQueueInList(pFile_obj, pciada);
1139
                if (!pciada->nInterruptHandlers)
1140
                {
1141
                        KdPrint(("Interrupts enabled.\n"));
1142
 
1143
                        globalInterruptEnable(pciada);
1144
                        pciada->nInterruptHandlers++;
1145
                }
1146
        }
1147
        else
1148
        {
1149
                if (pciada->nInterruptHandlers <= 1)
1150
                {
1151
                        KdPrint(("Interrupts disabled.\n"));
1152
 
1153
                        globalInterruptDisable(pciada);
1154
                        pciada->nInterruptHandlers = 0;
1155
                }
1156
 
1157
                Status = removeQueueFromList(pFile_obj, pciada);
1158
                ReleaseBlockingIrp(device_Obj, pciada, pFile_obj);
1159
        }
1160
 
1161
        // give back if the user grants space
1162
        if (OutputLength >= sizeof(PCIVME_IRQ_CONTROL))
1163
        {
1164
                pIrqControlOut->dwInterface = pFile_obj->uwAssociatedVMEMM;
1165
                pIrqControlOut->wEnable     = pFile_obj->bQueueIrq;
1166
        }
1167
 
1168
        // do what must be here in between --- end ---
1169
 
1170
        COMPLETE_REQUEST;
1171
 
1172
    KdPrint(("ioctl_control_interrupts(), Status = 0x%08x\n", Status));
1173
 
1174
        return Status;
1175
}
1176
 
1177
//------------------------------------------------------------------------
1178
// generate a uninterruptible read-modify-write cycle
1179
static NTSTATUS ioctl_TAS(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
1180
{
1181
        NTSTATUS        Status    = STATUS_SUCCESS;
1182
        ULONG           irp_info  = sizeof(PCIVME_TAS_STRUCT);
1183
        PVOID           pInputBuffer,pOutputBuffer;
1184
        ULONG           InputLength, OutputLength;
1185
        PCIADA      *pciada;
1186
        DEVICE_EXT      *pDevExt;
1187
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
1188
        KIRQL           oldIrql;
1189
        UCHAR           tempContent;
1190
        PBOOLEAN        pbPrevBusError;
1191
        PVOID       pvPartialAdr;
1192
 
1193
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
1194
 
1195
        SET_BUFFERS_METHOD_BUFFERED;
1196
 
1197
    KdPrint(("ioctl_TAS(%d)\n", file_obj->uwAssociatedVMEMM));
1198
 
1199
        // do what must be here in between -----------
1200
        if (OutputLength >= sizeof(PCIVME_TAS_STRUCT))
1201
        {
1202
                PCIVME_TAS_STRUCT *pTAS_struct_in;
1203
                PCIVME_TAS_STRUCT *pTAS_struct_out;
1204
                USHORT csr;                     // storage for old csr content
1205
                ULONG  pageAddress; // intermediate for the page register content
1206
                UCHAR  bAddressModifier;
1207
 
1208
                pTAS_struct_in  = (PCIVME_TAS_STRUCT *)pInputBuffer;
1209
                pTAS_struct_out = (PCIVME_TAS_STRUCT *)pOutputBuffer;
1210
 
1211
                pTAS_struct_out = pTAS_struct_in;
1212
                pTAS_struct_out->dwInterface = file_obj->uwAssociatedVMEMM;
1213
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
1214
 
1215
                // take the file_obj associated modifier if greater than ...
1216
                bAddressModifier = (pTAS_struct_in->wModifier > 63) ?
1217
                        file_obj->bAddressModifier : (UCHAR)pTAS_struct_in->wModifier;
1218
 
1219
                // lock other users out
1220
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
1221
 
1222
                // check for modifier (and set if needed)
1223
                if (pciada->bModifier != bAddressModifier)
1224
                {
1225
                        WRITE_REGISTER_UCHAR(pciada->pbModifier, bAddressModifier);
1226
                        pciada->bModifier = bAddressModifier;
1227
                }
1228
 
1229
                // check for page address (and set if needed)
1230
                pageAddress = pTAS_struct_in->dwAddress & ~VME_ADR_MASK;
1231
                if (pageAddress != pciada->dwVMEPage)
1232
                {
1233
                        WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
1234
                        pciada->dwVMEPage = pageAddress;
1235
                }
1236
 
1237
                // save VMEMM csr register and prepare for read modify write
1238
                csr = READ_REGISTER_USHORT(pciada->pwCSR);
1239
                WRITE_REGISTER_USHORT(pciada->pwCSR,  (USHORT)(csr | FLAG_RMC));
1240
 
1241
                // prepare the TAS
1242
                tempContent = pTAS_struct_in->bContent; // in and out point to same buffer
1243
                pvPartialAdr = (PVOID)((PUCHAR)pciada->pvVME + (pTAS_struct_in->dwAddress & VME_ADR_MASK));
1244
 
1245
                // get prepared for bus errors
1246
                file_obj->bBusError = FALSE;
1247
                pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
1248
 
1249
                // do the TAS
1250
                readByte(&pTAS_struct_out->bContent , 1, pvPartialAdr);
1251
                writeByte(pvPartialAdr , 1, &tempContent);
1252
                readByte(&tempContent , 1, pvPartialAdr);  // to overcome write on ..
1253
 
1254
                // restore csr
1255
                WRITE_REGISTER_USHORT(pciada->pwCSR, csr);
1256
 
1257
                // release the lock
1258
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
1259
                ExchangePointer(&pciada->pbBusError, pbPrevBusError);
1260
                if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
1261
        }
1262
        else
1263
                Status = STATUS_BUFFER_TOO_SMALL;
1264
 
1265
        // do what must be here in between --- end ---
1266
 
1267
        COMPLETE_REQUEST;
1268
 
1269
    KdPrint(("ioctl_TAS(), Status = 0x%08x\n", Status));
1270
 
1271
        return Status;
1272
}
1273
 
1274
//------------------------------------------------------------------------
1275
// make a VME reset
1276
static NTSTATUS ioctl_reset(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
1277
{
1278
        NTSTATUS        Status    = STATUS_SUCCESS;
1279
        ULONG           irp_info  = sizeof(PCIVME_RESET_RESULT);
1280
        PVOID           pInputBuffer,pOutputBuffer;
1281
        ULONG           InputLength, OutputLength;
1282
        DEVICE_EXT      *pDevExt;
1283
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
1284
 
1285
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
1286
 
1287
        SET_BUFFERS_METHOD_BUFFERED;
1288
 
1289
    KdPrint(("ioctl_reset(%d)\n", file_obj->uwAssociatedVMEMM));
1290
 
1291
        // do what must be here in between -----------
1292
        if (OutputLength >= sizeof(PCIVME_RESET_RESULT))
1293
        {
1294
                PCIVME_RESET_RESULT  *pResetResult  = (PCIVME_RESET_RESULT *)pOutputBuffer;
1295
                PCIVME_RESET_COMMAND *pResetCommand = (PCIVME_RESET_COMMAND *)pInputBuffer;
1296
                PCIADA                           *pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
1297
                USHORT wIRQStatus;
1298
                USHORT wControl;
1299
                UCHAR  *pbReset;
1300
                KIRQL  oldIrql;
1301
 
1302
                // set default result return size and contents
1303
                pResetResult->dwInterface       = file_obj->uwAssociatedVMEMM;
1304
 
1305
                if (pciada->dwLinkCount == 1)
1306
                {
1307
                        // lock other users out
1308
                        KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
1309
 
1310
                        // am I connected and switched on??
1311
                        if ((READ_REGISTER_USHORT(pciada->pwCntrl) & 0x0980) == 0x0980)
1312
                        {
1313
                                // do command
1314
                                switch (pResetCommand->wCommand)
1315
                                {
1316
                                        case POLL_RESET_CMD:  
1317
                                                break;
1318
                                        case VME_RESET_CMD:    
1319
                                                WRITE_REGISTER_UCHAR(pciada->pbModifier, 0);
1320
                                                pbReset = (UCHAR  *)((UCHAR *)pciada->pvVirtIfr +
1321
                                                                                                (ULONG)VICBASE + (ULONG)SRR);
1322
                                                WRITE_REGISTER_UCHAR(pbReset, 0xf0);  // make VME reset                         
1323
                                                break;
1324
                                        case LOCAL_RESET_CMD:  
1325
                                                WRITE_REGISTER_UCHAR(pciada->pbModifier, 0);
1326
                                                WRITE_REGISTER_USHORT(pciada->pwIRQStat, LOCAL_RESET);
1327
                                                break;
1328
                                        case GLOBAL_RESET_CMD:
1329
                                                WRITE_REGISTER_UCHAR(pciada->pbModifier, 0);
1330
                                                WRITE_REGISTER_USHORT(pciada->pwIRQStat, GLOBAL_RESET);
1331
                                                break;
1332
 
1333
                                        default: Status = STATUS_ILLEGAL_INSTRUCTION;
1334
                                }
1335
 
1336
                                // save IRQ status of PCIADA and switch off PCIADA interrupts
1337
                                wIRQStatus = READ_REGISTER_USHORT(pciada->pwIntCSR);
1338
                                WRITE_REGISTER_USHORT(pciada->pwIntCSR, (USHORT)(wIRQStatus & ~0x0040));
1339
 
1340
                                // always poll reset status - access will sometimes generate PCIADA #2 interrupt
1341
                                pResetResult->wResult = READ_REGISTER_UCHAR(pciada->pbModifier);
1342
 
1343
                                // reset any pending PCIADA interrupt #2  
1344
                                wControl   = READ_REGISTER_USHORT(pciada->pwCntrl);
1345
                                WRITE_REGISTER_USHORT(pciada->pwCntrl, (USHORT)(wControl & ~0x0100));
1346
                                WRITE_REGISTER_USHORT(pciada->pwCntrl, wControl);
1347
 
1348
                                // restore IRQStatus
1349
                                WRITE_REGISTER_USHORT(pciada->pwIntCSR, wIRQStatus);
1350
 
1351
                        }
1352
                        else
1353
                                Status = STATUS_ALREADY_DISCONNECTED;
1354
 
1355
                        // get other users free entry
1356
                        KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
1357
                }
1358
                else
1359
                        Status = STATUS_UNSUCCESSFUL;
1360
        }
1361
        else
1362
                Status = STATUS_BUFFER_TOO_SMALL;
1363
        // do what must be here in between --- end ---
1364
 
1365
        COMPLETE_REQUEST;
1366
 
1367
    KdPrint(("ioctl_reset(), Status = 0x%08x\n", Status));
1368
 
1369
        return Status;
1370
}
1371
 
1372
//------------------------------------------------------------------------
1373
// set parameter for this path for future access to VME
1374
static NTSTATUS ioctl_access_para(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
1375
{
1376
        NTSTATUS        Status    = STATUS_SUCCESS;
1377
        ULONG           irp_info  = 0;
1378
        PVOID           pInputBuffer,pOutputBuffer;
1379
        ULONG           InputLength, OutputLength;
1380
        PCIVME_ACCESS_COMMAND *pAccessPara;
1381
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
1382
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
1383
        PCIADA      *pciada   = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
1384
 
1385
        SET_BUFFERS_METHOD_BUFFERED;
1386
 
1387
    KdPrint(("ioctl_access_para(%d)\n", file_obj->uwAssociatedVMEMM));
1388
 
1389
        pAccessPara = (PCIVME_ACCESS_COMMAND *)pInputBuffer;
1390
 
1391
        // do here in between what has to be done -----------------
1392
        file_obj->bAddressModifier  = pAccessPara->bAddressModifier & MODIFIER_MASK;
1393
        file_obj->bAccessType       = pAccessPara->bAccessType;
1394
        file_obj->bIncrement        = pAccessPara->bIncrement;
1395
        file_obj->dwAddressMask     = pAccessPara->bAccessType - 1;
1396
 
1397
        // honor backward compatibility
1398
        if (file_obj->bAddressModifier & 0x30)
1399
                file_obj->dwAccessBase = 0;
1400
        else
1401
                file_obj->dwAccessBase      = pAccessPara->dwAccessBase;
1402
 
1403
        // access_type          increment
1404
        //      1                               0,1,2,3,4
1405
        //      2                               0,2,4
1406
        //      4                               0,4
1407
 
1408
        if (pAccessPara->bIncrement % pAccessPara->bAccessType)
1409
                Status = STATUS_DATATYPE_MISALIGNMENT;
1410
 
1411
        switch (pAccessPara->bAccessType)
1412
        {
1413
                case BYTE_ACCESS: file_obj->fRead  = readByte;
1414
                                                  file_obj->fWrite = writeByte;
1415
                                                  break;
1416
                case WORD_ACCESS: file_obj->fRead  = readWord;
1417
                                                  file_obj->fWrite = writeWord;
1418
                                                  break;
1419
                case LONG_ACCESS: if (pciada->bWordMode)
1420
                                                  {
1421
                                                        file_obj->fRead  = readWord;
1422
                                                        file_obj->fWrite = writeWord;
1423
                                                  }
1424
                                                  else
1425
                                                  {
1426
                                                        file_obj->fRead  = readLong;
1427
                                                        file_obj->fWrite = writeLong;
1428
                                                  }
1429
                                                  break;
1430
                default: Status = STATUS_UNSUCCESSFUL; break;
1431
        }
1432
        // do here in between what has to be done end -------------
1433
 
1434
        COMPLETE_REQUEST;
1435
 
1436
    KdPrint(("ioctl_access_para(), Status = 0x%08x\n", Status));
1437
 
1438
        return Status;
1439
}
1440
 
1441
//------------------------------------------------------------------------
1442
// the ultimate jumptable for ioctl
1443
//
1444
NTSTATUS (*ioctl[])(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack) =  
1445
{
1446
        ioctl_init_hardware,                    // 0
1447
        ioctl_deinit_hardware,                  // 1
1448
        ioctl_dummy,                                    // 2
1449
        ioctl_dummy,                                    // 3
1450
        ioctl_get_static_status,                // 4
1451
        ioctl_get_dynamic_status,               // 5
1452
        ioctl_read_vector,                              // 6
1453
        ioctl_access_VIC68A,                    // 7
1454
        ioctl_dummy,                                    // 8
1455
        ioctl_control_interrupts,       // 9
1456
        ioctl_TAS,                                              // 10
1457
        ioctl_dummy,                                    // 11
1458
        ioctl_reset,                                    // 12
1459
        ioctl_access_para                               // 13
1460
};
1461