Subversion Repositories f9daq

Rev

Rev 41 | Go to most recent revision | Details | 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 main body of the driver
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_drv.c,v $
16
// Revision 1.3  2004/07/24 07:07:26  klaus
17
// Update copyright to 2004
18
//
19
//
20
// what                                            who          when
21
// started                                         AR           15.06.1999
22
// first release 1.0                               AR           17.10.1999
23
// fixed error in PLX9050Bug                       AR           28.02.2000
24
// PLX9050Bugfix bug fixed                         AR           03.03.2000
25
// PCICC32 CAMAC Interface conflict solved         AR           03.03.2000
26
// Version 1.1 released                            AR           03.03.2000
27
// register all used resources, the idle too       AR           25.11.2001
28
// changed resource allocation caused by WIN2000   AR           08.06.2002
29
//
30
 
31
//-------------------------------------------------------------------------
32
// INCLUDES
33
//
34
 
35
#include <ntddk.h>
36
#include <devioctl.h>
37
#include <pcivme_drv.h>
38
#include <pcivme_v.h>
39
#include <pcivme_io.h>
40
#include <pcivme_i.h>
41
#include <pcivme.h>
42
#include <pciif.h>
43
#include <pcivme_fifo.h>
44
 
45
//------------------------------------------------------------------------
46
// DEFINES
47
//
48
#ifndef DWORD
49
#define DWORD ULONG
50
#endif
51
 
52
#ifndef WORD
53
#define WORD USHORT
54
#endif
55
 
56
#define CTL_INDEX(x) ((x >> 2) & 0x7FF)  // get user control code as index
57
#define IRQ_LIST_LENGTH 128     // max count of irqs in FIFO for each file_obj
58
 
59
#define RESOURCE_ENTRY_COUNT 6          // WIN2000 forces to claim all entries
60
 
61
#define DOS_DEVICE_NAME L"\\DosDevices\\PCIVME:"
62
 
63
//------------------------------------------------------------------------
64
// GLOBALS
65
//
66
 
67
//------------------------------------------------------------------------
68
// FUNCTIONS
69
//
70
 
71
//------------------------------------------------------------------------
72
// exchange the pointer to Bus Error 
73
//
74
PBOOLEAN ExchangePointer(PBOOLEAN *current, PBOOLEAN next)
75
{
76
        PBOOLEAN pb;
77
 
78
        pb       = *current;
79
        *current = next;
80
 
81
        return pb;
82
}
83
 
84
//------------------------------------------------------------------------
85
// get the vmemm number out of the filename
86
//
87
NTSTATUS InterpreteFileName(PCHAR name, int *nVmemm)
88
{
89
        char *ptr = name;
90
    char *n   = "vmemm";
91
        int  h = -1;  // high part
92
        int  l = -1;  // low part
93
 
94
        if (*ptr == '\\') ptr++; // jump over leading ...
95
 
96
    while (*n)                           // compare the basename
97
          if (*n == tolower(*ptr))     
98
          {
99
                  n++;
100
                  ptr++;
101
          }
102
          else
103
                  return STATUS_NO_SUCH_FILE;
104
 
105
        h = *ptr - '0';                  // get the number
106
        ptr++;
107
        l = *ptr - '0';
108
 
109
        if (*ptr == 0)                   // still over the end ??
110
        {
111
                l = h;
112
                h = 0;
113
        }
114
        else
115
          ptr++;
116
 
117
        if ((h < 0) || (l < 0) || (*ptr != 0))  // anything wrong ??
118
                  return STATUS_NO_SUCH_FILE;
119
 
120
        *nVmemm = (h * 10) + l;  // calculate number
121
 
122
        if (*nVmemm >= PCIVME_MAX_VMEMM) // out of range ??
123
                  return STATUS_NO_SUCH_FILE;
124
 
125
        return STATUS_SUCCESS;
126
}
127
 
