OpenCBM
checkcable.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-2007 Spiro Trikaliotis
8  *
9  */
10 
19 #include <wdm.h>
20 #include "cbm_driver.h"
21 #include "i_iec.h"
22 
23 /* XA1541: */
24 
25 #define PP_XA_ATN_OUT 0x01
26 #define PP_XA_CLK_OUT 0x02
27 #define PP_XA_DATA_OUT 0x04
28 #define PP_XA_RESET_OUT 0x08
29 #define PP_XA_EOR_OUT 0xcb
31 #define PP_XA_ATN_IN 0x10
32 #define PP_XA_CLK_IN 0x20
33 #define PP_XA_DATA_IN 0x40
34 #define PP_XA_RESET_IN 0x80
35 #define PP_XA_EOR_IN 0x80
38 /* XM1541: */
39 
40 #define PP_XM_ATN_OUT PP_XA_ATN_OUT
41 #define PP_XM_CLK_OUT PP_XA_CLK_OUT
42 #define PP_XM_DATA_OUT PP_XA_DATA_OUT
43 #define PP_XM_RESET_OUT PP_XA_RESET_OUT
44 #define PP_XM_EOR_OUT 0xc4
46 #define PP_XM_ATN_IN PP_XA_ATN_IN
47 #define PP_XM_CLK_IN PP_XA_CLK_IN
48 #define PP_XM_DATA_IN PP_XA_DATA_IN
49 #define PP_XM_RESET_IN PP_XA_RESET_IN
50 #define PP_XM_EOR_IN PP_XA_EOR_IN
52 /* XE1541: */
53 
54 #define PP_XE_ATN_OUT PP_XM_ATN_OUT
55 #define PP_XE_CLK_OUT PP_XM_CLK_OUT
56 #define PP_XE_DATA_OUT PP_XM_RESET_OUT
57 #define PP_XE_RESET_OUT PP_XM_DATA_OUT
58 #define PP_XE_EOR_OUT PP_XM_EOR_OUT
60 #define PP_XE_ATN_IN PP_XM_ATN_IN
61 #define PP_XE_CLK_IN PP_XM_CLK_IN
62 #define PP_XE_DATA_IN PP_XM_RESET_IN
63 #define PP_XE_RESET_IN PP_XM_DATA_IN
64 #define PP_XE_EOR_IN PP_XM_EOR_IN
75 static VOID
76 cbmiec_set_cablevalues(IN PDEVICE_EXTENSION Pdx)
77 {
78  FUNC_ENTER();
79 
80  switch (Pdx->IecCable)
81  {
82  case IEC_CABLETYPE_XM:
83  Pdx->IecAtnOut = PP_XM_ATN_OUT;
84  Pdx->IecClkOut = PP_XM_CLK_OUT;
85  Pdx->IecDataOut = PP_XM_DATA_OUT;
86  Pdx->IecResetOut = PP_XM_RESET_OUT;
87 
88  Pdx->IecAtnIn = PP_XM_ATN_IN;
89  Pdx->IecClkIn = PP_XM_CLK_IN;
90  Pdx->IecDataIn = PP_XM_DATA_IN;
91  Pdx->IecResetIn = PP_XM_RESET_IN;
92 
93  Pdx->IecInEor = PP_XM_EOR_IN;
94  Pdx->IecOutEor = PP_XM_EOR_OUT;
95  break;
96 
97  case IEC_CABLETYPE_XA:
98  Pdx->IecAtnOut = PP_XA_ATN_OUT;
99  Pdx->IecClkOut = PP_XA_CLK_OUT;
100  Pdx->IecDataOut = PP_XA_DATA_OUT;
101  Pdx->IecResetOut = PP_XA_RESET_OUT;
102 
103  Pdx->IecAtnIn = PP_XA_ATN_IN;
104  Pdx->IecClkIn = PP_XA_CLK_IN;
105  Pdx->IecDataIn = PP_XA_DATA_IN;
106  Pdx->IecResetIn = PP_XA_RESET_IN;
107 
108  Pdx->IecInEor = PP_XA_EOR_IN;
109  Pdx->IecOutEor = PP_XA_EOR_OUT;
110  break;
111 
112  case IEC_CABLETYPE_XE:
113  DBG_CABLE((DBG_PREFIX "************ XE1541 ***************"));
114  Pdx->IecAtnOut = PP_XE_ATN_OUT;
115  Pdx->IecClkOut = PP_XE_CLK_OUT;
116  Pdx->IecDataOut = PP_XE_DATA_OUT;
117  Pdx->IecResetOut = PP_XE_RESET_OUT;
118 
119  Pdx->IecAtnIn = PP_XE_ATN_IN;
120  Pdx->IecClkIn = PP_XE_CLK_IN;
121  Pdx->IecDataIn = PP_XE_DATA_IN;
122  Pdx->IecResetIn = PP_XE_RESET_IN;
123 
124  Pdx->IecInEor = PP_XE_EOR_IN;
125  Pdx->IecOutEor = PP_XE_EOR_OUT;
126  break;
127 
128  default:
129  DBG_CABLE((DBG_PREFIX "***************************************"));
130  DBG_CABLE((DBG_PREFIX "******************* DEFAULT? **********"));
131  DBG_CABLE((DBG_PREFIX "***************************************"));
132  break;
133  };
134 
135  /* remember the current state of the output bits */
136 
137  Pdx->IecOutBits = (READ_PORT_UCHAR(OUT_PORT) ^ Pdx->IecOutEor)
139 
140  DBG_CABLE((DBG_PREFIX "IecAtnOut = %02x IecAtnIn = %02x", Pdx->IecAtnOut, Pdx->IecAtnIn));
141  DBG_CABLE((DBG_PREFIX "IecClkOut = %02x IecClkIn = %02x", Pdx->IecClkOut, Pdx->IecClkIn));
142  DBG_CABLE((DBG_PREFIX "IecDataOut = %02x IecDataIn = %02x", Pdx->IecDataOut, Pdx->IecDataIn));
143  DBG_CABLE((DBG_PREFIX "IecResetOut = %02x IecResetIn = %02x", Pdx->IecResetOut, Pdx->IecResetIn));
144  DBG_CABLE((DBG_PREFIX "EOR Out = %02x EOR In = %02x - outbits = %02x", Pdx->IecOutEor,
145  Pdx->IecInEor, Pdx->IecOutBits));
146 
147  FUNC_LEAVE();
148 }
149 
156 #define READ(_x) ((((READ_PORT_UCHAR(OUT_PORT) ^ Pdx->IecOutEor)) & (_x)) ? 1 : 0)
157 
165 #define SHOW(_x, _y)
166  // DBG_CABLE((DBG_PREFIX "CBMIEC_GET(" #_x ") = $%02x, READ(" #_y ") = $%02x", CBMIEC_GET(_x), READ(_y) ));
167 
169 #define SHOW1() \
170  DBG_CABLE((DBG_PREFIX "############ ATN OUT = %u, CLOCK OUT = %u, DATA OUT = %u, RESET OUT = %u", \
171  READ(PP_ATN_OUT), READ(PP_CLK_OUT), READ(PP_DATA_OUT), READ(PP_RESET_OUT) )); \
172 \
173  DBG_CABLE((DBG_PREFIX "############ ATN IN = %u, CLOCK IN = %u, DATA IN = %u, RESET IN = %u", \
174  CBMIEC_GET(PP_ATN_IN), CBMIEC_GET(PP_CLK_IN), CBMIEC_GET(PP_DATA_IN), CBMIEC_GET(PP_RESET_IN) ));
175 
191 static NTSTATUS
192 cbmiec_testcable(PDEVICE_EXTENSION Pdx)
193 {
194  NTSTATUS ntStatus = STATUS_PORT_DISCONNECTED;
195  UCHAR ch;
196 
197  FUNC_ENTER();
198 
199  /* check if the state of all lines is correct */
200 
201  ch = READ_PORT_UCHAR(IN_PORT);
202 
203  DBG_CABLE((DBG_PREFIX "############ Status: out: $%02x, in: $%02x ($%02x ^ $%02x)",
204  READ_PORT_UCHAR(OUT_PORT), ch, ch ^ Pdx->IecOutEor, Pdx->IecOutEor));
205 
206  do {
207  /*
208  * Do some tests
209  */
210 
211  /* First of all: If a line is set by me, it must be set when reading, too. */
212 
213  if (READ(PP_RESET_OUT) && CBMIEC_GET(PP_RESET_IN) == 0)
214  {
215  DBG_CABLE((DBG_PREFIX "RESET does not follow"));
216  break;
217  }
218 
219  if (READ(PP_ATN_OUT) && CBMIEC_GET(PP_ATN_IN) == 0)
220  {
221  DBG_CABLE((DBG_PREFIX "ATN does not follow"));
222  break;
223  }
224 
225  if (READ(PP_DATA_OUT) && CBMIEC_GET(PP_DATA_IN) == 0)
226  {
227  DBG_CABLE((DBG_PREFIX "DATA does not follow"));
228  break;
229  }
230 
231  if (READ(PP_CLK_OUT) && CBMIEC_GET(PP_CLK_IN) == 0)
232  {
233  DBG_CABLE((DBG_PREFIX "CLOCK does not follow"));
234  break;
235  }
236 
237 
238  if (Pdx->DoNotReleaseBus)
239  {
240  DBG_CABLE((DBG_PREFIX "Pdx->DoNotReleaseBus set, skipping extra tests."));
241 
242  ntStatus = STATUS_SUCCESS;
243  break;
244  }
245 
246  /* Release all lines */
247 
249  cbmiec_schedule_timeout(1000); /* wait 1 ms */
250 
251 DBG_CABLE((DBG_PREFIX " --- Release all lines" ));
252 SHOW1();
254 DBG_CABLE((DBG_PREFIX " --- Release all lines - 1" ));
255 SHOW1();
256 
257  /* Now, check if all lines are unset */
258 
259  if (CBMIEC_GET(PP_RESET_IN))
260  {
261  DBG_CABLE((DBG_PREFIX "RESET is set, but it should not"));
262  break;
263  }
264 
265  if (CBMIEC_GET(PP_ATN_IN))
266  {
267  DBG_CABLE((DBG_PREFIX "ATN is set, but it should not"));
268  break;
269  }
270 
271  if (CBMIEC_GET(PP_DATA_IN))
272  {
273  DBG_CABLE((DBG_PREFIX "DATA is set, but it should not"));
274  break;
275  }
276 
277  if (CBMIEC_GET(PP_CLK_IN))
278  {
279  DBG_CABLE((DBG_PREFIX "CLOCK is set, but it should not"));
280  break;
281  }
282 
283  /* Set ATN and wait 1ms for the drive to react */
284 
286 
287 DBG_CABLE((DBG_PREFIX " --- ATN set" ));
288 SHOW1();
289 
290  if (CBMIEC_GET(PP_RESET_IN))
291  {
292  DBG_CABLE((DBG_PREFIX "RESET is reacting to ATN - most probably, it is an XE1541 cable!"));
293  Pdx->IecCable = IEC_CABLETYPE_XE;
294  }
295  else
296  {
297  if (CBMIEC_GET(PP_DATA_IN) == 0)
298  {
299  DBG_CABLE((DBG_PREFIX "DATA does not react to ATN."));
300  }
301  }
302 
303  /* Release ATN again */
304 
306 
307 #undef SHOW
308 #undef SHOW1
309 
310  ntStatus = STATUS_SUCCESS;
311 
312  } while (0);
313 
314 #undef READ
315 
316  FUNC_LEAVE_NTSTATUS(ntStatus);
317 }
318 
333 NTSTATUS
334 cbmiec_checkcable(PDEVICE_EXTENSION Pdx)
335 {
336  NTSTATUS ntStatus = STATUS_SUCCESS;
337  const wchar_t *msgAuto = L"";
338  const wchar_t *msgCable;
339  UCHAR in, out;
340  IEC_CABLETYPE iecCableType;
341 
342  FUNC_ENTER();
343 
344 DBG_CABLE((DBG_PREFIX "IecCableUserSet = %d, IecCable = %d", Pdx->IecCableUserSet, Pdx->IecCable));
345  do {
346  CABLESTATE newCableState = CABLESTATE_UNKNOWN;
347 
348  /*
349  * If the cabletype is still tested, do not retest again
350  */
351 
352  DBG_CABLE((DBG_PREFIX "*****************" ));
353  DBG_CABLE((DBG_PREFIX "cbmiec_checkcable" ));
354  DBG_CABLE((DBG_PREFIX "*****************" ));
355 
356  switch (Pdx->IecCableUserSet)
357  {
358  case IEC_CABLETYPE_XE:
359  /* FALL THROUGH */
360 
361  case IEC_CABLETYPE_XM:
362  /* FALL THROUGH */
363 
364  case IEC_CABLETYPE_XA:
365 
366  /* the user specified a cable type, use this
367  * without questioning:
368  */
369 
370  iecCableType = Pdx->IecCableUserSet;
371 
372  newCableState = CABLESTATE_TESTED;
373 
374  cbmiec_set_cablevalues(Pdx);
375  break;
376 
377  default:
378  in = CBMIEC_GET(PP_XA_ATN_IN);
379  out = (READ_PORT_UCHAR(OUT_PORT) & PP_XA_ATN_OUT) ? 1 : 0;
380  iecCableType = (in != out) ? IEC_CABLETYPE_XA : IEC_CABLETYPE_XM;
381  msgAuto = L" (auto)";
382  newCableState = CABLESTATE_UNKNOWN;
383  break;
384  }
385 
386  /*
387  * If the cable type recognized does not match the cable
388  * type we think we have, the cable is set to "unknown".
389  */
390 
391  if (iecCableType != Pdx->IecCable)
392  {
394  Pdx->DoNotReleaseBus = FALSE;
395  }
396 
397  /*
398  * If the cable was at least tested before (and we have no
399  * contradiction to think it is still in this state),
400  * do not do any more tests.
401  */
402  if (Pdx->IecCableState >= CABLESTATE_TESTED)
403  break;
404 
405  /*
406  * Remember the cable type we recognized, and the state
407  */
408 
409  Pdx->IecCable = iecCableType;
410  cbmiec_setcablestate(Pdx, newCableState);
411 
412  cbmiec_set_cablevalues(Pdx);
413 
414  switch (Pdx->IecCable)
415  {
416  case IEC_CABLETYPE_XE:
417  /* \todo XE and XM are distinguished later */
418 
419  /* FALL THROUGH */
420 
421  case IEC_CABLETYPE_XM:
422  msgCable = L"passive (XM1541)";
423  break;
424 
425  case IEC_CABLETYPE_XA:
426  msgCable = L"active (XA1541)";
427  break;
428  }
429 
430  /* Now, test if the cable really works */
431 
432  if (Pdx->IecCableState > CABLESTATE_UNKNOWN)
433  break;
434 
435  ntStatus = cbmiec_testcable(Pdx);
436 
437  if (NT_SUCCESS(ntStatus))
438  {
439  const wchar_t *msgExtra = L"";
440 
441  if (Pdx->IecCable == IEC_CABLETYPE_XE)
442  {
443  /* the test found out that we have an XE cable, not an XM! */
444 
445  msgCable = L"passive (XE1541)";
446 
447  msgExtra = L" (THIS IS NOT SUPPORTED YET!)";
448 
449  cbmiec_set_cablevalues(Pdx);
450  }
451 
452  DBG_SUCCESS((DBG_PREFIX "using %ws cable%ws%s",
453  msgCable, msgAuto, msgExtra));
454 
455  LogErrorString(Pdx->Fdo,
456  (Pdx->IecCable == IEC_CABLETYPE_XE) ? CBM_IEC_INIT_XE1541 : CBM_IEC_INIT,
457  msgCable, msgAuto);
458 
460  }
461  else
462  {
463  DBG_ERROR((DBG_PREFIX "could not validate that the cable "
464  "used is really a %ws cable%ws",
465  msgCable, msgAuto));
466 
467  LogErrorString(Pdx->Fdo, CBM_IEC_INIT_FAIL, msgCable, msgAuto);
468  }
469 
470 /*
471  if (Pdx->IecOutBits & PP_RESET_OUT)
472  {
473  cbmiec_reset(Pdx);
474  }
475 */
476 
477  } while (0);
478 
479  /*
480  * will be printed even if "start" was not printed!
481  */
482 
483  DBG_CABLE((DBG_PREFIX "*********************" ));
484  DBG_CABLE((DBG_PREFIX "end cbmiec_checkcable" ));
485  DBG_CABLE((DBG_PREFIX "*********************" ));
486 
487  FUNC_LEAVE_NTSTATUS(ntStatus);
488 }
489 
490 
493 VOID
494 cbmiec_setcablestate(PDEVICE_EXTENSION Pdx, CABLESTATE State)
495 {
496  FUNC_ENTER();
497 
498  Pdx->IecCableState = State;
499 
500  FUNC_LEAVE();
501 }
502 
503 
510 BOOLEAN
511 cbmiec_is_cable_state_wrong(PDEVICE_EXTENSION Pdx)
512 {
513  return CBMIEC_ARE_OUTPUT_LINES_CORRECT() ? FALSE : TRUE;
514 }
#define PP_XE_ATN_IN
@@@
Definition: checkcable.c:60
enum cablestate_e CABLESTATE
@@@
Definition: cbm_driver.h:92
#define CBMIEC_GET(_line)
Definition: i_iec.h:75
#define PP_XA_RESET_IN
@@@
Definition: checkcable.c:34
#define PP_XM_CLK_IN
@@@
Definition: checkcable.c:47
#define OUT_PORT
Definition: i_iec.h:61
#define PP_ATN_OUT
The ATN OUT bit.
Definition: i_iec.h:39
#define PP_XE_RESET_OUT
@@@
Definition: checkcable.c:57
NTSTATUS cbmiec_checkcable(PDEVICE_EXTENSION Pdx)
Determine the type of cable (XA1541/XM1541) on the IEC bus.
Definition: checkcable.c:334
#define PP_XM_RESET_OUT
@@@
Definition: checkcable.c:43
#define LogErrorString(_Fdo_, _UniqueErrorValue_, _String1_, _String2_)
Definition: util.h:39
#define PP_DATA_OUT
The DATA OUT bit.
Definition: i_iec.h:41
#define PP_XM_EOR_OUT
@@@
Definition: checkcable.c:44
#define PP_XA_EOR_OUT
@@@
Definition: checkcable.c:29
#define PP_XE_RESET_IN
@@@
Definition: checkcable.c:63
#define PP_CLK_IN
The CLOCK IN bit.
Definition: i_iec.h:50
enum iec_cabletype IEC_CABLETYPE
#define PP_RESET_OUT
The RESET OUT bit.
Definition: i_iec.h:42
#define PP_XM_DATA_OUT
@@@
Definition: checkcable.c:42
#define PP_XE_CLK_OUT
@@@
Definition: checkcable.c:55
#define PP_XA_ATN_OUT
@@@
Definition: checkcable.c:25
#define PP_XM_ATN_OUT
@@@
Definition: checkcable.c:40
#define PP_XM_ATN_IN
@@@
Definition: checkcable.c:46
#define CBMIEC_SET(_set)
Definition: i_iec.h:64
#define FUNC_LEAVE()
Definition: debug.h:349
#define PP_XA_CLK_OUT
@@@
Definition: checkcable.c:26
BOOLEAN cbmiec_is_cable_state_wrong(PDEVICE_EXTENSION Pdx)
@@@
Definition: checkcable.c:511
Internal functions and definitions of the libiec library.
#define PP_XE_DATA_IN
@@@
Definition: checkcable.c:62
#define READ(_x)
@@@
Definition: checkcable.c:156
#define PP_XA_CLK_IN
@@@
Definition: checkcable.c:32
#define IN_PORT
Definition: i_iec.h:58
#define PP_XA_ATN_IN
@@@
Definition: checkcable.c:31
VOID cbmiec_schedule_timeout(IN ULONG howlong)
Schedule a timeout.
Definition: libiec/util.c:34
#define PP_XE_CLK_IN
@@@
Definition: checkcable.c:61
#define PP_XE_ATN_OUT
@@@
Definition: checkcable.c:54
#define PP_XE_EOR_OUT
@@@
Definition: checkcable.c:58
#define DBG_ERROR(_xxx)
Definition: debug.h:397
#define PP_XE_EOR_IN
@@@
Definition: checkcable.c:64
VOID cbmiec_setcablestate(PDEVICE_EXTENSION Pdx, CABLESTATE State)
Set the current state of the cable detection.
Definition: checkcable.c:494
#define CBMIEC_ARE_OUTPUT_LINES_CORRECT()
Definition: i_iec.h:72
#define PP_DATA_IN
The DATA IN bit.
Definition: i_iec.h:51
#define DBG_SUCCESS(_xxx)
Definition: debug.h:393
#define CBMIEC_RELEASE(_rel)
Definition: i_iec.h:66
#define PP_XE_DATA_OUT
@@@
Definition: checkcable.c:56
#define PP_CLK_OUT
The CLOCK OUT bit.
Definition: i_iec.h:40
#define PP_XM_RESET_IN
@@@
Definition: checkcable.c:49
#define PP_XM_CLK_OUT
@@@
Definition: checkcable.c:41
#define PP_XA_DATA_IN
@@@
Definition: checkcable.c:33
#define PP_RESET_IN
The RESET IN bit.
Definition: i_iec.h:52
#define SHOW1()
@@@
Definition: checkcable.c:169
#define FUNC_ENTER()
Definition: debug.h:347
#define PP_ATN_IN
The ATN IN bit.
Definition: i_iec.h:49
Definitions for the opencbm driver.
#define PP_XA_DATA_OUT
@@@
Definition: checkcable.c:27
#define DBG_PREFIX
Definition: debug.h:320
#define PP_XM_EOR_IN
@@@
Definition: checkcable.c:50
NTSTATUS cbmiec_wait_for_drives_ready(IN PDEVICE_EXTENSION Pdx)
Wait for the drives to become ready after a RESET.
Definition: reset.c:39
#define PP_XA_EOR_IN
@@@
Definition: checkcable.c:35
#define PP_XM_DATA_IN
@@@
Definition: checkcable.c:48
#define PP_XA_RESET_OUT
@@@
Definition: checkcable.c:28
#define READ_PORT_UCHAR(_x_)
READ_PORT_UCHAR replacement for debugging.
Definition: i_iec.h:211