1/* @file plustekpp-io.c
2 * @brief as the name says, here we have all the I/O
3 *        functions according to the parallel port hardware
4 *
5 * based on sources acquired from Plustek Inc.
6 * Copyright (C) 1998 Plustek Inc.
7 * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
8 *
9 * History:
10 * - 0.37 - initial version
11 *        - added Kevins' suggestions
12 * - 0.38 - added Asic 98003 stuff and ioP98ReadWriteTest()
13 *        - added IODataRegisterToDAC()
14 *        - replaced function IOSPPWrite by IOMoveDataToScanner
15 *        - modified ioP98OpenScanPath again and reuse V0.36 stuff again
16 *        - added IO functions
17 * - 0.39 - added IO functions
18 *        - added f97003 stuff from A3I code
19 * - 0.40 - no changes
20 * - 0.41 - no changes
21 * - 0.42 - changed include names
22 * - 0.43 - no changes
23 * - 0.44 - fix format string issues, as Long types default to int32_t
24 *          now
25 * .
26 * <hr>
27 * This file is part of the SANE package.
28 *
29 * This program is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU General Public License as
31 * published by the Free Software Foundation; either version 2 of the
32 * License, or (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful, but
35 * WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37 * General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
41 *
42 * As a special exception, the authors of SANE give permission for
43 * additional uses of the libraries contained in this release of SANE.
44 *
45 * The exception is that, if you link a SANE library with other files
46 * to produce an executable, this does not by itself cause the
47 * resulting executable to be covered by the GNU General Public
48 * License.  Your use of that executable is in no way restricted on
49 * account of linking the SANE library code into it.
50 *
51 * This exception does not, however, invalidate any other reasons why
52 * the executable file might be covered by the GNU General Public
53 * License.
54 *
55 * If you submit changes to SANE to the maintainers to be included in
56 * a subsequent release, you agree by submitting the changes that
57 * those changes may be distributed with this exception intact.
58 *
59 * If you write modifications of your own for SANE, it is your choice
60 * whether to permit this exception to apply to your modifications.
61 * If you do not wish that, delete this exception notice.
62 * <hr>
63 */
64#include "plustek-pp_scan.h"
65
66/*************************** some prototypes *********************************/
67
68static Bool fnEPPRead  ( pScanData ps, pUChar pBuffer, ULong ulSize );
69static Bool fnSPPRead  ( pScanData ps, pUChar pBuffer, ULong ulSize );
70static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize );
71
72typedef struct {
73	pFnReadData func;
74	char       *name;
75} ioReadFuncDef;
76
77static ioReadFuncDef ioReadFunc[3] = {
78	{ fnEPPRead,   "fnEPPRead"   },
79	{ fnSPPRead,   "fnSPPRead"   },
80	{ fnBiDirRead, "fnBiDirRead" }
81};
82
83/*************************** some definitions ********************************/
84
85#define _MEMTEST_SIZE   1280
86
87/*************************** local functions *********************************/
88
89/** we provide some functions to read data from SPP port according to
90 * the speed we have detected (ReadWriteTest!!)
91 */
92static Byte ioDataFromSPPFast( pScanData ps )
93{
94	Byte bData, tmp;
95
96	/* notify asic we will read the high nibble data from status port */
97	if( _FALSE == ps->f97003 ) {
98		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
99		_DO_UDELAY( 1 );
100	}
101
102	/* read high nibble */
103    bData  = _INB_STATUS( ps );
104	bData &= 0xf0;
105
106    _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
107	_DO_UDELAY( 1 );
108
109	/* read low nibble */
110	tmp = _INB_STATUS( ps );
111
112	/* combine with low nibble */
113    bData |= (tmp >> 4);
114
115    _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
116	_DO_UDELAY( 1 );
117
118    return bData;
119}
120
121static Byte ioDataFromSPPMiddle( pScanData ps )
122{
123	Byte bData, tmp;
124
125	/* notify asic we will read the high nibble data from status port */
126	if( _FALSE == ps->f97003 ) {
127		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
128		_DO_UDELAY( 1 );
129	}
130
131	/* read high nibble */
132	_INB_STATUS( ps );
133    bData  = _INB_STATUS( ps );
134	bData &= 0xf0;
135
136    _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
137	_DO_UDELAY( 1 );
138
139	/* read low nibble */
140	_INB_STATUS( ps );
141	tmp = _INB_STATUS( ps );
142
143	/* combine with low nibble */
144    bData |= (tmp >> 4);
145
146    _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
147	_DO_UDELAY( 1 );
148
149    return bData;
150}
151
152static UChar ioDataFromSPPSlow( pScanData ps )
153{
154	Byte bData, tmp;
155
156	/* notify asic we will read the high nibble data from status port */
157	if( _FALSE == ps->f97003 ) {
158		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
159		_DO_UDELAY( 2 );
160	}
161
162	/* read high nibble */
163	_INB_STATUS( ps );
164	_INB_STATUS( ps );
165    bData  = _INB_STATUS( ps );
166	bData &= 0xf0;
167
168    _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
169	_DO_UDELAY( 2 );
170
171	/* read low nibble */
172	_INB_STATUS( ps );
173	_INB_STATUS( ps );
174	tmp = _INB_STATUS( ps );
175
176	/* combine with low nibble */
177    bData |= (tmp >> 4);
178
179    _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
180	_DO_UDELAY( 2 );
181
182    return bData;
183}
184
185static UChar ioDataFromSPPSlowest( pScanData ps )
186{
187	Byte bData, tmp;
188
189	/* notify asic we will read the high nibble data from status port */
190	if( _FALSE == ps->f97003 ) {
191		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
192		_DO_UDELAY( 3 );
193	}
194
195	/* read high nibble */
196	_INB_STATUS( ps );
197	_INB_STATUS( ps );
198	_INB_STATUS( ps );
199    bData  = _INB_STATUS( ps );
200	bData &= 0xf0;
201
202    _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
203	_DO_UDELAY( 3 );
204
205	/* read low nibble */
206	_INB_STATUS( ps );
207	_INB_STATUS( ps );
208	_INB_STATUS( ps );
209	tmp = _INB_STATUS( ps );
210
211	/* combine with low nibble */
212    bData |= (tmp >> 4);
213
214    _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
215	_DO_UDELAY( 3 );
216
217    return bData;
218}
219
220/** Read data from STATUS port. We have to read twice and combine two nibble
221 *  data to one byte.
222 */
223static Bool fnSPPRead( pScanData ps, pUChar pBuffer, ULong ulSize )
224{
225	switch( ps->IO.delay ) {
226
227		case 0:
228			for (; ulSize; ulSize--, pBuffer++)
229				*pBuffer = ioDataFromSPPFast( ps );
230			break;
231
232		case 1:
233			for (; ulSize; ulSize--, pBuffer++)
234				*pBuffer = ioDataFromSPPMiddle( ps );
235			break;
236
237		case 2:
238			for (; ulSize; ulSize--, pBuffer++)
239				*pBuffer = ioDataFromSPPSlow( ps );
240			break;
241
242		default:
243			for (; ulSize; ulSize--, pBuffer++)
244				*pBuffer = ioDataFromSPPSlowest( ps );
245			break;
246	}
247
248    return _TRUE;
249}
250
251
252/** Using buffered I/O to read data from EPP Data Port
253 */
254static Bool fnEPPRead( pScanData ps, pUChar pBuffer, ULong ulSize )
255{
256	register ULong i;
257
258	if( _IS_ASIC98(ps->sCaps.AsicID)) {
259
260		sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAIN );
261		for( i = 0; i < ulSize; i++ )
262			pBuffer[i] = _INB_EPPDATA( ps );
263
264		sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAOUT );
265	} else {
266
267		for( i = 0; i < ulSize; i++ )
268			pBuffer[i] = _INB_EPPDATA( ps );
269	}
270
271	return _TRUE;
272}
273
274/**
275 */
276static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize )
277{
278	UChar start, end;
279
280	start = _CTRL_START_BIDIREAD;
281	end   = _CTRL_END_BIDIREAD;
282
283	sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAIN );
284
285	if( !sanei_pp_uses_directio()) {
286		start &= ~_CTRL_DIRECTION;
287		end   &= ~_CTRL_DIRECTION;
288	}
289
290	switch( ps->IO.delay ) {
291
292		case 0:
293		    for( ; ulSize; ulSize--, pBuffer++ ) {
294				_OUTB_CTRL( ps, start );
295				*pBuffer = _INB_DATA( ps );
296				_OUTB_CTRL( ps, end );
297			}
298			break;
299
300		case 1:
301			_DO_UDELAY( 1 );
302		    for(; ulSize; ulSize--, pBuffer++ ) {
303				_OUTB_CTRL( ps, start );
304				_DO_UDELAY( 1 );
305
306				*pBuffer = _INB_DATA( ps );
307
308				_OUTB_CTRL( ps, end );
309				_DO_UDELAY( 1 );
310			}
311			break;
312
313		default:
314			_DO_UDELAY( 2 );
315		    for(; ulSize; ulSize--, pBuffer++ ) {
316				_OUTB_CTRL( ps, start );
317				_DO_UDELAY( 2 );
318
319				*pBuffer = _INB_DATA( ps );
320
321				_OUTB_CTRL( ps, end );
322				_DO_UDELAY( 2 );
323			}
324			break;
325
326	}
327
328	sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAOUT );
329	return _TRUE;
330}
331
332/** as the name says, we switch to SPP mode
333 */
334static void ioSwitchToSPPMode( pScanData ps )
335{
336	/* save the control and data port value
337	 */
338	ps->IO.bOldControlValue = _INB_CTRL( ps );
339	ps->IO.bOldDataValue    = _INB_DATA( ps );
340
341	_OUTB_CTRL( ps, _CTRL_GENSIGNAL );	/* 0xc4 */
342	_DO_UDELAY( 2 );
343}
344
345/** restore the port settings
346 */
347static void ioRestoreParallelMode( pScanData ps )
348{
349	_OUTB_CTRL( ps, ps->IO.bOldControlValue & 0x3f );
350	_DO_UDELAY( 1 );
351
352	_OUTB_DATA( ps, ps->IO.bOldDataValue );
353	_DO_UDELAY( 1 );
354}
355
356/** try to connect to scanner (ASIC 9600x and 98001)
357 */
358_LOC void ioP98001EstablishScannerConnection( pScanData ps, ULong delTime )
359{
360	_OUTB_DATA( ps, _ID_TO_PRINTER );
361    _DO_UDELAY( delTime );
362
363	_OUTB_DATA( ps, _ID1ST );
364    _DO_UDELAY( delTime );
365
366	_OUTB_DATA( ps, _ID2ND );
367    _DO_UDELAY( delTime );
368
369	_OUTB_DATA( ps, _ID3RD );
370    _DO_UDELAY( delTime );
371
372    _OUTB_DATA( ps, _ID4TH );
373    _DO_UDELAY( delTime );
374}
375
376/** try to connect to scanner (ASIC 98003)
377 */
378static void ioP98003EstablishScannerConnection( pScanData ps, ULong delTime )
379{
380	_OUTB_DATA( ps, _ID1ST );
381	_DO_UDELAY( delTime );
382
383	_OUTB_DATA( ps, _ID2ND );
384	_DO_UDELAY( delTime );
385
386	_OUTB_DATA( ps, _ID3RD );
387	_DO_UDELAY( delTime );
388
389	_OUTB_DATA( ps, _ID4TH );
390	_DO_UDELAY( delTime );
391}
392
393/** switch the printer interface to scanner
394 */
395static Bool ioP96OpenScanPath( pScanData ps )
396{
397	if( 0 == ps->IO.bOpenCount ) {
398
399		/* not established */
400		ioSwitchToSPPMode( ps );
401
402		/* Scanner command sequence to open scanner path */
403		ioP98001EstablishScannerConnection( ps, 5 );
404	}
405#ifdef DEBUG
406	else
407		DBG( DBG_IO, "!!!! Path already open (%u)!!!!\n", ps->IO.bOpenCount );
408#endif
409
410	ps->IO.bOpenCount++;			/* increment the opened count */
411
412/*
413 * CHECK to we really need that !!
414 */
415	ps->IO.useEPPCmdMode = _FALSE;
416	return _TRUE;
417}
418
419/** try to connect to scanner
420 */
421static Bool ioP98OpenScanPath( pScanData ps )
422{
423    Byte  tmp;
424    ULong dw;
425	ULong dwTime = 1;
426
427	if( 0 == ps->IO.bOpenCount ) {
428
429		/* not established */
430		ioSwitchToSPPMode( ps );
431
432		for( dw = 10; dw; dw-- ) {
433
434			/*
435			 * this seems to be necessary...
436			 */
437 			if( _ASIC_IS_98001 == ps->sCaps.AsicID ) {
438				ioP98001EstablishScannerConnection( ps, dw );
439#if 0
440				ioP98001EstablishScannerConnection( ps, dw );
441				ioP98001EstablishScannerConnection( ps, dw );
442#endif
443			} else {
444				ioP98003EstablishScannerConnection( ps, dw );
445			}
446
447			_INB_STATUS( ps );
448			tmp = _INB_STATUS( ps );
449
450			if( 0x50 == ( tmp & 0xf0 )) {
451
452				ps->IO.bOpenCount = 1;
453
454				if( ps->sCaps.AsicID == IODataFromRegister(ps, ps->RegAsicID)) {
455					return _TRUE;
456				}
457				ps->IO.bOpenCount = 0;
458			}
459
460			dwTime++;
461		}
462		DBG( DBG_IO, "ioP98OpenScanPath() failed!\n" );
463		return _FALSE;
464	}
465#ifdef DEBUG
466	else
467		DBG( DBG_IO, "!!!! Path already open (%u)!!!!\n", ps->IO.bOpenCount );
468#endif
469
470	ps->IO.bOpenCount++;			/* increment the opened count */
471	return _TRUE;
472}
473
474/** Switch back to printer mode.
475 * Restore the printer control/data port value.
476 */
477static void ioCloseScanPath( pScanData ps )
478{
479	if( ps->IO.bOpenCount && !(--ps->IO.bOpenCount)) {
480
481#ifdef DEBUG
482		ps->IO.bOpenCount = 1;
483#endif
484		IORegisterToScanner( ps, 0xff );
485
486		/*
487		 * back to pass-through printer mode
488		 */
489		IORegisterToScanner( ps, ps->RegSwitchBus );
490#ifdef DEBUG
491        ps->IO.bOpenCount = 0;
492#endif
493		ps->IO.useEPPCmdMode = _FALSE;
494
495		ioRestoreParallelMode( ps );
496	}
497}
498
499/** check the memory to see that the data-transfers will work.
500 * (ASIC 9800x only)
501 */
502static int ioP98ReadWriteTest( pScanData ps )
503{
504	UChar  tmp;
505	ULong  ul;
506	pUChar buffer;
507	int	   retval;
508
509	DBG( DBG_LOW, "ioP98ReadWriteTest()\n" );
510
511	/* _MEMTEST_SIZE: Read, _MEMTEST_SIZE:Write */
512	buffer = _KALLOC( sizeof(UChar) * _MEMTEST_SIZE*2, GFP_KERNEL );
513	if( NULL == buffer )
514		return _E_ALLOC;
515
516	/* prepare content */
517	for( ul = 0; ul < _MEMTEST_SIZE; ul++ )
518	    buffer[ul] = (UChar)ul;
519
520	ps->OpenScanPath(ps);
521
522	/* avoid switching to Lamp0, when previously scanned in transp./neg mode */
523	tmp = ps->bLastLampStatus + _SCAN_BYTEMODE;
524	IODataToRegister( ps, ps->RegScanControl, tmp );
525
526	IODataToRegister( ps, ps->RegModelControl, (_LED_ACTIVITY | _LED_CONTROL));
527
528	IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
529	IODataToRegister( ps, ps->RegMemoryLow,  0 );
530	IODataToRegister( ps, ps->RegMemoryHigh, 0 );
531
532	/* fill to buffer */
533	IOMoveDataToScanner( ps, buffer, _MEMTEST_SIZE );
534
535	IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
536	IODataToRegister( ps, ps->RegMemoryLow,  0 );
537	IODataToRegister( ps, ps->RegMemoryHigh, 0 );
538	IODataToRegister( ps, ps->RegWidthPixelsLow,  0 );
539	IODataToRegister( ps, ps->RegWidthPixelsHigh, 5 );
540
541	ps->AsicReg.RD_ModeControl = _ModeReadMappingMem;
542
543	if( _ASIC_IS_98001 == ps->sCaps.AsicID )
544		ps->CloseScanPath( ps );
545
546	IOReadScannerImageData( ps, buffer + _MEMTEST_SIZE, _MEMTEST_SIZE );
547
548	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
549		ps->CloseScanPath( ps );
550
551	/* check the result ! */
552	retval = _OK;
553
554	for( ul = 0; ul < _MEMTEST_SIZE; ul++ ) {
555		if( buffer[ul] != buffer[ul+_MEMTEST_SIZE] ) {
556			DBG( DBG_HIGH, "Error in memory test at pos %u (%u != %u)\n",
557				 ul, buffer[ul], buffer[ul+_MEMTEST_SIZE] );
558			retval = _E_NO_DEV;
559			break;
560		}
561	}
562
563	_KFREE(buffer);
564	return retval;
565}
566
567/** Put data to DATA port and trigger hardware through CONTROL port to read it.
568 */
569static void ioSPPWrite( pScanData ps, pUChar pBuffer, ULong size )
570{
571	DBG( DBG_IO , "Moving %u bytes to scanner, IODELAY = %u...\n",
572					size, ps->IO.delay );
573	switch( ps->IO.delay ) {
574
575		case 0:
576		    for (; size; size--, pBuffer++) {
577				_OUTB_DATA( ps, *pBuffer );
578				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
579				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
580        	}
581			break;
582
583		case 1:
584		case 2:
585		    for (; size; size--, pBuffer++) {
586				_OUTB_DATA( ps, *pBuffer );
587				_DO_UDELAY( 1 );
588				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
589				_DO_UDELAY( 1 );
590				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
591				_DO_UDELAY( 2 );
592        	}
593			break;
594
595		default:
596		    for (; size; size--, pBuffer++) {
597				_OUTB_DATA( ps, *pBuffer );
598				_DO_UDELAY( 1 );
599				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
600				_DO_UDELAY( 2 );
601				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
602				_DO_UDELAY( 3 );
603        	}
604			break;
605	}
606	DBG( DBG_IO , "... done.\n" );
607}
608
609/** set the scanner to "read" data mode
610 */
611static void ioEnterReadMode( pScanData ps )
612{
613	if( ps->IO.portMode != _PORT_SPP ) {
614
615		_DO_UDELAY( 1 );
616		IORegisterToScanner( ps, ps->RegEPPEnable );
617
618		if( _IS_ASIC98( ps->sCaps.AsicID ))
619			ps->IO.useEPPCmdMode = _TRUE;
620	}
621
622	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
623		ps->IO.bOldControlValue = _INB_CTRL( ps );
624
625	/* ask ASIC to enter read mode */
626	IORegisterToScanner( ps, ps->RegReadDataMode );
627}
628
629/************************ exported functions *********************************/
630
631/** here we do some init work
632 */
633_LOC int IOInitialize( pScanData ps )
634{
635	DBG( DBG_HIGH, "IOInitialize()\n" );
636
637	if( NULL == ps )
638		return _E_NULLPTR;
639
640	if( _IS_ASIC98(ps->sCaps.AsicID)) {
641
642		ps->OpenScanPath  = ioP98OpenScanPath;
643		ps->ReadWriteTest = ioP98ReadWriteTest;
644
645	} else if( _IS_ASIC96(ps->sCaps.AsicID)) {
646
647		ps->OpenScanPath = ioP96OpenScanPath;
648
649	} else {
650
651		DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" );
652		return _E_NOSUPP;
653	}
654
655	ps->CloseScanPath   = ioCloseScanPath;
656	ps->Device.ReadData = ioReadFunc[ps->IO.portMode].func;
657	DBG( DBG_HIGH, "* using readfunction >%s<\n",
658	                  ioReadFunc[ps->IO.portMode].name );
659	return _OK;
660}
661
662/** Write specific length buffer to scanner
663 * The scan path is already established
664 */
665_LOC void IOMoveDataToScanner( pScanData ps, pUChar pBuffer, ULong size )
666{
667#ifdef DEBUG
668	if( 0 == ps->IO.bOpenCount )
669		DBG( DBG_IO, "IOMoveDataToScanner - no connection!\n" );
670#endif
671
672	IORegisterToScanner( ps, ps->RegInitDataFifo );
673	IORegisterToScanner( ps, ps->RegWriteDataMode );
674
675	ioSPPWrite( ps, pBuffer, size );
676}
677
678/** Calling SITUATION: Scanner path is established.
679 * download a scanstate-table
680 */
681_LOC void IODownloadScanStates( pScanData ps )
682{
683	TimerDef timer;
684#ifdef DEBUG
685	if( 0 == ps->IO.bOpenCount )
686		DBG( DBG_IO, "IODownloadScanStates - no connection!\n" );
687#endif
688
689	IORegisterToScanner( ps, ps->RegScanStateControl );
690
691	ioSPPWrite( ps, ps->a_nbNewAdrPointer, _SCANSTATE_BYTES );
692
693	if( ps->Scan.fRefreshState ) {
694
695		IORegisterToScanner( ps, ps->RegRefreshScanState );
696
697		MiscStartTimer( &timer, (_SECOND/2));
698		do {
699
700			if (!( IOGetScanState( ps, _TRUE) & _SCANSTATE_STOP))
701				break;
702		}
703		while( !MiscCheckTimer(&timer));
704	}
705}
706
707/** Calling SITUATION: Scanner path is established.
708 * Write a data to asic
709 */
710_LOC void IODataToScanner( pScanData ps, Byte bValue )
711{
712	ULong deltime = 4;
713
714#ifdef DEBUG
715	if( 0 == ps->IO.bOpenCount )
716        DBG( DBG_IO, "IODataToScanner - no connection!\n" );
717#endif
718
719	if( ps->IO.delay < 2 )
720		deltime = 2;
721
722    /* output data */
723   	_OUTB_DATA( ps, bValue );
724	_DO_UDELAY( deltime );
725
726	/* notify asic there is data */
727    _OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
728	_DO_UDELAY( deltime );
729
730		/* end write cycle */
731   	_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
732	_DO_UDELAY( deltime-1 );
733}
734
735/** Calling SITUATION: Scanner path is established.
736 * Write a data to specific asic's register
737 */
738_LOC void IODataToRegister( pScanData ps, Byte bReg, Byte bData )
739{
740#ifdef DEBUG
741    if( 0 == ps->IO.bOpenCount )
742        DBG( DBG_IO, "IODataToRegister - no connection!\n" );
743#endif
744
745	/* specify register */
746    IORegisterToScanner( ps, bReg );
747
748	/* then write the content */
749	IODataToScanner( ps, bData );
750}
751
752/** Calling SITUATION: Scanner path is established.
753 * Read the content of specific asic's register
754 */
755_LOC Byte IODataFromRegister( pScanData ps, Byte bReg )
756{
757	IORegisterToScanner( ps, bReg );
758
759	if( 0 == ps->IO.delay )
760		return ioDataFromSPPFast( ps );
761	else if( 1 == ps->IO.delay )
762		return ioDataFromSPPMiddle( ps );
763	else if( 2 == ps->IO.delay )
764		return ioDataFromSPPSlow( ps );
765	else
766		return ioDataFromSPPSlowest( ps );
767}
768
769/** Calling SITUATION: Scanner path is established.
770 * Write a register to asic (used for a command without parameter)
771 */
772_LOC void IORegisterToScanner( pScanData ps, Byte bReg )
773{
774#ifdef DEBUG
775    if( 0 == ps->IO.bOpenCount )
776        DBG( DBG_IO, "IORegisterToScanner - no connection!\n" );
777#endif
778
779    /*
780     * write data to port
781     */
782	_OUTB_DATA( ps, bReg );
783
784    /*
785     * depending on the mode, generate the trigger signals
786     */
787    if( ps->IO.useEPPCmdMode ) {
788
789		_DO_UDELAY( 5 );
790
791		_OUTB_CTRL( ps, _CTRL_EPPSIGNAL_WRITE);	/* 0xc5 */
792		_DO_UDELAY( 5 );
793
794		_OUTB_CTRL( ps, _CTRL_EPPTRIG_REGWRITE);/* 0xcd */
795		_DO_UDELAY( 5 );
796
797		_OUTB_CTRL( ps, _CTRL_EPPSIGNAL_WRITE);	/* 0xc5 */
798		_DO_UDELAY( 5 );
799
800		_OUTB_CTRL( ps, _CTRL_END_REGWRITE);    /* 0xc4 */
801
802    } else {
803		if( ps->IO.delay < 2 ) {
804
805			_DO_UDELAY( 1 );
806			_OUTB_CTRL( ps, _CTRL_START_REGWRITE);
807			_DO_UDELAY( 1 );
808			_OUTB_CTRL( ps, _CTRL_END_REGWRITE);
809		} else {
810
811			_DO_UDELAY( 2 );
812			_OUTB_CTRL( ps, _CTRL_START_REGWRITE);
813			_DO_UDELAY( 2 );
814			_OUTB_CTRL( ps, _CTRL_END_REGWRITE);
815			_DO_UDELAY( 2 );
816		}
817    }
818}
819
820/** write data to the DAC - ASIC 98001/3 only
821 */
822_LOC void IODataRegisterToDAC( pScanData ps, Byte bReg, Byte bData )
823{
824    ULong i;
825
826	IODataToRegister( ps, ps->RegADCAddress, bReg );
827    IODataToRegister( ps, ps->RegADCData,    bData );
828    IODataToRegister( ps, ps->RegADCSerialOutStr, bData );
829
830    /* TEST: ORG was 1 ms for ASIC 98001 */
831    _DO_UDELAY( 12 );
832
833    for( i = 4; i; i-- ) {
834
835    	_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
836        _DO_UDELAY( 5 );
837    	_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
838        _DO_UDELAY( 12 );
839    }
840}
841
842/** Calling SITUATION: Scanner path was not established.
843 * Read the content of specific asics' register
844 */
845_LOC Byte IODataRegisterFromScanner( pScanData ps, Byte bReg )
846{
847    Byte bData;
848
849    ps->OpenScanPath( ps );
850    bData = IODataFromRegister( ps, bReg );
851    ps->CloseScanPath( ps );
852
853    return bData;
854}
855
856/** Calling SITUATION: Scanner path not established.
857 * Write a value of register to asic
858 */
859_LOC void IOCmdRegisterToScanner( pScanData ps, Byte bReg, Byte bData )
860{
861    ps->OpenScanPath( ps );
862    IODataToRegister( ps, bReg, bData );
863    ps->CloseScanPath( ps );
864}
865
866/** Calling SITUATION: Scanner path not established.
867 * Write a register to asic (used for a command without parameter)
868 */
869_LOC void IORegisterDirectToScanner( pScanData ps, Byte bReg )
870{
871    ps->OpenScanPath( ps );				/* establish the connection */
872    IORegisterToScanner( ps, bReg );	/* write register to asic	*/
873    ps->CloseScanPath( ps );			/* disconnect				*/
874}
875
876/** perform a SW reset of ASIC 98003 models
877 */
878_LOC void IOSoftwareReset( pScanData ps )
879{
880    if( _ASIC_IS_98003 != ps->sCaps.AsicID )
881        return;
882
883    ps->OpenScanPath( ps );
884
885    IODataToRegister( ps, ps->RegTestMode, _SW_TESTMODE );
886
887    ioSwitchToSPPMode( ps );
888
889    _OUTB_DATA( ps, _RESET1ST );
890    _DODELAY( 5 );
891
892    _OUTB_DATA( ps, _RESET2ND );
893    _DODELAY( 5 );
894
895    _OUTB_DATA( ps, _RESET3RD );
896    _DODELAY( 5 );
897
898    _OUTB_DATA( ps, _RESET4TH );
899    _DODELAY( 5 );
900
901    ioRestoreParallelMode( ps );
902
903    /* reset test mode register */
904    IODataToRegister( ps, ps->RegTestMode, 0 );
905    IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
906
907    ps->CloseScanPath( ps );
908}
909
910/** Read specific length data from scanner and the method depends on the
911 *  mode defined in registry.
912 */
913_LOC void IOReadScannerImageData( pScanData ps, pUChar pBuf, ULong size )
914{
915	if( _ASIC_IS_98003 != ps->sCaps.AsicID )
916		ps->OpenScanPath( ps);
917
918	if( _IS_ASIC98( ps->sCaps.AsicID))
919		IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );
920
921	/* enter read mode */
922	ioEnterReadMode( ps );
923
924	/* call corresponding read proc */
925	ps->Device.ReadData( ps, pBuf, size );
926
927	/* Clear EPP/ECP read mode by simply close scanner path and re-open it */
928	ps->CloseScanPath( ps );
929
930	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
931		ps->OpenScanPath( ps );
932}
933
934/* END PLUSTEK-PP_IO.C ......................................................*/
935