128
//------------------------------------------------------------------------
129
// the ultimate driver unload
130
VOID PCIVMEUnload(PDRIVER_OBJECT driverObj)
131
{
132
        int              i;
133
        UNICODE_STRING symbol_name;
134
        DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
135
        int         nPCIADAs = ext->nPCIADAs;
136
        PCIADA      *pciada;
137
 
138
    KdPrint(("PCIVMEUnload()\n"));
139
 
140
        switch (ext->nInitState)
141
        {
142
                case 8:
143
                case 7:
144
                        // stop interrupts and shut off
145
                        PCIVMEDeInitPCIADAs(driverObj->DeviceObject);
146
                        PCIVMEDisConnectInterrupt(driverObj->DeviceObject);
147
 
148
                        // remove interrupt lists
149
                        for (i = 0; i < nPCIADAs; i++)
150
                        {
151
                                pciada = &ext->pciada[i];
152
 
153
                                // removeQueueFromList(...)
154
                                while (IsListEmpty(&pciada->IrqListList) == FALSE)
155
                                {
156
                                        PLIST_ENTRY pList;
157
                                        FIFO_LIST   *next;
158
 
159
                                        KdPrint(("RemoveHeadList(0x%08x)\n", &pciada->IrqListList));
160
                                        pList = RemoveHeadList(&pciada->IrqListList);
161
                                        next  = CONTAINING_RECORD(pList, FIFO_LIST, entry);
162
 
163
                                        ExFreePool((PVOID)next);
164
                                }
165
                        }
166
                case 6:
167
                        // InitializeIRPQueue has no counterpart
168
                case 5:
169
                        // KeInitializeDpc has no counterpart
170
                case 4:
171
                        // release io spaces
172
                        for (i = 0; i < nPCIADAs; i++)
173
                        {
174
                                pciada = &ext->pciada[i];
175
 
176
                                if (pciada->pvVirtLcr != NULL)
177
                                        MmUnmapIoSpace(pciada->pvVirtLcr, LCR_SPACE);
178
                                if (pciada->pvVirtIfr != NULL)
179
                                        MmUnmapIoSpace(pciada->pvVirtIfr, IFR_SPACE);
180
                        }
181
                case 3:
182
                        // HalGetInterruptVector has no counterpart
183
                case 2:
184
                        // HalTranslateBusAddress has no counterpart
185
                case 1:
186
                        PCIVMEFreeResources(driverObj->DeviceObject);
187
                default:
188
                case 0:
189
                        RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
190
 
191
                        // delete the symbolicLink in the registry 
192
                        IoDeleteSymbolicLink( &symbol_name);
193
 
194
                        // delete the deviceObject 
195
                        IoDeleteDevice(driverObj->DeviceObject);
196
        }
197
 
198
        KdPrint(("PCIVMEUnload() OK.\n"));
199
}
200
 
201
 
202
//------------------------------------------------------------------------
203
// called at CreateFile()
204
NTSTATUS PCIVMEOpen(PDEVICE_OBJECT deviceObj, PIRP Irp)
205
{
206
        NTSTATUS result = STATUS_SUCCESS;
207
    ANSI_STRING name;
208
    int nVmemm;
209
        int i;
210
        DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
211
        PCIADA      *pciada;
212
        FILE_OBJ        *file_obj = (FILE_OBJ *)NULL;
213
 
214
        name.Buffer = NULL;
215
    name.MaximumLength = 80;
216
 
217
        result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
218
        if (result != STATUS_SUCCESS) goto fin;
219
 
220
        result = InterpreteFileName(name.Buffer, &nVmemm);
221
    if (result != STATUS_SUCCESS) goto fin;
222
 
223
    KdPrint(("PCIVMEOpen(%d)\n", nVmemm));
224
        RtlFreeAnsiString(&name);
225
 
226
    file_obj = (FILE_OBJ *)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJ),'nepo');
227
        if (file_obj == (FILE_OBJ *)NULL)
228
        {
229
                result = STATUS_NO_MEMORY;
230
                goto fin;
231
        }
232
 
233
        file_obj->uwAssociatedVMEMM = (USHORT) nVmemm;
234
        file_obj->bAddressModifier  = 0x39;
235
        file_obj->bAccessType       = BYTE_ACCESS;
236
        file_obj->bIncrement        = BYTE_ACCESS; // increments each byte
237
        file_obj->dwAccessBase      = 0;           // normal setting for all but extended
238
 
239
        file_obj->bQueueIrq                     = FALSE;
240
        result = InitializeFIFO(IRQ_LIST_LENGTH, &file_obj->pIrqListHandle);
241
        if (result != STATUS_SUCCESS) goto fin;
242
 
243
    Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
244
 
245
        result = PCIVMEScanVMEMM(deviceObj);
246
        if (result != STATUS_SUCCESS) goto fin;
247
 
248
        for (i = 0; i < pDevExt->nPCIADAs; i++)
249
        {
250
          pciada = &pDevExt->pciada[i];
251
 
252
          if (pciada->wModuleNumber == nVmemm)
253
          {
254
                  pDevExt->vmemm[nVmemm] = pciada; // create association
255
                  pciada->dwLinkCount++;
256
                  break;
257
          }
258
        }
259
 
260
        if (i >= pDevExt->nPCIADAs)
261
        {
262
                result = STATUS_NO_SUCH_FILE;
263
                goto fin;
264
        }
265
 
266
        fin:
267
        Irp->IoStatus.Status = result;
268
        Irp->IoStatus.Information = 0;
269
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
270
 
271
        // be careful when releasing allocated memory !
272
        if (result != STATUS_SUCCESS)
273
                if (file_obj != (FILE_OBJ *)NULL)
274
                        if (file_obj->pIrqListHandle != (PVOID)NULL)
275
                                DestroyFIFO(file_obj->pIrqListHandle);
276
 
277
        return result;
278
}
279
 
