Subversion Repositories f9daq

Rev

Rev 19 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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