OpenCBM
testirq.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 2006 Spiro Trikaliotis
8  *
9  */
10 
19 #include <wdm.h>
20 #include "cbm_driver.h"
21 #include "iec.h"
22 #include "i_iec.h"
23 
40 NTSTATUS
41 cbmiec_test_irq(IN PDEVICE_EXTENSION Pdx, OUT PVOID Buffer, IN ULONG BufferLength)
42 {
43  PCBMT_I_TESTIRQ bufferTestIrq = Buffer;
44  NTSTATUS ntStatus;
45  LONG ret;
46 #if DBG
47  LONG oldDbgFlags = DbgFlags;
48 #endif
49 
50  FUNC_ENTER();
51 
52  if (bufferTestIrq)
53  {
54  if (sizeof(*bufferTestIrq) > BufferLength)
55  {
56  // the buffer is not long enough; don't use it at all!
57  bufferTestIrq = NULL;
58  }
59  else
60  {
61  RtlZeroMemory(bufferTestIrq, BufferLength);
62  }
63  }
64 
65  ntStatus = STATUS_SUCCESS;
66 
67  do {
68  PUCHAR ecrPort = Pdx->ParPortEcpPortAddress + ECR_OFFSET;
69  UCHAR ecr = READ_PORT_UCHAR(ecrPort);
70  UCHAR ecp0, ecp1;
71 
72 #if DBG
73 // DbgFlags |= 0x7;
74 // DbgFlags |= 0x7fffffff;
75 #endif
76 
77  //
78  // Did we get a an interrupt at all? If not, no need
79  // to do ANY test!
80  //
81 
82  if (!Pdx->ParallelPortAllocatedInterrupt)
83  {
84  ntStatus = STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
85  if (bufferTestIrq)
86  bufferTestIrq->ErrAcquireIrq = 1;
87  break;
88  }
89 
90  //
91  // Now, do the test
92  //
93 
94  DBG_CABLE((DBG_PREFIX "Release all lines"));
96 
97  DBG_CABLE((DBG_PREFIX "Pdx->IrqCount = 100"));
98  ret = InterlockedExchange(&Pdx->IrqCount, 100);
99  DBG_ASSERT(ret==0);
100 
101  DBG_CABLE((DBG_PREFIX "Allow Interrupts"));
103 
104  if (Pdx->ParPortEcpPortAddress)
105  {
106  ecr = READ_PORT_UCHAR(ecrPort);
107 
108  DBG_CABLE((DBG_PREFIX ""));
109  DBG_CABLE((DBG_PREFIX "" __DATE__ " " __TIME__));
110  DBG_CABLE((DBG_PREFIX "Setting ECP to configuration mode"));
111 
112  WRITE_PORT_UCHAR(Pdx->ParPortEcpPortAddress, ecr | 0xe0);
113  ecp0 = READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + 0);
114  ecp1 = READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + 1);
115 
116  DBG_CABLE((DBG_PREFIX "Addresses: %p = (%02x, %02x, %02x)",
117  Pdx->ParPortEcpPortAddress,
118  ecp0,
119  ecp1,
120  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + 2)));
121 
122  DBG_CABLE((DBG_PREFIX "Interrupt bit = %s",
123  (READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + 0) & 0x40)
124  ? "TRUE"
125  : "FALSE"));
126 
127  DBG_CABLE((DBG_PREFIX "Interrupt bit = %s",
128  (READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + 0) & 0x40)
129  ? "TRUE"
130  : "FALSE"));
131 
132  DBG_CABLE((DBG_PREFIX "Resetting ECP to old mode"));
133 
134  WRITE_PORT_UCHAR(Pdx->ParPortEcpPortAddress, ecr);
135 
136  DBG_CABLE((DBG_PREFIX "Interrupt bit ECR = %s",
137  (READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) & 0x04)
138  ? "TRUE"
139  : "FALSE"));
140 
141  DBG_CABLE((DBG_PREFIX "Interrupt bit ECR = %s",
142  (READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) & 0x04)
143  ? "TRUE"
144  : "FALSE"));
145 
146  WRITE_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET,
147  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) & ~0x04);
148 
149  DBG_CABLE((DBG_PREFIX "Interrupt bit ECR = %s",
150  (READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) & 0x04)
151  ? "TRUE"
152  : "FALSE"));
153 
154  DBG_CABLE((DBG_PREFIX ""));
155  DBG_CABLE((DBG_PREFIX ""));
156 
157  DBG_CABLE((DBG_PREFIX "Before: ECR (%p) = %02x",
158  Pdx->ParPortEcpPortAddress + ECR_OFFSET,
159  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET)));
160 
161  WRITE_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET,
162  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) | 0x10);
163 
164  DBG_CABLE((DBG_PREFIX "After: ECR (%p) = %02x",
165  Pdx->ParPortEcpPortAddress + ECR_OFFSET,
166  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET)));
167  }
168 
169  DBG_CABLE((DBG_PREFIX "Set all lines"));
171 
172  DBG_CABLE((DBG_PREFIX "Wait 1s"));
173  cbmiec_udelay(1000000);
174 
175  ret = InterlockedExchange(&Pdx->IrqCount, 100);
176  DBG_CABLE((DBG_PREFIX "Pdx->IrqCount = 100, old Value = %u", ret));
177 
178  if (ret != 100)
179  {
180  DBG_ERROR((DBG_PREFIX "Interrupt generated when SETTING"));
181  LogErrorOnly(Pdx->Fdo, CBM_IRQ_WHEN_SETTING);
182 
183  if (bufferTestIrq)
184  bufferTestIrq->ErrIrqRisingEdge = -1;
185 
186  /* But: This is NO error, thus, no need for setting ntStatus! */
187  /* ntStatus = STATUS_UNSUCCESSFUL; */
188  }
189 
190  DBG_CABLE((DBG_PREFIX "Release all lines"));
192 
193  DBG_CABLE((DBG_PREFIX "Wait 1s"));
194  cbmiec_udelay(1000000);
195 
196  DBG_CABLE((DBG_PREFIX "Disallow Interrupts"));
198 
199  if (Pdx->ParPortEcpPortAddress)
200  {
201  DBG_CABLE((DBG_PREFIX "Before: ECR (%p) = %02x",
202  Pdx->ParPortEcpPortAddress + ECR_OFFSET,
203  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET)));
204 
205  WRITE_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET,
206  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET) & ~0x10);
207 
208  DBG_CABLE((DBG_PREFIX "After: ECR (%p) = %02x",
209  Pdx->ParPortEcpPortAddress + ECR_OFFSET,
210  READ_PORT_UCHAR(Pdx->ParPortEcpPortAddress + ECR_OFFSET)));
211  }
212 
213  ret = InterlockedExchange(&Pdx->IrqCount, 0);
214  DBG_CABLE((DBG_PREFIX "Pdx->IrqCount = 0, old Value = %u", ret));
215 
216  /*
217  * Check if an interrupt occurred
218  *
219  * Note: Check for > 99 (and not !=99) because the 1581 issues
220  * two IRQs in this short test!
221  */
222 
223  if (ret > 99)
224  {
225  DBG_ERROR((DBG_PREFIX "No interrupt generated when RELEASING"));
226  ntStatus = STATUS_NO_SUCH_DEVICE;
227 
228  if (bufferTestIrq)
229  bufferTestIrq->ErrIrqFallingEdge = 1;
230  }
231 
232  } while (0);
233 
234 #if DBG
235  DbgFlags = oldDbgFlags;
236 #endif
237 
238  FUNC_LEAVE_NTSTATUS(ntStatus);
239 }
VOID cbmiec_udelay(IN ULONG howlong)
Wait for a timeout.
Definition: libiec/util.c:66
#define PP_ATN_OUT
The ATN OUT bit.
Definition: i_iec.h:39
#define PP_DATA_OUT
The DATA OUT bit.
Definition: i_iec.h:41
unsigned long DbgFlags
#define PP_RESET_OUT
The RESET OUT bit.
Definition: i_iec.h:42
Definitions for the libiec library.
#define CBMIEC_SET(_set)
Definition: i_iec.h:64
Internal functions and definitions of the libiec library.
#define PP_LP_IRQ
Bit for allowing interrupts of the LPT.
Definition: i_iec.h:45
#define DBG_ASSERT(_xxx)
Definition: debug.h:401
#define DBG_ERROR(_xxx)
Definition: debug.h:397
#define WRITE_PORT_UCHAR(_x_, _y_)
WRITE_PORT_UCHAR replacement for debugging.
Definition: i_iec.h:221
#define CBMIEC_RELEASE(_rel)
Definition: i_iec.h:66
#define PP_CLK_OUT
The CLOCK OUT bit.
Definition: i_iec.h:40
CHAR ErrAcquireIrq
Definition: cbmioctl.h:198
NTSTATUS cbmiec_test_irq(IN PDEVICE_EXTENSION Pdx, OUT PVOID Buffer, IN ULONG BufferLength)
Test for IRQ capabilities.
Definition: testirq.c:41
#define FUNC_ENTER()
Definition: debug.h:347
Definitions for the opencbm driver.
#define DBG_PREFIX
Definition: debug.h:320
#define LogErrorOnly(_Fdo_, _UniqueErrorValue_)
Definition: util.h:35
CHAR ErrIrqFallingEdge
Definition: cbmioctl.h:206
CHAR ErrIrqRisingEdge
Definition: cbmioctl.h:202
#define READ_PORT_UCHAR(_x_)
READ_PORT_UCHAR replacement for debugging.
Definition: i_iec.h:211