280
//------------------------------------------------------------------------
281
// called at close()
282
NTSTATUS PCIVMEClose(PDEVICE_OBJECT deviceObj, PIRP Irp)
283
{
284
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(deviceObj->DeviceExtension);
285
        FILE_OBJ    *file_obj = (FILE_OBJ *)NULL;
286
        PCIADA      *pciada;                   
287
 
288
        file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
289
 
290
    KdPrint(("PCIVMEClose(%d)\n", file_obj->uwAssociatedVMEMM));
291
 
292
        if (file_obj != (FILE_OBJ *)NULL)
293
        {
294
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
295
                pciada->dwLinkCount--;
296
 
297
                // remove the ListEntry(s) associated with this path
298
        removeQueueFromList(file_obj, pciada);
299
 
300
            // empty and remove the interrupt queue (if there is anything stored)
301
                DestroyFIFO(file_obj->pIrqListHandle);
302
 
303
                ExFreePool(file_obj);
304
                Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
305
        }
306
 
307
        KdPrint(("PCIVMEClose OK\n"));
308
 
309
    Irp->IoStatus.Status = STATUS_SUCCESS;
310
        Irp->IoStatus.Information = 0;
311
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
312
 
313
        return STATUS_SUCCESS;
314
}
315
 
316
//------------------------------------------------------------------------
317
// called at 
318
NTSTATUS PCIVMEShutdown(PDEVICE_OBJECT deviceObj, PIRP  irp  )
319
{
320
        UNREFERENCED_PARAMETER(irp);
321
 
322
    KdPrint(("PCIVMEShutdown()\n"));
323
 
324
        // deinit interfaces and interrupts
325
        PCIVMEDeInitPCIADAs(deviceObj);
326
 
327
    KdPrint(("PCIVMEShutdown() OK\n"));
328
 
329
        return STATUS_SUCCESS;
330
}
331
 
332
//------------------------------------------------------------------------
333
// called at ioctl()
334
NTSTATUS PCIVMEDeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
335
{
336
        PIO_STACK_LOCATION IrpStack;
337
        int   nIndex;
338
 
339
        IrpStack  = IoGetCurrentIrpStackLocation(Irp);
340
        nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
341
 
342
    KdPrint(("PCIVMEDeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
343
 
344
        if (nIndex > CTL_INDEX(PCIVME_LAST_CTL_CODE))
345
        {
346
                Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
347
                Irp->IoStatus.Information = 0;
348
                IoCompleteRequest(Irp,IO_NO_INCREMENT);
349
 
350
        KdPrint(("PCIVMEDeviceControl() FAIL.\n"));
351
 
352
                return STATUS_UNSUCCESSFUL;
353
        }
354
 
355
        return ioctl[nIndex](deviceObj, Irp, IrpStack);
356
}
357
 
358
 
359
//------------------------------------------------------------------------
360
// called at read()
361
NTSTATUS PCIVMERead(PDEVICE_OBJECT device_Obj, PIRP Irp)
362
{
363
        NTSTATUS        Status        = STATUS_SUCCESS;
364
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
365
        PVOID           pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
366
        LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
367
        FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
368
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
369
  PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
370
        register ULONG Address  = IrpStack->Parameters.Read.ByteOffset.LowPart  + file_obj->dwAccessBase;  
371
        ULONG storeLength                   = 0;
372
        PBOOLEAN pbPrevBusError;
373
 
374
        KdPrint(("PCIVMERead(%d)\n", file_obj->uwAssociatedVMEMM));
375
 
376
        // do here in between what has to be done -----------------
377
  if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
378
                Status = STATUS_DATATYPE_MISALIGNMENT;
379
        else
380
        {
381
                register ULONG Length = IrpStack->Parameters.Read.Length;    
382
                register ULONG blockLength;
383
                register ULONG pageAddress;
384
                register ULONG toNextPage;
385
                KIRQL              oldIrql;
386
 
387
                Length     &= ~file_obj->dwAddressMask; // align to integer increments
388
                storeLength = Length;
389
 
390
                // lock other users out
391
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
392
 
393
                // check for modifier
394
                if (pciada->bModifier != file_obj->bAddressModifier)
395
                {
396
                        WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
397
                        pciada->bModifier = file_obj->bAddressModifier;
398
                }
399
 
400
                // do the read ---
401
                file_obj->bBusError = FALSE;
402
                pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
403
                while (Length)
404
                {
405
                        pageAddress = Address & ~VME_ADR_MASK;
406
                        if (pageAddress != pciada->dwVMEPage)
407
                        {
408
                                WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
409
                                pciada->dwVMEPage = pageAddress;
410
                        }
411
 
412
                        toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
413
                        blockLength = (toNextPage < Length) ? toNextPage : Length;
414
 
415
                        KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
416
                                                                                Address, blockLength, Length));
417
 
418
                        file_obj->fRead(pOutputBuffer , blockLength, (PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)));
419
 
420
                        Length  -= blockLength;
421
                        Address += blockLength;
422
                        pOutputBuffer = (PVOID)((PUCHAR)pOutputBuffer + blockLength);
423
                }
424
 
425
                // release the lock
426
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
427
                ExchangePointer(&pciada->pbBusError, pbPrevBusError);
428
                if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
429
 
430
            if (file_obj->bIncrement)  // only when increment to next is on
431
                        *fileOffset =
432
                                RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
433
        }
434
        // do here in between what has to be done end -------------
435
 
436
        Irp->IoStatus.Status      = Status;  
437
        Irp->IoStatus.Information = storeLength;  
438
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
439
 
440
    KdPrint(("PCIVMERead(), Status = 0x%08x\n", Status));
441
 
442
        return Status;
443
}
444
 
445
 
