Subversion Repositories f9daq

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
23 f9daq 1
//-------------------------------------------------------------------------
2
// WINNT driver for PCICC32 interface from ARW Elektronik, Germany ---------
3
// the ioctl functions
4
//
5
// (c) 1999-2002 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
// what                                            who          when
16
// started                                         AR           03.07.1999
17
// first release 1.0                                                       AR                   17.10.1999
18
// added access to PLX LC-Register                 AR           30.03.2001
19
// changed making procedure (only VCC > 6.0)       AR           30.05.2002
20
// multiple interrupt enable allowed               AR           01.06.2002
21
// added KeSynchronizeExecution for interrupt sync AR           16.06.2002
22
// extended ioctl_irq_status_kernel                AR           18.06.2002
23
//
24
 
25
//-------------------------------------------------------------------------
26
// INCLUDES
27
//
28
#include <ntddk.h>
29
#include <devioctl.h>
30
#include <pcicc32_drv.h>
31
#include <pcicc32.h>
32
#include <pcicc32_v.h>
33
#include <pcicc32_io.h>
34
#include <pcicc32_local.h>
35
#include <pcicc32_i.h>
36
 
37
//------------------------------------------------------------------------
38
// DEFINES
39
//
40
 
41
// buffers usage must match the corresponding ioctl code!
42
#define SET_BUFFERS_METHOD_OUT_DIRECT \
43
{\
44
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
45
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
46
        pInputBuffer  = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
47
        pOutputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
48
}
49
 
50
#define SET_BUFFERS_METHOD_IN_DIRECT \
51
{\
52
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
53
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
54
        pInputBuffer  = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
55
        pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
56
}
57
 
58
#define SET_BUFFERS_METHOD_BUFFERED \
59
{\
60
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
61
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
62
        pInputBuffer  = pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
63
}
64
 
65
#define COMPLETE_REQUEST \
66
{\
67
        if (Status != STATUS_PENDING)\
68
        {\
69
                Irp->IoStatus.Status      = Status; \
70
                Irp->IoStatus.Information = irp_info; \
71
                IoCompleteRequest(Irp,IO_NO_INCREMENT); \
72
        }\
73
}
74
 
75
// compatibilty issues to WIN95 driver calls
76
#ifndef WORD
77
#define WORD USHORT
78
#endif
79
 
80
#ifndef DWORD
81
#define DWORD ULONG
82
#endif
83
 
84
#ifndef BYTE
85
#define BYTE UCHAR
86
#endif
87
 
88
#ifndef BOOL
89
#define BOOL BOOLEAN
90
#endif
91
 
92
 
93
//-------------------------------------------------------------------------
94
// TYPEDEFS
95
//
96
typedef struct
97
{
98
        FILE_OBJ    *file_obj;
99
        PCIADA      *pciada;
100
        PCICC32_IRQ_RESPONSE *pIrqStatus;
101
        PIRP        *Irp;
102
        ULONG       *irp_info;
103
        NTSTATUS    *Status;
104
} IOCTL_IRQ_STATUS_CONTEXT;
105
 
106
//--------------------------------------------------------------------------
107
// LOCAL FUNCTIONS
108
//
109
 
110
//--------------------------------------------------------------------------
111
// fast read or write functions - portable -
112
static void readWord(void *to, void *from)
113
{
114
        *(PUSHORT)to = READ_REGISTER_USHORT((PUSHORT)from);
115
}
116
 
117
static void readLong(void *to, void *from)
118
{
119
        *(PULONG)to = READ_REGISTER_ULONG((PULONG)from);
120
}
121
 
122
static void writeWord(void *to, void *from)
123
{
124
        WRITE_REGISTER_USHORT((PUSHORT)to, *(PUSHORT)from);
125
}
126
 
127
static void writeLong(void *to, void *from)
128
{
129
        WRITE_REGISTER_ULONG((PULONG)to, *(PULONG)from);
130
}
131
 
