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