446
//------------------------------------------------------------------------
447
// called at write()
448
NTSTATUS PCIVMEWrite(PDEVICE_OBJECT device_Obj, PIRP Irp)
449
{
450
        NTSTATUS        Status        = STATUS_SUCCESS;
451
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
452
        PVOID           pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
453
        LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
454
        FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
455
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
456
  PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
457
        register ULONG Address  = IrpStack->Parameters.Write.ByteOffset.LowPart + file_obj->dwAccessBase;  
458
        ULONG storeLength                   = 0;
459
        PBOOLEAN pbPrevBusError;
460
 
461
        KdPrint(("PCIVMEWrite(%d)\n", file_obj->uwAssociatedVMEMM));
462
 
463
        // do here in between what has to be done -----------------
464
  if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
465
                Status = STATUS_DATATYPE_MISALIGNMENT;
466
        else
467
        {
468
                register ULONG Length = IrpStack->Parameters.Write.Length;    
469
                register ULONG blockLength;
470
                register ULONG pageAddress;
471
                register ULONG toNextPage;
472
                KIRQL              oldIrql;
473
 
474
                Length     &= ~file_obj->dwAddressMask; // align to integer increments
475
                storeLength = Length;
476
                                                       // check for modifier
477
                // lock other users out
478
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
479
 
480
                if (pciada->bModifier != file_obj->bAddressModifier)
481
                {
482
                        WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
483
                        pciada->bModifier = file_obj->bAddressModifier;
484
                }
485
 
486
                // do the read ---
487
                file_obj->bBusError = FALSE;
488
                pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
489
                while (Length)
490
                {
491
                        pageAddress = Address & ~VME_ADR_MASK;
492
                        if (pageAddress != pciada->dwVMEPage)
493
                        {
494
                                WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
495
                                pciada->dwVMEPage = pageAddress;
496
                        }
497
 
498
                        toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
499
                        blockLength = (toNextPage < Length) ? toNextPage : Length;
500
 
501
                        KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
502
                                                                                Address, blockLength, Length));
503
 
504
                        file_obj->fWrite((PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)) , blockLength, pInputBuffer);
505
 
506
                        Length  -= blockLength;
507
                        Address += blockLength;
508
                        pInputBuffer = (PVOID)((PUCHAR)pInputBuffer + blockLength);
509
                }
510
 
511
                // release the lock
512
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
513
                ExchangePointer(&pciada->pbBusError, pbPrevBusError);
514
                if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
515
 
516
                if (file_obj->bIncrement)  // only when increment to next is on
517
                        *fileOffset =   RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
518
        }
519
        // do here in between what has to be done end -------------
520
 
521
        Irp->IoStatus.Status      = Status;  
522
        Irp->IoStatus.Information = storeLength;  
523
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
524
 
525
    KdPrint(("PCIVMEWrite(), Status = 0x%08x\n", Status));
526
 
527
        return Status;
528
}
529
 
530
#ifdef DO_CLEANUP
531
//------------------------------------------------------------------------
532
// called at cancel of a path
533
NTSTATUS PCIVMECancel(PDEVICE_OBJECT device_Obj, PIRP Irp)
534
{
535
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
536
        PIRP     pIrpCancel;
537
 
538
        KdPrint(("PCIVMECancel()\n"));
539
 
540
        // remove all queued IRPs of this file_obj
541
        do
542
        {
543
                pIrpCancel = RemoveIRPfromQueue(device_Obj, file_obj);
544
 
545
                if (pIrpCancel == (PIRP)NULL)
546
                {
547
                        IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
548
                        break;
549
                }
550
                else
551
                {
552
                        IoAcquireCancelSpinLock(pIrpCancel->CancelIrql);
553
 
554
                        // mark irp as not pending
555
                        IoSetCancelRoutine(pIrpCancel, NULL);
556
 
557
                        IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
558
 
559
                        pIrpCancel->IoStatus.Status = STATUS_CANCELLED;
560
                        pIrpCancel->IoStatus.Information = 0;
561
                }
562
        } while (pIrpCancel != (PIRP)NULL);
563
 
564
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
565
 
566
        KdPrint(("PCIVMECancel(OK)\n"));
567
 
568
        return STATUS_SUCCESS;
569
}
570
#endif
571
 