132
//------------------------------------------------------------------------
133
// init the interface with build in and user supplied constants
134
static BOOLEAN InitInterface(PVOID pvLcr, PVOID pvIfr)
135
{
136
  UNREFERENCED_PARAMETER(pvLcr);
137
  UNREFERENCED_PARAMETER(pvIfr);
138
  return TRUE;
139
}
140
 
141
// deinit the interface with user supplied and build in constants
142
static BOOLEAN DeInitInterface(PVOID pvLcr, PVOID pvIfr)
143
{
144
  UNREFERENCED_PARAMETER(pvLcr);
145
  UNREFERENCED_PARAMETER(pvIfr);
146
  return TRUE;
147
}
148
 
149
//------------------------------------------------------------------------
150
// the default cancel routine for an queued Irp 
151
//
152
void CancelRequest(PDEVICE_OBJECT device_Obj, PIRP Irp)
153
{
154
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
155
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
156
        PCIADA      *pciada   = pDevExt->cc32[file_obj->uwAssociatedCC32];
157
 
158
        if (pciada->pBlockingIrp == (PIRP *)NULL)
159
        {
160
                IoReleaseCancelSpinLock(Irp->CancelIrql);
161
                KdPrint(("Nothing to do: CancelRequest(0x%08x)\n", Irp));
162
                return;
163
        }
164
        else
165
        {
166
                // release control of interrupt
167
                if (pciada->pIrqControlFile == file_obj)
168
                {
169
                        pciada->pIrqControlFile = (FILE_OBJ *)NULL;
170
                        globalInterruptDisable(pciada);
171
                }
172
 
173
                // cancel any blocking Irp origin from this file
174
                if (file_obj->blockingIrp != (PIRP)NULL)
175
                        file_obj->blockingIrp = (PIRP)NULL;
176
 
177
                if (pciada->pBlockingIrp == &file_obj->blockingIrp)
178
                        pciada->pBlockingIrp = (PIRP *)NULL;
179
 
180
                IoReleaseCancelSpinLock(Irp->CancelIrql);
181
 
182
                KdPrint(("Done: CancelRequest(0x%08x)\n", Irp));
183
 
184
                Irp->IoStatus.Status = STATUS_CANCELLED;
185
                Irp->IoStatus.Information = 0;
186
 
187
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
188
        }
189
}
190
 
191
//------------------------------------------------------------------------
192
// the custom deffered routine to finish blocking io on irq_block
193
void fMyDefferedRoutine(PKDPC Dpc, PVOID pvDevice_object, PVOID pvPciada, PVOID pdwIrqStatus)
194
{
195
        NTSTATUS Status = STATUS_SUCCESS;
196
        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
197
    PIRP  Irp = (PIRP)NULL;
198
        PCIADA          *pciada = (PCIADA *)pvPciada;
199
        KIRQL                   oldIrqlCancel;
200
 
201
        UNREFERENCED_PARAMETER(Dpc);
202
        UNREFERENCED_PARAMETER(pdwIrqStatus);
203
        UNREFERENCED_PARAMETER(pvDevice_object);
204
    KdPrint(("fMyDefferedRoutine(0x%08x)\n", pciada->dwIrqStatus));
205
 
206
        // beware off damage due to intercept at cancel of thread
207
    IoAcquireCancelSpinLock(&oldIrqlCancel);
208
 
209
        // get my associated packet
210
        if (pciada->pBlockingIrp != (PIRP *)NULL)
211
        {
212
                Irp = *pciada->pBlockingIrp;
213
 
214
                if (Irp != (PIRP)NULL) // then a blcoking Irp is waiting
215
                {
216
                        FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
217
                        PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
218
 
219
                        // fill the response structure
220
                        pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus;
221
                        pciada->dwIrqStatus = 0;          // to prevent a following direct return
222
                        pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
223
 
224
                        // release the cancel routine from this Irp
225
                        IoSetCancelRoutine(Irp, NULL);
226
 
227
                        COMPLETE_REQUEST;
228
 
229
                        file_obj->blockingIrp = (PIRP)NULL;
230
                }
231
 
232
                pciada->pBlockingIrp  = (PIRP *)NULL;
233
        }
234
 
235
        // release the spin locks
236
        IoReleaseCancelSpinLock(oldIrqlCancel);
237
}
238
 
