1 /* JTAG GNU/Linux parport device io
2 
3 Copyright (C) 2004 Andrew Rogers
4 Additions for Byte Blaster Cable (C) 2005-2011  Uwe Bonnes
5                               bon@elektron.ikp.physik.tu-darmstadt.de
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 
21 Changes:
22 Dmitry Teytelman [dimtey@gmail.com] 14 Jun 2006 [applied 13 Aug 2006]:
23     Code cleanup for clean -Wall compile.
24     Changes to support new IOBase interface.
25     Support for byte counting and progress bar.
26 */
27 
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <string.h>
33 
34 #ifdef __linux__
35 // Default parport device
36 #ifndef PPDEV
37 #  define PPDEV "/dev/parport0"
38 #endif
39 
40 #include <sys/ioctl.h>
41 #  include <linux/parport.h>
42 #  include <linux/ppdev.h>
43 #include <errno.h>
44 
45 #elif defined (__FreeBSD__)
46 // Default parport device
47 #ifndef PPDEV
48 #  define PPDEV "/dev/parport0"
49 #include <errno.h>
50 #endif
51 
52 #include <sys/ioctl.h>
53 #  include <dev/ppbus/ppi.h>
54 #  include <dev/ppbus/ppbconf.h>
55 
56 #  define PARPORT_CONTROL_STROBE    STROBE
57 #  define PARPORT_CONTROL_AUTOFD    AUTOFEED
58 #  define PARPORT_CONTROL_INIT      INIT
59 #  define PARPORT_CONTROL_SELECT    SELECTIN
60                      /* DLC 5 Schematics:
61             http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html
62                         Pin Connectes for a 25 pin parallel port connector
63                         http://www.kabelfaq.de/-> parallel
64                         Pin 15 is nERR*/
65 #  define PARPORT_STATUS_ERROR      nFAULT
66                      /* PIN 13 is SELECT (Printer is online)*/
67 #  define PARPORT_STATUS_SELECT     SELECT
68                      /* PIN 12 is PE */
69 #  define PARPORT_STATUS_PAPEROUT   PERROR
70                      /* PIN 10 is nACK */
71 #  define PARPORT_STATUS_ACK        nACK
72                      /* PIN 11 is nBusy */
73 #  define PARPORT_STATUS_BUSY       nBUSY
74 
75 #elif defined (__WIN32__)
76 // Default parport device
77 #ifndef PPDEV
78 #  define PPDEV "\\\\.\\$VDMLPT1"
79 #endif
80 #include <windows.h>
81 #include <ddk/ntddpar.h>
82 #include "par_nt.h"
83 
84 /*FIXME: These defines fit numerically, but not logically*/
85 #  define PARPORT_CONTROL_STROBE    PARALLEL_INIT
86 #  define PARPORT_CONTROL_AUTOFD    PARALLEL_AUTOFEED
87 #  define PARPORT_CONTROL_INIT      PARALLEL_PAPER_EMPTY
88 #  define PARPORT_CONTROL_SELECT    PARALLEL_OFF_LINE
89 
90 #  define PARPORT_STATUS_ERROR      PARALLEL_OFF_LINE
91 #  define PARPORT_STATUS_SELECT     PARALLEL_POWER_OFF
92 #  define PARPORT_STATUS_PAPEROUT   PARALLEL_NOT_CONNECTED
93 #  define PARPORT_STATUS_ACK        PARALLEL_BUSY
94 #  define PARPORT_STATUS_BUSY       PARALLEL_SELECTED
95 #endif
96 
97 #include <sys/time.h>
98 #include <unistd.h>
99 
100 #include "ioparport.h"
101 #include "debug.h"
102 
103 #define NO_CABLE 0
104 #define IS_PCIII 1
105 #define IS_BBLST 2
106 
107 #define BIT_MASK(b)     (1<<(b))
108 
109 /* Attention: PARPORT_STATUS_BUSY reflects the inverted input */
110 /* Attention: PARPORT_CONTROL_AUTOFD write zero to output */
111 
112 /* Altera Byteblaster Definitions */
113 #define BBLST_DEF_BYTE      0
114 #define BBLST_ENABLE_N      PARPORT_CONTROL_AUTOFD   /* Base + 2, Inv */
115 #define BBLST_TCK_VALUE     BIT_MASK(0)              /* Base */
116 #define BBLST_TMS_VALUE     BIT_MASK(1)              /* Base */
117 #define BBLST_TDI_VALUE     BIT_MASK(6)              /* Base */
118 #define BBLST_RESET_VALUE   BIT_MASK(3)              /* Base, Inv by Open
119 			    			        Collector Transistor */
120 #define BBLST_TDO_MASK      PARPORT_STATUS_BUSY      /* Base + 1, Input */
121 #define BBLST_LB_IN_MASK    PARPORT_STATUS_PAPEROUT  /* Base + 1, Input */
122 #define BBLST_LB_OUT_VALUE  BIT_MASK(7)              /* Base */
123 #define BBLST_ACK_OUT_VALUE BIT_MASK(5)
124 #define BBLST_ACK_IN_MASK   PARPORT_STATUS_ACK
125 
126 /* Xilinx Parallel Cable III Definitions */
127 #define PCIII_PROG_EN_N     BIT_MASK(4)
128 #define PCIII_DEF_BYTE      PCIII_PROG_EN_N
129 #define PCIII_TCK_VALUE     BIT_MASK(1)              /* Base */
130 #define PCIII_TMS_VALUE     BIT_MASK(2)              /* Base */
131 #define PCIII_TDI_VALUE     BIT_MASK(0)              /* Base */
132 #define PCIII_TDO_MASK      PARPORT_STATUS_SELECT
133 #define PCIII_CHECK_OUT     BIT_MASK(6)
134 #define PCIII_CHECK_IN1     PARPORT_STATUS_BUSY
135 #define PCIII_CHECK_IN2     PARPORT_STATUS_PAPEROUT
136 
137 
138 using namespace std;
139 
detectcable(void)140 int  IOParport::detectcable(void)
141 {
142   unsigned char data=0, status, control;
143 
144 
145   write_data(fd, data);
146   read_status(fd, &status);
147   read_control(fd, &control);
148   if ((status == 0) || (status == 0xff))
149     {
150       fprintf(stderr,"IOParport::detectcable status 0x%02x control %02x"
151 	      " Check system driver setup\n",
152 	      status, control);
153       return NO_CABLE;
154     }
155   /* Error_n should is hardwired to ground on a byteblaster cable*/
156   if (!(status & PARPORT_STATUS_ERROR))
157     {
158       if (debug & HW_DETAILS)
159 	fprintf(stderr,"Trying Byteblaster\n");
160       /* D5/ACK and D7/PE should be connected*/
161       if (( (data & BBLST_LB_OUT_VALUE)  && !(status & BBLST_LB_IN_MASK)) ||
162 	  (!(data & BBLST_LB_OUT_VALUE)  &&  (status & BBLST_LB_IN_MASK)))
163 	{ /* The difference is in D7/PE if the card is unpowered*/
164 	  if(( (data & BBLST_ACK_OUT_VALUE) &&  (status & BBLST_ACK_IN_MASK))||
165 	     (!(data & BBLST_ACK_OUT_VALUE) && !(status & BBLST_ACK_IN_MASK)))
166 	    {
167 	      fprintf(stderr,"Unpowered Byteblaster cable\n");
168 	      return NO_CABLE;
169 	    }
170 	  /*We have an unpowered Xilinx cable if D6/Busy/PE are connected */
171 	  else if
172 	    ( ( (data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN1))||
173 	      (!(data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN1))||
174 	      ( (data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN2))||
175 	      (!(data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN2))) {
176 	    fprintf(stderr,"Unpowered Parallel Cable III cable\n");
177 	    return NO_CABLE;
178 	  }
179 	  else 	    {
180 	    fprintf(stderr,"No dongle found\n");
181 	    return NO_CABLE;
182 	  }
183 	}
184       /* now try all 4 permuttation */
185       data = (data & BBLST_LB_OUT_VALUE) ? (data & ~BBLST_LB_OUT_VALUE) :
186 	(data | BBLST_LB_OUT_VALUE);
187       write_data(fd, data);
188       read_status(fd, &status);
189       if (( (data & BBLST_LB_OUT_VALUE)  && !(status & BBLST_LB_IN_MASK)) ||
190 	  (!(data & BBLST_LB_OUT_VALUE)  &&  (status & BBLST_LB_IN_MASK)) ||
191 	  ( (data & BBLST_ACK_OUT_VALUE) && !(status & BBLST_ACK_IN_MASK))||
192 	  (!(data & BBLST_ACK_OUT_VALUE) &&  (status & BBLST_ACK_IN_MASK)))
193 	{
194 	  fprintf(stderr,"Missing reaction for Altera cable(1)\n");
195 	  return NO_CABLE;
196 	}
197       data = (data & BBLST_ACK_OUT_VALUE) ? (data & ~BBLST_ACK_OUT_VALUE) :
198 	(data | BBLST_ACK_OUT_VALUE);
199       write_data(fd, data);
200       read_status(fd, &status);
201       if (( (data & BBLST_LB_OUT_VALUE)  && !(status & BBLST_LB_IN_MASK)) ||
202 	  (!(data & BBLST_LB_OUT_VALUE)  &&  (status & BBLST_LB_IN_MASK)) ||
203 	  ( (data & BBLST_ACK_OUT_VALUE) && !(status & BBLST_ACK_IN_MASK))||
204 	  (!(data & BBLST_ACK_OUT_VALUE) &&  (status & BBLST_ACK_IN_MASK)))
205 	{
206 	  fprintf(stderr,"Missing reaction for Altera cable(2)\n");
207 	  return NO_CABLE;
208 	}
209       data = (data & BBLST_LB_OUT_VALUE) ? (data & ~BBLST_LB_OUT_VALUE) :
210 	(data | BBLST_LB_OUT_VALUE);
211       write_data(fd, data);
212       read_status(fd, &status);
213       if (( (data & BBLST_LB_OUT_VALUE)  && !(status & BBLST_LB_IN_MASK)) ||
214 	  (!(data & BBLST_LB_OUT_VALUE)  &&  (status & BBLST_LB_IN_MASK)) ||
215 	  ( (data & BBLST_ACK_OUT_VALUE) && !(status & BBLST_ACK_IN_MASK))||
216 	  (!(data & BBLST_ACK_OUT_VALUE) &&  (status & BBLST_ACK_IN_MASK)))
217 	{
218 	  fprintf(stderr,"Missing reaction for Altera cable(3)\n");
219 	  return NO_CABLE;
220 	}
221       data = (data & BBLST_ACK_OUT_VALUE) ? (data & ~BBLST_ACK_OUT_VALUE) :
222 	(data | BBLST_ACK_OUT_VALUE);
223       write_data(fd, data);
224       read_status(fd, &status);
225       if (( (data & BBLST_LB_OUT_VALUE)  && !(status & BBLST_LB_IN_MASK)) ||
226 	  (!(data & BBLST_LB_OUT_VALUE)  &&  (status & BBLST_LB_IN_MASK)) ||
227 	  ( (data & BBLST_ACK_OUT_VALUE) && !(status & BBLST_ACK_IN_MASK))||
228 	  (!(data & BBLST_ACK_OUT_VALUE) &&  (status & BBLST_ACK_IN_MASK)))
229 	{
230 	  fprintf(stderr,"Missing reaction for Altera cable(4)\n");
231 	  return NO_CABLE;
232 	}
233       fprintf(stderr,"Found ByteBlaster Cable\n");
234       def_byte = BBLST_DEF_BYTE;
235       tdi_value = BBLST_TDI_VALUE;
236       tms_value = BBLST_TMS_VALUE;
237       tck_value = BBLST_TCK_VALUE;
238       tdo_mask = BBLST_TDO_MASK;
239       tdo_inv  = 1;
240       read_control(fd, &control);
241       control |=  BBLST_ENABLE_N;
242       write_control(fd, control);
243       return IS_BBLST;
244     }
245   else { /*Probably  Xilinx cable */
246     /* Check for D6/BUSY/PE Connection and for D4/Select Feedback */
247     if ( ( (data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN1))||
248 	 (!(data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN1))||
249 	 ( (data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN2))||
250 	 (!(data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN2)))
251       {
252 	fprintf(stderr,"No dongle found\n");
253 	return NO_CABLE;
254       }
255 
256 /* 20100708: This check will only work with U1 on the DLC(clone)
257  * from a high drive family like LVC and a not so strong driver at the end
258  * of the JTAG chain, like an XCF0x.
259  * E.G. Digilent S3 drives TDO-A with an LVC, while the
260  * original DLC5 only has an HC125, and so the HC125 can not drive the line
261  * low consitstantly
262  *
263  * So disable this check
264 
265     if ((status & PCIII_TDO_MASK) && (!(data & PCIII_PROG_EN_N))) {
266 	fprintf(stderr,"Missing power for Parallel Cable III\n");
267 	return NO_CABLE;}
268 */
269     data = (data & PCIII_CHECK_OUT) ? (data & ~PCIII_CHECK_OUT) :
270       (data |PCIII_CHECK_OUT);
271     write_data(fd, data);
272     read_status(fd, &status);
273     if ( ( (data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN1))||
274 	 (!(data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN1))||
275 	 ( (data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN2)) ||
276 	 (!(data & PCIII_CHECK_OUT) && (status & PCIII_CHECK_IN2)))
277 	{
278 	  fprintf(stderr,"Missing reaction on XILINX Cable(1)\n");
279 	  return NO_CABLE;
280 	}
281     data = (data & PCIII_CHECK_OUT) ? (data & ~PCIII_CHECK_OUT) :
282       (data | PCIII_CHECK_OUT);
283     write_data(fd, data);
284     read_status(fd, &status);
285     if ( ( (data & PCIII_CHECK_OUT) &&  (status & PCIII_CHECK_IN1))||
286 	 (!(data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN1))||
287 	 ( (data & PCIII_CHECK_OUT) && !(status & PCIII_CHECK_IN2))||
288 	 (!(data & PCIII_CHECK_OUT) && (status & PCIII_CHECK_IN2)))
289       {
290 	fprintf(stderr,"Missing reaction on XILINX Cable(2)\n");
291 	return NO_CABLE;
292       }
293     fprintf(stderr,"Found Xilinx Parallel Cable III\n");
294     def_byte = PCIII_DEF_BYTE;
295     tdi_value = PCIII_TDI_VALUE;
296     tms_value = PCIII_TMS_VALUE;
297     tck_value = PCIII_TCK_VALUE;
298     tdo_mask = PCIII_TDO_MASK;
299     tdo_inv = 0;
300     return IS_PCIII;
301   }
302 }
303 
IOParport()304 IOParport::IOParport() : IOBase(), total(0), debug(0)
305 {
306 }
307 
Init(struct cable_t * cable,const char * dev,unsigned int freq)308 int IOParport::Init(struct cable_t *cable, const char *dev, unsigned int freq)
309 {
310     int res;
311 
312   // Try to obtain device from environment or use default if not given
313   if(!dev) {
314     if(!(dev = getenv("XCPORT")))  dev = PPDEV;
315   }
316 
317 #if defined (__linux__) || defined(__FreeBSD__)
318   // Try to open parport device
319   if((fd = open(dev, O_RDWR)) == -1)
320 #elif defined(__WIN32__)
321     if ((fd = (int)CreateFile(dev, GENERIC_READ | GENERIC_WRITE,
322 			      0, NULL, OPEN_EXISTING, 0, NULL))
323 	== (int)INVALID_HANDLE_VALUE)
324 #endif
325       {
326 	fprintf(stderr,"Could not access parallel device '%s': %s\n",
327 		dev, strerror(errno));
328 	return -1;
329       }
330 
331 #if defined (__linux__)
332   // Lock port
333   res = ioctl(fd, PPCLAIM);
334   if(res)
335   {
336       fprintf(stderr, "Port %s already in use\n", dev);
337       return res;
338   }
339 
340   // Switch to compatibility mode
341   int const  mode = IEEE1284_MODE_COMPAT;
342   res = ioctl(fd, PPNEGOT, &mode);
343   if(res) {
344       fprintf(stderr,"IEEE1284 compatibility not available on dev %s\n", dev);
345       return res;
346   }
347 #endif
348   cabletype = detectcable();
349   if(cabletype == NO_CABLE)
350   {
351       fprintf(stderr, "No adapter found\n");
352       return 1;
353   }
354   return 0;
355 }
356 
txrx(bool tms,bool tdi)357 bool IOParport::txrx(bool tms, bool tdi)
358 {
359   unsigned char ret;
360   bool retval;
361   unsigned char data=def_byte; // D4 pin5 TDI enable
362   if(tdi)data|=tdi_value; // D0 pin2
363   if(tms)data|=tms_value; // D2 pin4
364   write_data(fd, data);
365   data|=tck_value; // clk high D1 pin3
366   write_data(fd, data);
367   total++;
368   read_status(fd, &ret);
369   //data=data^2; // clk low
370   //write_data(fd, data);
371   //read_status(fd, &ret);
372   retval = (ret&tdo_mask)?!tdo_inv:tdo_inv;
373   if (debug & HW_FUNCTIONS)
374     fprintf(stderr,"IOParport::txrx tms %s tdi %s tdo %s \n",
375 	    (tms)?"true ":"false", (tdi)?"true ":"false",
376 	    (retval)?"true ":"false");
377   return retval;
378 
379 }
380 
tx(bool tms,bool tdi)381 void IOParport::tx(bool tms, bool tdi)
382 {
383   unsigned char data=def_byte; // D4 pin5 TDI enable
384   if (debug & HW_FUNCTIONS)
385     fprintf(stderr,"tx tms %s tdi %s\n",(tms)?"true ":"false",
386 	    (tdi)?"true ":"false");
387   if(tdi)data|=tdi_value; // D0 pin2
388   if(tms)data|=tms_value; // D2 pin4
389   write_data(fd, data);
390   //delay(2);
391   data|=tck_value; // clk high
392   total++;
393   write_data(fd, data);
394   //delay(2);
395   //data=data^2; // clk low
396   //write_data(fd, data);
397   //delay(2);
398 }
399 
tx_tdi_byte(unsigned char tdi_byte)400 void IOParport::tx_tdi_byte(unsigned char tdi_byte)
401 {
402   int k;
403 
404   for (k = 0; k < 8; k++)
405     tx(false, (tdi_byte>>k)&1);
406 }
407 
txrx_block(const unsigned char * tdi,unsigned char * tdo,int length,bool last)408 void IOParport::txrx_block(const unsigned char *tdi, unsigned char *tdo,
409 			   int length, bool last)
410 {
411   int i=0;
412   int j=0;
413   unsigned char tdo_byte=0;
414   unsigned char tdi_byte;
415   unsigned char data=def_byte;
416   if (tdi)
417       tdi_byte = tdi[j];
418 
419   while(i<length-1){
420       tdo_byte=tdo_byte+(txrx(false, (tdi_byte&1)==1)<<(i%8));
421       if (tdi)
422 	  tdi_byte=tdi_byte>>1;
423     i++;
424     if((i%8)==0){ // Next byte
425 	if(tdo)
426 	    tdo[j]=tdo_byte; // Save the TDO byte
427       tdo_byte=0;
428       j++;
429       if (tdi)
430 	  tdi_byte=tdi[j]; // Get the next TDI byte
431     }
432   };
433   tdo_byte=tdo_byte+(txrx(last, (tdi_byte&1)==1)<<(i%8));
434   if(tdo)
435       tdo[j]=tdo_byte;
436   write_data(fd, data); /* Make sure, TCK is low */
437   return;
438 }
439 
tx_tms(unsigned char * pat,int length,int force)440 void IOParport::tx_tms(unsigned char *pat, int length, int force)
441 {
442     int i;
443     unsigned char tms;
444     unsigned char data=def_byte;
445     for (i = 0; i < length; i++)
446     {
447       if ((i & 0x7) == 0)
448 	tms = pat[i>>3];
449       tx((tms & 0x01), true);
450       tms = tms >> 1;
451     }
452     write_data(fd, data); /* Make sure, TCK is low */
453 }
454 
~IOParport()455 IOParport::~IOParport()
456 {
457   if (cabletype == IS_BBLST)
458     {
459       unsigned char control;
460       read_control(fd, &control);
461       control &=  ~BBLST_ENABLE_N;
462       write_control(fd, control);
463     }
464 #ifdef __linux__
465   ioctl (fd, PPRELEASE);
466   close (fd);
467 #elif defined(__FreeBSD__)
468   close (fd);
469 #elif defined(__WIN32__)
470   CloseHandle((HANDLE)(fd));
471 #endif
472   if (verbose) fprintf(stderr, "Total bytes sent: %d\n", total>>3);
473 }
474 #define XC3S_OK 0
475 #define XC3S_EIO 1
476 #define XC3S_ENIMPL 2
477 
write_data(int fd,unsigned char data)478 int IOParport::write_data(int fd, unsigned char data)
479 {
480     int status;
481 #ifdef __linux__
482     status = ioctl(fd, PPWDATA, &data);
483     return  status == 0 ? XC3S_OK : -XC3S_EIO;
484 #elif defined (__FreeBSD__)
485     status = ioctl(fd, PPISDATA, &data);
486     return status == 0 ? XC3S_OK : -XC3S_EIO;
487 #elif defined(__WIN32__)
488     DWORD dummy;
489     status = DeviceIoControl((HANDLE)(fd), NT_IOCTL_DATA, &data, sizeof(data),
490                              NULL, 0, (LPDWORD)&dummy, NULL);
491     return status != 0 ? XC3S_OK : -XC3S_EIO;
492 #else
493     return -XC3S_ENIMPL;
494 #endif
495 }
496 
497 
write_control(int fd,unsigned char control)498 int IOParport::write_control(int fd, unsigned char control)
499 {
500     int status;
501 #ifdef __linux__
502     status = ioctl(fd, PPWCONTROL, &control);
503     return status == 0 ? XC3S_OK : -XC3S_EIO;
504 #elif defined (__FreeBSD__)
505     status = ioctl(fd, PPISCTRL, &control);
506     return status == 0 ? XC3S_OK : -XC3S_EIO;
507 #elif defined(__WIN32__)
508     DWORD dummyc;
509     DWORD dummy;
510     /*FIXME: hamlib used much more compicated expression*/
511     status = DeviceIoControl((HANDLE)(fd),NT_IOCTL_CONTROL, &control,
512                              sizeof(control), &dummyc, sizeof(dummyc),
513 			     (LPDWORD)&dummy, NULL);
514     return status != 0 ? XC3S_OK : -XC3S_EIO;
515 #else
516     return -XC3S_ENIMPL;
517 #endif
518 }
519 
read_control(int fd,unsigned char * control)520 int IOParport::read_control(int fd, unsigned char *control)
521 {
522     int status;
523 #ifdef __linux
524     status = ioctl(fd, PPRCONTROL, control);
525     return status == 0 ? XC3S_OK : -XC3S_EIO;
526 #elif defined (__FreeBSD__)
527     status = ioctl(fd, PPIGCTRL, control);
528     return status == 0 ? XC3S_OK : -XC3S_EIO;
529 #elif defined (__WIN32__)
530     char ret;
531     DWORD dummy;
532     status = DeviceIoControl((HANDLE)(fd), NT_IOCTL_CONTROL, NULL, 0, &ret,
533                              sizeof(ret), (LPDWORD)&dummy, NULL);
534     *control = ret ^ S1284_INVERTED;
535     return status == 0 ? XC3S_OK : -XC3S_EIO;
536 #else
537     return -XC3S_ENIMPL;
538 #endif
539 }
540 
read_status(int fd,unsigned char * status)541 int IOParport::read_status(int fd, unsigned char *status)
542 {
543     int ret;
544 #ifdef __linux__
545     ret = ioctl(fd, PPRSTATUS, status);
546     return ret == 0 ? XC3S_OK : -XC3S_EIO;
547 #elif defined (__FreeBSD__)
548     ret = ioctl(fd, PPIGSTATUS, status);
549     return ret == 0 ? XC3S_OK : -XC3S_EIO;
550 #elif defined (__WIN32__)
551     unsigned char res;
552     DWORD dummy;
553     ret = DeviceIoControl((HANDLE)(fd), NT_IOCTL_STATUS, NULL, 0, &res,
554                              sizeof(res), (LPDWORD)&dummy, NULL);
555     *status = res ;
556     return ret == 0 ? XC3S_OK : -XC3S_EIO;
557 #else
558     return -XC3S_ENIMPL;
559 #endif
560 }
561 
562 
563