572
//------------------------------------------------------------------------
573
// search for pciada's
574
//
575
NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
576
{
577
  PCI_SLOT_NUMBER   SlotNumber;
578
  PCI_COMMON_CONFIG pci_config;
579
  PCIADA            *pciada;
580
  ULONG             length;
581
  int               *found;
582
  int               i,j,k;
583
 
584
  KdPrint(("SearchDevices()\n"));
585
 
586
  // prepare structures ----------------------------------------
587
  found = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
588
  *found = 0;
589
  for (i = 0; i < PCIVME_MAX_PCIADA; i++)
590
  {
591
        pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
592
 
593
        pciada->Bus                = -1;
594
    pciada->Slot.u.AsULONG     = 0xFFFFFFFF;
595
  }
596
 
597
  // search for pciada's ---------------------------------------
598
  SlotNumber.u.bits.Reserved = 0;
599
 
600
  for (j = 0; j < PCI_MAX_BUSES; j++)
601
  {
602
    for (i = 0; i < PCI_MAX_DEVICES; i++)
603
        {
604
          SlotNumber.u.bits.DeviceNumber = i;
605
          for (k = 0; k < PCI_MAX_FUNCTION; k++)
606
          {
607
                SlotNumber.u.bits.FunctionNumber = k;
608
            length = HalGetBusData( PCIConfiguration,         // Bustype 
609
                                                            j,                                    // PCI-Busnumber
610
                                                            SlotNumber.u.AsULONG,     // Slotnumber
611
                                                            (PVOID) &(pci_config),    // Pointer for the PCI-Information
612
                                                            sizeof(PCI_COMMON_CONFIG) );
613
 
614
                if ((pci_config.VendorID    == PCIVME_VENDOR_ID) &&
615
                        (pci_config.DeviceID    == PCIVME_DEVICE_ID) &&
616
                        (pci_config.u.type0.SubSystemID == PCIVME_SUBSYS_ID) &&
617
                        (pci_config.u.type0.SubVendorID == PCIVME_SUBVEN_ID) &&
618
                        (pci_config.u.type0.BaseAddresses[2]))
619
                {
620
               pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
621
 
622
               memcpy(&pciada->PCIDevice, &pci_config, sizeof(pci_config));
623
                   pciada->Slot = SlotNumber;
624
                   pciada->Bus  = j;
625
 
626
                   KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
627
 
628
                   (*found)++;
629
                   if (*found >= PCIVME_MAX_PCIADA) return STATUS_SUCCESS;
630
                }
631
          }
632
        }              
633
  }
634
 
635
  return STATUS_SUCCESS;
636
}
637
 
638
//---------------------------------------------------------------
639
// function to call for bug fix of PLX9050 build in bug
640
//
641
NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
642
{
643
        DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
644
        int i;
645
        ULONG dwData;
646
        PCIADA *pciada;
647
 
648
        KdPrint(("PLX9050BugFix()\n"));
649
 
650
        for (i = 0; i < DeviceExtension->nPCIADAs; i++)
651
        {
652
                pciada = &DeviceExtension->pciada[i];
653
 
654
                if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
655
                {      
656
                        KdPrint(("Changing address 0:0x%p with 4:0x%p\n",
657
                                pciada->PCIDevice.u.type0.BaseAddresses[0],
658
                                pciada->PCIDevice.u.type0.BaseAddresses[4]));
659
 
660
                        pciada->PCIDevice.u.type0.BaseAddresses[0] =           // exchange
661
                                pciada->PCIDevice.u.type0.BaseAddresses[4];
662
                        pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
663
 
664
                        if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
665
                                  pciada->Slot.u.AsULONG,
666
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0],
667
                                                0x10, 4) != 4)
668
                        return STATUS_UNSUCCESSFUL;
669
 
670
                        if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
671
                                  pciada->Slot.u.AsULONG,
672
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4],
673
                                                0x20, 4) != 4)
674
                        return STATUS_UNSUCCESSFUL;
675
                }
676
 
677
                if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
678
                {
679
                        KdPrint(("Changing address 1:0x%p with 5:0x%p\n",
680
                                pciada->PCIDevice.u.type0.BaseAddresses[1],
681
                                pciada->PCIDevice.u.type0.BaseAddresses[5]));
682
 
683
                  pciada->PCIDevice.u.type0.BaseAddresses[1] =           // exchange
684
                                pciada->PCIDevice.u.type0.BaseAddresses[5];
685
                  pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
686
 
687
                  if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
688
                                  pciada->Slot.u.AsULONG,
689
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1],
690
                                                0x14, 4) != 4)
691
                        return STATUS_UNSUCCESSFUL;
692
 
693
                  if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
694
                                  pciada->Slot.u.AsULONG,
695
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5],
696
                                                0x24, 4) != 4)
697
                        return STATUS_UNSUCCESSFUL;
698
                }
699
        }
700
 
701
        return STATUS_SUCCESS;
702
}
703
 
704
 