239
//------------------------------------------------------------------------
240
// if the interrupt is disabled for a blocking path, cancel the block 
241
static void ReleaseBlockingIrp(PDEVICE_OBJECT device_Obj, PCIADA *pciada, PFILE_OBJ pFile_obj)
242
{
243
        NTSTATUS Status = STATUS_CANCELLED;
244
        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
245
    PIRP  Irp       = (PIRP)NULL;
246
        KIRQL oldIrqlCancel;
247
        UNREFERENCED_PARAMETER(device_Obj);
248
        UNREFERENCED_PARAMETER(pFile_obj);
249
 
250
        UNREFERENCED_PARAMETER(irp_info);
251
    KdPrint(("ReleaseBlockingIrp()\n"));
252
 
253
        // beware off damage due to intercept with cancel of thread
254
        IoAcquireCancelSpinLock(&oldIrqlCancel);
255
 
256
        if (pciada->pBlockingIrp != (PIRP *)NULL)
257
        {
258
                // get my associated packet
259
                Irp = *pciada->pBlockingIrp;
260
 
261
                if (Irp != (PIRP)NULL)
262
                {
263
                        FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
264
                        PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
265
                        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
266
 
267
                        pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus;
268
                        pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
269
 
270
                        // release the cancel routine from this Irp
271
                        IoSetCancelRoutine(Irp, NULL);
272
 
273
                        COMPLETE_REQUEST;
274
 
275
                        file_obj->blockingIrp = (PIRP)NULL;
276
                }
277
 
278
                pciada->pBlockingIrp = (PIRP *)NULL; // mark the storage for blocking Irp free
279
        }
280
 
281
        // release the spin locks
282
        IoReleaseCancelSpinLock(oldIrqlCancel);
283
}
284
 
285
//------------------------------------------------------------------------
286
// all functions called from ioctl jump table
287
//
288
 