705
//------------------------------------------------------------------------
706
//  reserve resources for PCIADAs 
707
//
708
NTSTATUS PCIVMEExtractResources(PCIADA *pciada, PCM_RESOURCE_LIST pList)
709
{
710
        PCM_RESOURCE_LIST pResourceList;
711
        PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
712
        PCM_PARTIAL_RESOURCE_LIST pPartialList;
713
        PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
714
        int i;
715
        int bug = 0;
716
 
717
        KdPrint(("PCIVMEExtractResources()\n"));
718
 
719
        pResourceList   = pList;
720
        pFullDescriptor = pResourceList->List;
721
        pPartialList    = &pFullDescriptor->PartialResourceList;
722
 
723
        for (i=0; i<(int)pPartialList->Count; i++)
724
        {
725
                pPartialDescriptor = &pPartialList->PartialDescriptors[i];
726
                switch (pPartialDescriptor->Type)
727
                {
728
                        case CmResourceTypeInterrupt:
729
                                pciada->Irql     = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
730
                                pciada->Vector   = pPartialDescriptor->u.Interrupt.Vector;
731
                                pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
732
 
733
                                KdPrint(("Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
734
                                        pciada->Irql, pciada->Vector, pciada->Affinity));
735
                                break;
736
                        case CmResourceTypeDma:
737
                                KdPrint(("Dma    : \n"));
738
                                break;
739
                        case CmResourceTypePort:
740
 
741
                                KdPrint(("Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
742
                                break;
743
                        case CmResourceTypeMemory:
744
                                // special handling of PLXBUG here because of WIN2000
745
                                // WIN2000 doesn't recognize late address changes
746
                                if (!bug)
747
                                {
748
                                        if (i == 0)
749
                                        {
750
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
751
 
752
                                                if (pciada->pvPhysLcr.LowPart & 0x80)
753
                                                        bug = 1;
754
                                        }
755
                                }
756
                                else
757
                                {
758
                                        if (i == 3)
759
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
760
                                }
761
 
762
                                if (i == 2)
763
                                        pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
764
 
765
                                KdPrint(("Memory : 0x%p\n", (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
766
                                break;
767
                }
768
        }
769
 
770
        if (pciada->Irql == 0)
771
                return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
772
 
773
        KdPrint(("PCIVMEExtractResources() OK.\n"));
774
 
775
        return STATUS_SUCCESS;
776
}
777
 
778
NTSTATUS PCIVMEReserveResources(PDEVICE_OBJECT device_Obj)
779
{
780
        PCM_RESOURCE_LIST pList = NULL;
781
        NTSTATUS result = STATUS_SUCCESS;
782
        int i;
783
        DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
784
        int nPCIADAs = pDevExt->nPCIADAs;
785
        PCIADA *pciada;
786
    UNICODE_STRING DriverClassName;
787
 
788
        KdPrint(("PCIVMEReserveResources()\n"));
789
 
790
        // prepare resource claiming
791
        RtlInitUnicodeString(&DriverClassName, L"PCICC32");
792
 
793
        // cycle through all busses and slots assigned to PCIADAs
794
        for (i = 0; i < nPCIADAs; i++)
795
    {
796
                pciada = &pDevExt->pciada[i];
797
 
798
                result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj,
799
                        PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
800
 
801
                if (result != STATUS_SUCCESS)
802
                        break;
803
 
804
                result = PCIVMEExtractResources(pciada, pList);
805
 
806
                if (result != STATUS_SUCCESS)
807
                        break;
808
        }
809
 
810
        // its my part to free allocated resources
811
        if (pList != NULL) ExFreePoolWithTag(pList,'nepo');
812
 
813
        KdPrint(("PCIVMEReserveResources(0x%08x)\n", result));
814
 
815
        return result;
816
};
817
 
818
 
819
//------------------------------------------------------------------------
820
//  free resources from PCIADAs 
821
//
822
NTSTATUS PCIVMEFreeResources(PDEVICE_OBJECT device_Obj)
823
{
824
        CM_RESOURCE_LIST ResList;
825
        BOOLEAN          bConflict;
826
    UNICODE_STRING   DriverClassName;
827
 
828
    KdPrint(("PCIVMEFreeResources()\n"));
829
 
830
        RtlInitUnicodeString(&DriverClassName, L"PCIVME");
831
 
832
        ResList.Count = 0;
833
 
834
        IoReportResourceUsage(&DriverClassName, device_Obj->DriverObject,
835
                                         &ResList, sizeof(ResList), device_Obj,
836
                                                                         NULL, 0, FALSE, &bConflict);
837
        return STATUS_SUCCESS;
838
};
839
 
840
 
841
//------------------------------------------------------------------------
842
//  translate memory resources to neutral for PCIADAs 
843
//
844
NTSTATUS PCIVMETranslateBusAddresses(PDEVICE_OBJECT device_Obj)
845
{
846
        int              i;
847
        NTSTATUS         result = STATUS_SUCCESS;
848
        int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
849
        ULONG            memType0, memType2;
850
        PCIADA           *pciada;
851
 
852
    KdPrint(("TranslateBusAddresseses()\n"));
853
        for (i = 0; i < nPCIADAs; i++)
854
        {
855
      pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
856
 
857
          memType0 = memType2 = 0;
858
 
859
          if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0,
860
                                                               &pciada->pvPhysLcr)) ||
861
              !(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2,
862
                                                               &pciada->pvPhysIfr)))
863
          {
864
                  result = STATUS_UNSUCCESSFUL;
865
                  break;
866
          }
867
 
868
          if ((memType0) || (memType2))
869
          {
870
                  result = STATUS_UNSUCCESSFUL;
871
                  break;
872
          }
873
        }
874
        return result;
875
}
876
 
877
//------------------------------------------------------------------------
878
//  map address spaces to virtual addresses
879
//
880
NTSTATUS PCIVMEMapIOspace(PDEVICE_OBJECT device_Obj)
881
{
882
        int              i;
883
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
884
        int                              nPCIADAs = pDevExt->nPCIADAs;
885
        PCIADA           *pciada;
886
 
887
        KdPrint(("PCIVMEMapIOspace()\n"));
888
 
889
        for (i = 0; i < nPCIADAs; i++)
890
        {
891
       pciada = &pDevExt->pciada[i];
892
 
893
       if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL)
894
          return STATUS_UNSUCCESSFUL;
895
       if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL)
896
          return STATUS_UNSUCCESSFUL;
897
 
898
           KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n",
899
                                         i, pciada->pvVirtLcr, pciada->pvVirtIfr));
900
 
901
           pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
902
           pciada->pwCntrl  = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
903
        }
904
 
905
        return STATUS_SUCCESS;
906
}
907
 
908
 
909
//------------------------------------------------------------------------
910
//  initializes and registers a DPC routine for each pciada
911
//
912
NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
913
{
914
        int              i;
915
        int nPCIADAs = ((DEVICE_EXT*)(device_object->DeviceExtension))->nPCIADAs;
916
        PCIADA           *pciada;
917
 
918
        KdPrint(("InitializeCustomDPCObject()\n"));
919
 
920
        for (i = 0; i < nPCIADAs; i++)
921
        {
922
                pciada = &((DEVICE_EXT*)(device_object->DeviceExtension))->pciada[i];
923
                KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
924
        }
925
 
926
        return STATUS_SUCCESS;
927
}
928
 
929
//------------------------------------------------------------------------
930
//  initializes the queue for storing IRPs waiting for vectors
931
// 
932
NTSTATUS InitializeIRPQueue(PDEVICE_OBJECT device_Obj)
933
{
934
        DEVICE_EXT *pDevExt = ((DEVICE_EXT*)(device_Obj->DeviceExtension));
935
 
936
        KdPrint(("InitializeIRPQueue()\n"));
937
 
938
        KeInitializeSpinLock(&pDevExt->IRPLock);
939
        InitializeListHead(&pDevExt->IRPList);
940
 
941
        return STATUS_SUCCESS;
942
}
943
 
944
//------------------------------------------------------------------------
945
// init structures a.s.o.
946
//
947
VOID PCIVMESoftInit(PDEVICE_OBJECT device_Obj)
948
{
949
        int i;
950
        PCIADA *pciada;
951
 
952
        for (i = 0; i < PCIVME_MAX_PCIADA; i++)
953
        {
954
                pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
955
 
956
                pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
957
                pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
958
 
959
                pciada->bConnected     = FALSE;   // connection still not verified
960
                pciada->bWordMode      = TRUE;
961
                pciada->bSysControl    = FALSE;
962
                pciada->wModuleNumber  = 0xFFFF;
963
                pciada->wFPGAVersion   = 0xFFFF;
964
                pciada->wModuleType    = 1;       // always VMEMM
965
 
966
                pciada->InterruptObject = NULL;
967
                pciada->Irql                    = 0;
968
                pciada->Vector          = 0;
969
                pciada->Affinity                = 0;
970
 
971
                pciada->dwLinkCount     = 0;
972
 
973
                KeInitializeSpinLock(&pciada->IrqListLock);
974
                KeInitializeSpinLock(&pciada->AccessLock);
975
 
976
                InitializeListHead(&pciada->IrqListList);  // start of list of irq fifos
977
 
978
                pciada->nInterruptHandlers = 0;
979
        }
980
 
981
        // no vmemm associated to any PCIADA
982
        for (i = 0; i < PCIVME_MAX_VMEMM; i++)
983
          ((DEVICE_EXT*)(device_Obj->DeviceExtension))->vmemm[i] = NULL;
984
}
985
 