289
//------------------------------------------------------------------------
290
// a dummy entry because of compatibiltiy (near) WIN95 driver
291
static NTSTATUS ioctl_dummy(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
292
{
293
        NTSTATUS        Status    = STATUS_SUCCESS;
294
        ULONG           irp_info  = 0;
295
        PVOID           pInputBuffer,pOutputBuffer;
296
        ULONG           InputLength, OutputLength;
297
        char            *pCommand;
298
 
299
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
300
#ifndef _DEBUG
301
        UNREFERENCED_PARAMETER(file_obj);
302
#endif
303
        SET_BUFFERS_METHOD_BUFFERED;
304
        UNREFERENCED_PARAMETER(device_Obj);
305
        pCommand = (char *)pInputBuffer;
306
 
307
    KdPrint(("ioctl_dummy(%d)\n", file_obj->uwAssociatedCC32));
308
 
309
        // do what must be here in between -----------
310
 
311
        // do what must be here in between --- end ---
312
 
313
        COMPLETE_REQUEST;
314
 
315
    KdPrint(("ioctl_dummy(), Status = 0x%08x\n", Status));
316
 
317
        return Status;
318
}
319
 
320
//------------------------------------------------------------------------
321
// requests status
322
static NTSTATUS ioctl_get_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
323
{
324
        NTSTATUS        Status    = STATUS_SUCCESS;
325
        ULONG           irp_info  = sizeof(PCICC32_STATUS);
326
        PVOID           pInputBuffer,pOutputBuffer;
327
        ULONG           InputLength, OutputLength;
328
        PCIADA      *pciada;
329
        DEVICE_EXT      *pDevExt;
330
        PCICC32_STATUS *pStatus;
331
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
332
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
333
 
334
        // do what must be here in between -----------
335
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
336
 
337
        SET_BUFFERS_METHOD_BUFFERED;
338
 
339
    KdPrint(("ioctl_get_status(%d)\n", wModuleNumber));
340
 
341
        // do what must be here in between -----------
342
        if (OutputLength >= sizeof(PCICC32_STATUS))
343
        {
344
                USHORT temp;
345
 
346
                pStatus = (PCICC32_STATUS *)pOutputBuffer;
347
 
348
                pciada = pDevExt->cc32[wModuleNumber];
349
 
350
                pStatus->dwInterface    = wModuleNumber;
351
 
352
                temp = READ_REGISTER_USHORT(pciada->pwIntCSR);
353
                pStatus->bTimeout                       = (temp & 0x0020) ? 1 : 0;
354
                pStatus->bInterrupt                     = (temp & 0x0004) ? 1 : 0;
355
        }
356
        else
357
                Status = STATUS_BUFFER_TOO_SMALL;
358
        // do what must be here in between --- end ---
359
 
360
        COMPLETE_REQUEST;
361
 
362
    KdPrint(("ioctl_get_status(), Status = 0x%08x\n", Status));
363
 
364
        return Status;
365
}
366
 
367
//------------------------------------------------------------------------
368
// clears status
369
static BOOLEAN ioctl_clear_status_kernel(PVOID pvContext)
370
{
371
        PCIADA *pciada = (PCIADA *)pvContext;
372
        USHORT wCntrl;
373
 
374
        // get current Cntrl - and clear interrupt
375
        wCntrl  = READ_REGISTER_USHORT(pciada->pwCntrl);
376
        wCntrl &= ~0x0100;  // disable
377
        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
378
        wCntrl |= 0x0100;   // enable again
379
        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
380
 
381
        return TRUE;
382
}
383
 
384
static NTSTATUS ioctl_clear_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
385
{
386
        NTSTATUS        Status    = STATUS_SUCCESS;
387
        ULONG           irp_info  = 0;
388
        PVOID           pInputBuffer,pOutputBuffer;
389
        ULONG           InputLength, OutputLength;
390
        PCIADA      *pciada;
391
        DEVICE_EXT      *pDevExt;
392
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
393
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
394
 
395
        // do what must be here in between -----------
396
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
397
 
398
        SET_BUFFERS_METHOD_BUFFERED;
399
 
400
    KdPrint(("ioctl_clear_status(%d)\n", wModuleNumber));
401
 
402
        // do what must be here in between -----------
403
        pciada = pDevExt->cc32[wModuleNumber];
404
 
405
        KeSynchronizeExecution(pciada->InterruptObject, ioctl_clear_status_kernel, pciada);
406
 
407
        // do what must be here in between --- end ---
408
 
409
        COMPLETE_REQUEST;
410
 
411
    KdPrint(("ioctl_clear_status() OK\n"));
412
 
413
        return Status;
414
}
415
 
416
//------------------------------------------------------------------------
417
// set parameter for this path for future access to CC32
418
static NTSTATUS ioctl_access_para(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
419
{
420
        NTSTATUS        Status    = STATUS_SUCCESS;
421
        ULONG           irp_info  = 0;
422
        PVOID           pInputBuffer,pOutputBuffer;
423
        ULONG           InputLength, OutputLength;
424
        PCICC32_ACCESS_COMMAND *pAccessPara;
425
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
426
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
427
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
428
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
429
        UNREFERENCED_PARAMETER(pciada);
430
        SET_BUFFERS_METHOD_BUFFERED;
431
 
432
    KdPrint(("ioctl_access_para(%d)\n", wModuleNumber));
433
 
434
        pAccessPara = (PCICC32_ACCESS_COMMAND *)pInputBuffer;
435
 
436
        // do here in between what has to be done -----------------
437
        file_obj->wAccessType       = pAccessPara->wAccessType;
438
        file_obj->wBlockTransfer    = pAccessPara->wBlockTransfer;
439
 
440
        pAccessPara->dwInterface = wModuleNumber;
441
 
442
        switch (pAccessPara->wAccessType)
443
        {
444
                case WORD_ACCESS: file_obj->fRead  = readWord;
445
                                                  file_obj->fWrite = writeWord;
446
                                                  break;
447
                case LONG_ACCESS: file_obj->fRead  = readLong;
448
                                                  file_obj->fWrite = writeLong;
449
                                                  break;
450
                default: Status = STATUS_UNSUCCESSFUL;
451
                                                  break;
452
        }
453
        // do here in between what has to be done end -------------
454
 
455
        COMPLETE_REQUEST;
456
 
457
    KdPrint(("ioctl_access_para(), Status = 0x%08x\n", Status));
458
 
459
        return Status;
460
}
461
 
462
//------------------------------------------------------------------------
463
// allow or inhibit interrupt requests from either CC32 or thru local timeout
464
static NTSTATUS ioctl_control_interrupts(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
465
{
466
        NTSTATUS        Status    = STATUS_SUCCESS;
467
        ULONG           irp_info  = 0;
468
        PVOID           pInputBuffer,pOutputBuffer;
469
        ULONG           InputLength, OutputLength;
470
        PCICC32_IRQ_CONTROL *pIrqControlIn, *pIrqControlOut;
471
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
472
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
473
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
474
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
475
 
476
        SET_BUFFERS_METHOD_BUFFERED;
477
 
478
    KdPrint(("ioctl_control_interrupts(%d)\n", wModuleNumber));
479
 
480
        pIrqControlIn  = (PCICC32_IRQ_CONTROL *)pInputBuffer;
481
        pIrqControlOut = (PCICC32_IRQ_CONTROL *)pOutputBuffer;
482
 
483
        // do here in between what has to be done -----------------
484
        if (pIrqControlIn->wEnable)
485
        {
486
                // reserve the controlling of interrupts for this path
487
                if ((pciada->pIrqControlFile == (FILE_OBJ *)NULL) ||
488
                        (pciada->pIrqControlFile == file_obj))
489
                {
490
                        pciada->pIrqControlFile = file_obj;
491
                        globalInterruptEnable(pciada);
492
                }
493
                else
494
                        Status = STATUS_DEVICE_BUSY;
495
        }
496
        else
497
        {
498
                // nobody else is allowed to disable interrupts
499
                if (pciada->pIrqControlFile == file_obj)
500
                {
501
                        pciada->pIrqControlFile = (FILE_OBJ *)NULL;
502
                        globalInterruptDisable(pciada);
503
                }
504
                else
505
                        Status = STATUS_DEVICE_BUSY;
506
        }
507
 
508
        // give back if the user grants space
509
        if (OutputLength >= sizeof(PCICC32_IRQ_CONTROL))
510
        {
511
                pIrqControlOut->dwInterface = wModuleNumber;
512
                pIrqControlOut->wEnable     = globalInterruptEnabledStatus(pciada);
513
        }      
514
        // do here in between what has to be done end -------------
515
 
516
        COMPLETE_REQUEST;
517
 
518
    KdPrint(("ioctl_control_interrupts(), Status = 0x%08x\n", Status));
519
 
520
        return Status;
521
}
522
 
523
//------------------------------------------------------------------------
524
// implements a blocking io-call to get irq status.
525
static BOOLEAN ioctl_irq_status_kernel(PVOID pvContext)
526
{
527
        IOCTL_IRQ_STATUS_CONTEXT *context = (IOCTL_IRQ_STATUS_CONTEXT *)pvContext;
528
    KIRQL       oldIrql;
529
 
530
        if (context->pciada->dwIrqStatus)
531
        {
532
                // there is a pending interrupt - return immediately
533
                KdPrint(("ioctl_irq_status(), direct return (0x%08x)\n", context->pciada->dwIrqStatus));
534
 
535
                context->pIrqStatus->dwInterruptFlags = context->pciada->dwIrqStatus;
536
                context->pciada->dwIrqStatus          = 0;  // release pending status
537
 
538
                *context->irp_info = sizeof(PCICC32_IRQ_RESPONSE);
539
        }
540
        else
541
        {
542
                // make the request blocking
543
                IoAcquireCancelSpinLock(&oldIrql);
544
 
545
                if ((*context->Irp)->Cancel)    // cancel while doing
546
                {
547
                        KdPrint(("ioctl_irq_status(), canceled return\n"));
548
                        *context->Status = STATUS_CANCELLED;
549
                }
550
                else
551
                {
552
                        KdPrint(("ioctl_irq_status(), blocking\n"));
553
 
554
                        if (context->pciada->pBlockingIrp != (PIRP *)NULL)
555
                        {
556
                                // a Irp is still waiting
557
                                *context->Status = STATUS_DEVICE_BUSY;
558
                        }
559
                        else
560
                        {
561
                                context->file_obj->blockingIrp = *context->Irp;
562
                                context->pciada->pBlockingIrp  = &context->file_obj->blockingIrp;
563
 
564
                                *context->Status = STATUS_PENDING;
565
 
566
                                // mark irp as pending and return
567
                                IoMarkIrpPending(*context->Irp);
568
                                IoSetCancelRoutine(*context->Irp, CancelRequest);
569
                        }
570
                } // if (Irp->Cancel) ...
571
        }
572
 
573
        return TRUE;
574
}
575
 
576
static NTSTATUS ioctl_irq_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
577
{
578
        NTSTATUS        Status    = STATUS_SUCCESS;
579
        ULONG           irp_info  = 0;
580
        PVOID           pInputBuffer,pOutputBuffer;
581
        ULONG           InputLength, OutputLength;
582
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
583
        USHORT      wModuleNumber;
584
        IOCTL_IRQ_STATUS_CONTEXT context;
585
 
586
        SET_BUFFERS_METHOD_BUFFERED;
587
 
588
        context.file_obj   = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
589
        wModuleNumber      = context.file_obj->uwAssociatedCC32;
590
        context.pciada     = pDevExt->cc32[wModuleNumber];
591
        context.pIrqStatus = (PCICC32_IRQ_RESPONSE *)pOutputBuffer;
592
        context.Status     = &Status;
593
        context.irp_info   = &irp_info;
594
        context.Irp        = &Irp;
595
 
596
 
597
    KdPrint(("ioctl_irq_status(%d)\n", wModuleNumber));
598
 
599
        // do here in between what has to be done -----------------
600
        if (OutputLength < sizeof(PCICC32_IRQ_RESPONSE))
601
                Status = STATUS_BUFFER_TOO_SMALL;
602
        else
603
        {
604
                context.pIrqStatus->dwInterface = wModuleNumber;
605
 
606
            KeSynchronizeExecution(context.pciada->InterruptObject, ioctl_irq_status_kernel, &context);
607
        }
608
        // do here in between what has to be done end -------------
609
 
610
        COMPLETE_REQUEST;
611
 
612
    KdPrint(("ioctl_irq_status(), Status = 0x%08x\n", Status));
613
 
614
        return Status;
615
}
616
 
617
 
618
//------------------------------------------------------------------------
619
// for test and debug purposes: direkt access to PLX LCR space
620
static NTSTATUS ioctl_access_lcr(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
621
{
622
        NTSTATUS        Status    = STATUS_SUCCESS;
623
        ULONG           irp_info  = 0;
624
        PVOID           pInputBuffer,pOutputBuffer;
625
        ULONG           InputLength, OutputLength;
626
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
627
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
628
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
629
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
630
        PCICC32_LCR_ACCESS *pAccessOut;
631
        PCICC32_LCR_ACCESS *pAccessIn;
632
 
633
        SET_BUFFERS_METHOD_BUFFERED;
634
 
635
    KdPrint(("ioctl_access_lcr(%d)\n", wModuleNumber));
636
 
637
        pAccessOut = (PCICC32_LCR_ACCESS *)pOutputBuffer;
638
        pAccessIn  = (PCICC32_LCR_ACCESS *)pInputBuffer;
639
 
640
        // do here in between what has to be done -----------------
641
        if (OutputLength < sizeof(PCICC32_LCR_ACCESS))
642
                Status = STATUS_BUFFER_TOO_SMALL;
643
        else
644
        {
645
                *pAccessOut = *pAccessIn;
646
                pAccessOut->dwInterface = wModuleNumber;
647
 
648
                if (pAccessIn->wRegisterAddress <= 0x52)
649
                {
650
                        // 1st part: long word accesses
651
                        if (pAccessIn->bBytesLane == LONG_ACCESS)
652
                        {
653
                                if (pAccessIn->wRegisterAddress & 0x0003)
654
                                        Status = STATUS_INSTRUCTION_MISALIGNMENT;
655
                                else
656
                                {
657
                                        ULONG       *pdwVirtAddress;
658
                                        ULONG           dwDummy;
659
 
660
                                        pdwVirtAddress = (ULONG *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
661
 
662
                                        switch (pAccessIn->bAccessMode)
663
                                        {
664
                                                case LCR_WRITE:
665
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
666
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
667
                                                        break;
668
                                                case LCR_OR:
669
                                                        dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
670
                                                        dwDummy |= pAccessIn->dwContent;
671
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
672
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
673
                                                        break;
674
                                                case LCR_AND:
675
                                                        dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
676
                                                        dwDummy &= pAccessIn->dwContent;
677
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
678
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
679
                                                        break;
680
                                                case LCR_WRITE_ONLY:
681
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
682
                                                        break;
683
                                                case LCR_READ:
684
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
685
                                                        break;
686
 
687
                                                default: Status = STATUS_ILLEGAL_INSTRUCTION;
688
                                        }
689
                                }
690
                        }
691
 
692
                        // 2nd part: short word accesses
693
                        if (pAccessIn->bBytesLane == WORD_ACCESS)
694
                        {
695
                                if (pAccessIn->wRegisterAddress & 0x0001)
696
                                        Status = STATUS_INSTRUCTION_MISALIGNMENT;
697
                                else
698
                                {
699
                                        USHORT      *pwVirtAddress;
700
                                        USHORT          wDummy;
701
 
702
                                        pwVirtAddress = (USHORT *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
703
 
704
                                        switch (pAccessIn->bAccessMode)
705
                                        {
706
                                                case LCR_WRITE:
707
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
708
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
709
                                                        break;
710
                                                case LCR_OR:
711
                                                        wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
712
                                                        wDummy |= (USHORT)pAccessIn->dwContent;
713
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
714
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
715
                                                        break;
716
                                                case LCR_AND:
717
                                                        wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
718
                                                        wDummy &= (USHORT)pAccessIn->dwContent;
719
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
720
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
721
                                                        break;
722
                                                case LCR_WRITE_ONLY:
723
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
724
                                                        break;
725
                                                case LCR_READ:
726
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
727
                                                        break;
728
 
729
                                                default: Status = STATUS_ILLEGAL_INSTRUCTION;
730
                                                        break;
731
                                        }
732
                                }
733
                        }
734
 
735
                        // 3rd part: check illegal byte lanes
736
                        if (!((pAccessIn->bBytesLane == LONG_ACCESS) || (pAccessIn->bBytesLane == WORD_ACCESS)))
737
                                Status = STATUS_ILLEGAL_INSTRUCTION;
738
                }
739
                else
740
                        Status = STATUS_ILLEGAL_INSTRUCTION;
741
        }      
742
        // do here in between what has to be done end -------------
743
 
744
        if (Status == STATUS_SUCCESS)          
745
                irp_info = sizeof(PCICC32_LCR_ACCESS);
746
 
747
        COMPLETE_REQUEST;
748
 
749
    KdPrint(("ioctl_access_lcr(), Status = 0x%08x\n", Status));
750
 
751
        return Status;
752
}
753
 
754
 
755
//------------------------------------------------------------------------
756
// the ultimate jumptable for ioctl
757
//
758
NTSTATUS (*ioctl[])(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack) =  
759
{
760
        ioctl_dummy,                                    // 0
761
        ioctl_dummy,                                    // 4
762
        ioctl_get_status,                               // 8
763
        ioctl_clear_status,                             // 0x0c
764
        ioctl_access_para,                              // 0x10
765
        ioctl_control_interrupts,       // 0x14
766
        ioctl_dummy,                    // 0x18
767
        ioctl_irq_status,               // 0x1c
768
        ioctl_access_lcr                // 0x20
769
};
770