986
//------------------------------------------------------------------------
987
// the ultimate starting point of a driver
988
NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath  )
989
{
990
        UNREFERENCED_PARAMETER(regPath);
991
        PDEVICE_OBJECT device_object;                   // pointer to the device object
992
        UNICODE_STRING device_name;
993
        UNICODE_STRING symbol_name;
994
        NTSTATUS result = STATUS_SUCCESS;
995
        int            nPCIADAs;                                // count of PCIADAs
996
        DEVICE_EXT     *DeviceExtension = NULL;
997
 
998
    KdPrint(("DriverEntry() ---%d.%d---------------------------------\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
999
 
1000
        driverObj->DriverUnload = PCIVMEUnload;
1001
        driverObj->MajorFunction[IRP_MJ_CREATE] = PCIVMEOpen;
1002
        driverObj->MajorFunction[IRP_MJ_CLOSE]  = PCIVMEClose;
1003
        driverObj->MajorFunction[IRP_MJ_READ]   = PCIVMERead;
1004
    driverObj->MajorFunction[IRP_MJ_WRITE]  = PCIVMEWrite;
1005
        driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]    = PCIVMEDeviceControl;
1006
#ifdef DO_CLEANUP
1007
        driverObj->MajorFunction[IRP_MJ_CLEANUP] = PCIVMECancel;
1008
#endif
1009
    driverObj->MajorFunction[IRP_MJ_SHUTDOWN]          = PCIVMEShutdown;
1010
 
1011
        RtlInitUnicodeString(&device_name, L"\\Device\\PCIVME");
1012
 
1013
        /* DeviceObject durch IO-Manager erzeugen */
1014
        result = IoCreateDevice( driverObj,           // DriverObject received by the DriverEntry Call
1015
                                                         sizeof(DEVICE_EXT),  // required Memory for the DeviceExtension
1016
                                                         &device_name,        // Name of the device in the device-Directory
1017
                                                         FILE_DEVICE_UNKNOWN, // Device-ID              
1018
                                                         0,                   // Device-Characteristics normal 0
1019
                                                         FALSE,               // TRUE : one Thread can open the driver
1020
                                                         &device_object);     // DeviceObject returned from the IO-Manager
1021
 
1022
        // defines how the data are handled between user / kernel Adress-Space  
1023
        device_object->Flags |= DO_DIRECT_IO;
1024
 
1025
#if 0
1026
        // register the shutdown notification entry
1027
    IoRegisterShutdownNotification(device_object);
1028
#endif
1029
 
1030
        // anounce driver as symbolic device ---------------------------------
1031
        if (result == STATUS_SUCCESS)
1032
        {
1033
                /* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
1034
                RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
1035
                result = IoCreateSymbolicLink(&symbol_name,&device_name);
1036
                if (result != STATUS_SUCCESS)
1037
                {
1038
                        IoDeleteDevice(device_object);
1039
                        return result;
1040
                }
1041
        }
1042
        else
1043
                return result;
1044
 
1045
        DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
1046
 
1047
        DeviceExtension->actualIrp  = NULL;
1048
        DeviceExtension->driverObj  = driverObj;
1049
        DeviceExtension->nInitState = 0;
1050
 
1051
        // init pciada structures ------------------------------------
1052
        PCIVMESoftInit(device_object);
1053
 
1054
        // search for PCIADAs ----------------------------------------
1055
        result   = SearchDevices(device_object);
1056
        nPCIADAs = DeviceExtension->nPCIADAs;
1057
 
1058
        if ((result != STATUS_SUCCESS) || !(nPCIADAs))
1059
        {
1060
                PCIVMEUnload(driverObj);    
1061
                return STATUS_DEVICE_DOES_NOT_EXIST;
1062
        }
1063
 
1064
        // request exclusive ownership of .. ---------------------------------
1065
        if ((result = PCIVMEReserveResources(device_object)) != STATUS_SUCCESS)
1066
        {
1067
                PCIVMEUnload(driverObj);    
1068
                return result;
1069
        }
1070
        else
1071
                DeviceExtension->nInitState++;
1072
        // fix PLX9050 Bug -------------------------------------------
1073
        if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
1074
        {
1075
                PCIVMEUnload(driverObj);    
1076
                return result;
1077
        }
1078
 
1079
 
1080
        // translate BUS relative addresses ----------------------------------
1081
        if ((result = PCIVMETranslateBusAddresses(device_object)) != STATUS_SUCCESS)
1082
        {
1083
                PCIVMEUnload(driverObj);    
1084
                return STATUS_DEVICE_DOES_NOT_EXIST;
1085
        }
1086
        else
1087
                DeviceExtension->nInitState++;
1088
 
1089
        // translate Interrupt Resources used --------------------------------
1090
        if ((result = PCIVMETranslateInterrupts(device_object)) != STATUS_SUCCESS)
1091
        {
1092
                PCIVMEUnload(driverObj);    
1093
                return STATUS_DEVICE_DOES_NOT_EXIST;
1094
        }
1095
        else
1096
                DeviceExtension->nInitState++;
1097
 
1098
        // map address spaces to virtual addresses ---------------------------
1099
        if ((result = PCIVMEMapIOspace(device_object)) != STATUS_SUCCESS)
1100
        {
1101
                PCIVMEUnload(driverObj);    
1102
                return STATUS_DEVICE_DOES_NOT_EXIST;
1103
        }
1104
        else
1105
                DeviceExtension->nInitState++;
1106
 
1107
        // initialze my custom DPC objects -----------------------------------
1108
        if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
1109
        {
1110
                PCIVMEUnload(driverObj);    
1111
                return result;
1112
        }
1113
        else
1114
                DeviceExtension->nInitState++;
1115
 
1116
        // initialze the queue for IRPs waiting for vectors ------------------
1117
        if ((result = InitializeIRPQueue(device_object)) != STATUS_SUCCESS)
1118
        {
1119
                PCIVMEUnload(driverObj);    
1120
                return result;
1121
        }
1122
        else
1123
                DeviceExtension->nInitState++;
1124
 
1125
        // connect interrupts to service routines ----------------------------
1126
        if ((result = PCIVMEConnectInterrupt(device_object)) != STATUS_SUCCESS)
1127
        {
1128
                PCIVMEUnload(driverObj);    
1129
                return STATUS_DEVICE_DOES_NOT_EXIST;
1130
        }
1131
        else
1132
                DeviceExtension->nInitState++;
1133
 
1134
        // scan all connected VMEMM for info and later use -------------------
1135
        if ((result = PCIVMEScanVMEMM(device_object)) != STATUS_SUCCESS)
1136
        {
1137
                PCIVMEUnload(driverObj);    
1138
                return STATUS_DEVICE_DOES_NOT_EXIST;
1139
        }
1140
 
1141
        device_object->Flags &= ~DO_DEVICE_INITIALIZING;
1142
 
1143
    KdPrint(("DriverEntry() OK.\n"));
1144
 
1145
        return result;
1146
}
1147