kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			1000 wiersze
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			1000 wiersze
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
| /* @file plustekpp-io.c
 | |
|  * @brief as the name says, here we have all the I/O
 | |
|  *        functions according to the parallel port hardware
 | |
|  *
 | |
|  * based on sources acquired from Plustek Inc.
 | |
|  * Copyright (C) 1998 Plustek Inc.
 | |
|  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
 | |
|  *
 | |
|  * History:
 | |
|  * - 0.37 - initial version
 | |
|  *        - added Kevins' suggestions
 | |
|  * - 0.38 - added Asic 98003 stuff and ioP98ReadWriteTest()
 | |
|  *        - added IODataRegisterToDAC()
 | |
|  *        - replaced function IOSPPWrite by IOMoveDataToScanner
 | |
|  *        - modified ioP98OpenScanPath again and reuse V0.36 stuff again
 | |
|  *        - added IO functions
 | |
|  * - 0.39 - added IO functions
 | |
|  *        - added f97003 stuff from A3I code
 | |
|  * - 0.40 - no changes
 | |
|  * - 0.41 - no changes
 | |
|  * - 0.42 - changed include names
 | |
|  * - 0.43 - no changes
 | |
|  * - 0.44 - fix format string issues, as Long types default to int32_t
 | |
|  *          now
 | |
|  * .
 | |
|  * <hr>
 | |
|  * This file is part of the SANE package.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of the
 | |
|  * License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 | |
|  * MA 02111-1307, USA.
 | |
|  *
 | |
|  * As a special exception, the authors of SANE give permission for
 | |
|  * additional uses of the libraries contained in this release of SANE.
 | |
|  *
 | |
|  * The exception is that, if you link a SANE library with other files
 | |
|  * to produce an executable, this does not by itself cause the
 | |
|  * resulting executable to be covered by the GNU General Public
 | |
|  * License.  Your use of that executable is in no way restricted on
 | |
|  * account of linking the SANE library code into it.
 | |
|  *
 | |
|  * This exception does not, however, invalidate any other reasons why
 | |
|  * the executable file might be covered by the GNU General Public
 | |
|  * License.
 | |
|  *
 | |
|  * If you submit changes to SANE to the maintainers to be included in
 | |
|  * a subsequent release, you agree by submitting the changes that
 | |
|  * those changes may be distributed with this exception intact.
 | |
|  *
 | |
|  * If you write modifications of your own for SANE, it is your choice
 | |
|  * whether to permit this exception to apply to your modifications.
 | |
|  * If you do not wish that, delete this exception notice.
 | |
|  * <hr>
 | |
|  */
 | |
| #include "plustek-pp_scan.h"
 | |
| 
 | |
| /*************************** some prototypes *********************************/
 | |
| 
 | |
| static Bool fnEPPRead  ( pScanData ps, pUChar pBuffer, ULong ulSize );
 | |
| static Bool fnSPPRead  ( pScanData ps, pUChar pBuffer, ULong ulSize );
 | |
| static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize );
 | |
| 
 | |
| typedef struct {
 | |
| 	pFnReadData func;
 | |
| 	char       *name;
 | |
| } ioReadFuncDef;
 | |
| 
 | |
| static ioReadFuncDef ioReadFunc[3] = {
 | |
| 	{ fnEPPRead,   "fnEPPRead"   },
 | |
| 	{ fnSPPRead,   "fnSPPRead"   },
 | |
| 	{ fnBiDirRead, "fnBiDirRead" }
 | |
| };
 | |
| 
 | |
| /*************************** some definitions ********************************/
 | |
| 
 | |
| #define _MEMTEST_SIZE   1280
 | |
| 
 | |
| /*************************** local functions *********************************/
 | |
| 
 | |
| /** we provide some functions to read data from SPP port according to
 | |
|  * the speed we have detected (ReadWriteTest!!)
 | |
|  */
 | |
| static Byte ioDataFromSPPFast( pScanData ps )
 | |
| {
 | |
| 	Byte bData, tmp;
 | |
| 
 | |
| 	/* notify asic we will read the high nibble data from status port */
 | |
| 	if( _FALSE == ps->f97003 ) {
 | |
| 		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
 | |
| 		_DO_UDELAY( 1 );
 | |
| 	}
 | |
| 
 | |
| 	/* read high nibble */
 | |
|     bData  = _INB_STATUS( ps );
 | |
| 	bData &= 0xf0;
 | |
| 
 | |
|     _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
 | |
| 	_DO_UDELAY( 1 );
 | |
| 
 | |
| 	/* read low nibble */
 | |
| 	tmp = _INB_STATUS( ps );
 | |
| 
 | |
| 	/* combine with low nibble */
 | |
|     bData |= (tmp >> 4);
 | |
| 
 | |
|     _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 	_DO_UDELAY( 1 );
 | |
| 
 | |
|     return bData;
 | |
| }
 | |
| 
 | |
| static Byte ioDataFromSPPMiddle( pScanData ps )
 | |
| {
 | |
| 	Byte bData, tmp;
 | |
| 
 | |
| 	/* notify asic we will read the high nibble data from status port */
 | |
| 	if( _FALSE == ps->f97003 ) {
 | |
| 		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
 | |
| 		_DO_UDELAY( 1 );
 | |
| 	}
 | |
| 
 | |
| 	/* read high nibble */
 | |
| 	_INB_STATUS( ps );
 | |
|     bData  = _INB_STATUS( ps );
 | |
| 	bData &= 0xf0;
 | |
| 
 | |
|     _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
 | |
| 	_DO_UDELAY( 1 );
 | |
| 
 | |
| 	/* read low nibble */
 | |
| 	_INB_STATUS( ps );
 | |
| 	tmp = _INB_STATUS( ps );
 | |
| 
 | |
| 	/* combine with low nibble */
 | |
|     bData |= (tmp >> 4);
 | |
| 
 | |
|     _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 	_DO_UDELAY( 1 );
 | |
| 
 | |
|     return bData;
 | |
| }
 | |
| 
 | |
| static UChar ioDataFromSPPSlow( pScanData ps )
 | |
| {
 | |
| 	Byte bData, tmp;
 | |
| 
 | |
| 	/* notify asic we will read the high nibble data from status port */
 | |
| 	if( _FALSE == ps->f97003 ) {
 | |
| 		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
 | |
| 		_DO_UDELAY( 2 );
 | |
| 	}
 | |
| 
 | |
| 	/* read high nibble */
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
|     bData  = _INB_STATUS( ps );
 | |
| 	bData &= 0xf0;
 | |
| 
 | |
|     _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
 | |
| 	_DO_UDELAY( 2 );
 | |
| 
 | |
| 	/* read low nibble */
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
| 	tmp = _INB_STATUS( ps );
 | |
| 
 | |
| 	/* combine with low nibble */
 | |
|     bData |= (tmp >> 4);
 | |
| 
 | |
|     _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 	_DO_UDELAY( 2 );
 | |
| 
 | |
|     return bData;
 | |
| }
 | |
| 
 | |
| static UChar ioDataFromSPPSlowest( pScanData ps )
 | |
| {
 | |
| 	Byte bData, tmp;
 | |
| 
 | |
| 	/* notify asic we will read the high nibble data from status port */
 | |
| 	if( _FALSE == ps->f97003 ) {
 | |
| 		_OUTB_CTRL( ps, ps->CtrlReadHighNibble );
 | |
| 		_DO_UDELAY( 3 );
 | |
| 	}
 | |
| 
 | |
| 	/* read high nibble */
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
|     bData  = _INB_STATUS( ps );
 | |
| 	bData &= 0xf0;
 | |
| 
 | |
|     _OUTB_CTRL( ps, ps->CtrlReadLowNibble );
 | |
| 	_DO_UDELAY( 3 );
 | |
| 
 | |
| 	/* read low nibble */
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
| 	_INB_STATUS( ps );
 | |
| 	tmp = _INB_STATUS( ps );
 | |
| 
 | |
| 	/* combine with low nibble */
 | |
|     bData |= (tmp >> 4);
 | |
| 
 | |
|     _OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 	_DO_UDELAY( 3 );
 | |
| 
 | |
|     return bData;
 | |
| }
 | |
| 
 | |
| /** Read data from STATUS port. We have to read twice and combine two nibble
 | |
|  *  data to one byte.
 | |
|  */
 | |
| static Bool fnSPPRead( pScanData ps, pUChar pBuffer, ULong ulSize )
 | |
| {
 | |
| 	switch( ps->IO.delay ) {
 | |
| 
 | |
| 		case 0:
 | |
| 			for (; ulSize; ulSize--, pBuffer++)
 | |
| 				*pBuffer = ioDataFromSPPFast( ps );
 | |
| 			break;
 | |
| 
 | |
| 		case 1:
 | |
| 			for (; ulSize; ulSize--, pBuffer++)
 | |
| 				*pBuffer = ioDataFromSPPMiddle( ps );
 | |
| 			break;
 | |
| 
 | |
| 		case 2:
 | |
| 			for (; ulSize; ulSize--, pBuffer++)
 | |
| 				*pBuffer = ioDataFromSPPSlow( ps );
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			for (; ulSize; ulSize--, pBuffer++)
 | |
| 				*pBuffer = ioDataFromSPPSlowest( ps );
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
|     return _TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /** Using buffered I/O to read data from EPP Data Port
 | |
|  */
 | |
| static Bool fnEPPRead( pScanData ps, pUChar pBuffer, ULong ulSize )
 | |
| {
 | |
| 	register ULong i;
 | |
| 
 | |
| 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
 | |
| 
 | |
| #ifndef __KERNEL__
 | |
| 		sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAIN );
 | |
| #else
 | |
| 		_OUTB_CTRL( ps, (_CTRL_GENSIGNAL + _CTRL_DIRECTION));
 | |
| 		_DO_UDELAY( 1 );
 | |
| #endif
 | |
| 		for( i = 0; i < ulSize; i++ )
 | |
| 			pBuffer[i] = _INB_EPPDATA( ps );
 | |
| 
 | |
| #ifndef __KERNEL__
 | |
| 		sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAOUT );
 | |
| #else
 | |
| 		_OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 		_DO_UDELAY( 1 );
 | |
| #endif
 | |
| 	} else {
 | |
| 
 | |
| 		for( i = 0; i < ulSize; i++ )
 | |
| 			pBuffer[i] = _INB_EPPDATA( ps );
 | |
| 	}
 | |
| 
 | |
| 	return _TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize )
 | |
| {
 | |
| 	UChar start, end;
 | |
| 
 | |
| 	start = _CTRL_START_BIDIREAD;
 | |
| 	end   = _CTRL_END_BIDIREAD;
 | |
| 
 | |
| #ifndef __KERNEL__
 | |
| 	sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAIN );
 | |
| 
 | |
| 	if( !sanei_pp_uses_directio()) {
 | |
| 		start &= ~_CTRL_DIRECTION;
 | |
| 		end   &= ~_CTRL_DIRECTION;
 | |
| 	}
 | |
| #else
 | |
| 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
 | |
| 		_OUTB_CTRL( ps, (_CTRL_GENSIGNAL + _CTRL_DIRECTION));
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	switch( ps->IO.delay ) {
 | |
| 
 | |
| 		case 0:
 | |
| 		    for( ; ulSize; ulSize--, pBuffer++ ) {
 | |
| 				_OUTB_CTRL( ps, start );
 | |
| 				*pBuffer = _INB_DATA( ps );
 | |
| 				_OUTB_CTRL( ps, end );
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case 1:
 | |
| 			_DO_UDELAY( 1 );
 | |
| 		    for(; ulSize; ulSize--, pBuffer++ ) {
 | |
| 				_OUTB_CTRL( ps, start );
 | |
| 				_DO_UDELAY( 1 );
 | |
| 
 | |
| 				*pBuffer = _INB_DATA( ps );
 | |
| 
 | |
| 				_OUTB_CTRL( ps, end );
 | |
| 				_DO_UDELAY( 1 );
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			_DO_UDELAY( 2 );
 | |
| 		    for(; ulSize; ulSize--, pBuffer++ ) {
 | |
| 				_OUTB_CTRL( ps, start );
 | |
| 				_DO_UDELAY( 2 );
 | |
| 
 | |
| 				*pBuffer = _INB_DATA( ps );
 | |
| 
 | |
| 				_OUTB_CTRL( ps, end );
 | |
| 				_DO_UDELAY( 2 );
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 	}
 | |
| 
 | |
| #ifndef __KERNEL__
 | |
| 	sanei_pp_set_datadir( ps->pardev, SANEI_PP_DATAOUT );
 | |
| #else
 | |
| 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
 | |
| 		_OUTB_CTRL( ps, _CTRL_GENSIGNAL );
 | |
| 	}
 | |
| #endif
 | |
| 	return _TRUE;
 | |
| }
 | |
| 
 | |
| /** as the name says, we switch to SPP mode
 | |
|  */
 | |
| static void ioSwitchToSPPMode( pScanData ps )
 | |
| {
 | |
| 	/* save the control and data port value
 | |
| 	 */
 | |
| 	ps->IO.bOldControlValue = _INB_CTRL( ps );
 | |
| 	ps->IO.bOldDataValue    = _INB_DATA( ps );
 | |
| 
 | |
| 	_OUTB_CTRL( ps, _CTRL_GENSIGNAL );	/* 0xc4 */
 | |
| 	_DO_UDELAY( 2 );
 | |
| }
 | |
| 
 | |
| /** restore the port settings
 | |
|  */
 | |
| static void ioRestoreParallelMode( pScanData ps )
 | |
| {
 | |
| 	_OUTB_CTRL( ps, ps->IO.bOldControlValue & 0x3f );
 | |
| 	_DO_UDELAY( 1 );
 | |
| 
 | |
| 	_OUTB_DATA( ps, ps->IO.bOldDataValue );
 | |
| 	_DO_UDELAY( 1 );
 | |
| }
 | |
| 
 | |
| /** try to connect to scanner (ASIC 9600x and 98001)
 | |
|  */
 | |
| _LOC void ioP98001EstablishScannerConnection( pScanData ps, ULong delTime )
 | |
| {
 | |
| 	_OUTB_DATA( ps, _ID_TO_PRINTER );
 | |
|     _DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID1ST );
 | |
|     _DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID2ND );
 | |
|     _DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID3RD );
 | |
|     _DO_UDELAY( delTime );
 | |
| 
 | |
|     _OUTB_DATA( ps, _ID4TH );
 | |
|     _DO_UDELAY( delTime );
 | |
| }
 | |
| 
 | |
| /** try to connect to scanner (ASIC 98003)
 | |
|  */
 | |
| static void ioP98003EstablishScannerConnection( pScanData ps, ULong delTime )
 | |
| {
 | |
| 	_OUTB_DATA( ps, _ID1ST );
 | |
| 	_DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID2ND );
 | |
| 	_DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID3RD );
 | |
| 	_DO_UDELAY( delTime );
 | |
| 
 | |
| 	_OUTB_DATA( ps, _ID4TH );
 | |
| 	_DO_UDELAY( delTime );
 | |
| }
 | |
| 
 | |
| /** switch the printer interface to scanner
 | |
|  */
 | |
| static Bool ioP96OpenScanPath( pScanData ps )
 | |
| {
 | |
| 	if( 0 == ps->IO.bOpenCount ) {
 | |
| 
 | |
| 		/* not established */
 | |
| 		ioSwitchToSPPMode( ps );
 | |
| 
 | |
| 		/* Scanner command sequence to open scanner path */
 | |
| 		ioP98001EstablishScannerConnection( ps, 5 );
 | |
| 	}
 | |
| #ifdef DEBUG
 | |
| 	else
 | |
| 		DBG( DBG_IO, "!!!! Path already open (%u)!!!!\n", ps->IO.bOpenCount );
 | |
| #endif
 | |
| 
 | |
| 	ps->IO.bOpenCount++;			/* increment the opened count */
 | |
| 
 | |
| /*
 | |
|  * CHECK to we really need that !!
 | |
|  */
 | |
| 	ps->IO.useEPPCmdMode = _FALSE;
 | |
| 	return _TRUE;
 | |
| }
 | |
| 
 | |
| /** try to connect to scanner
 | |
|  */
 | |
| static Bool ioP98OpenScanPath( pScanData ps )
 | |
| {
 | |
|     Byte  tmp;
 | |
|     ULong dw;
 | |
| 	ULong dwTime = 1;
 | |
| 
 | |
| 	if( 0 == ps->IO.bOpenCount ) {
 | |
| 
 | |
| 		/* not established */
 | |
| 		ioSwitchToSPPMode( ps );
 | |
| 
 | |
| 		for( dw = 10; dw; dw-- ) {
 | |
| 
 | |
| 			/*
 | |
| 			 * this seems to be necessary...
 | |
| 			 */
 | |
|  			if( _ASIC_IS_98001 == ps->sCaps.AsicID ) {
 | |
| 				ioP98001EstablishScannerConnection( ps, dw );
 | |
| #if 0
 | |
| 				ioP98001EstablishScannerConnection( ps, dw );
 | |
| 				ioP98001EstablishScannerConnection( ps, dw );
 | |
| #endif
 | |
| 			} else {
 | |
| 				ioP98003EstablishScannerConnection( ps, dw );
 | |
| 			}
 | |
| 
 | |
| 			_INB_STATUS( ps );
 | |
| 			tmp = _INB_STATUS( ps );
 | |
| 
 | |
| 			if( 0x50 == ( tmp & 0xf0 )) {
 | |
| 
 | |
| 				ps->IO.bOpenCount = 1;
 | |
| 
 | |
| 				if( ps->sCaps.AsicID == IODataFromRegister(ps, ps->RegAsicID)) {
 | |
| 					return _TRUE;
 | |
| 				}
 | |
| 				ps->IO.bOpenCount = 0;
 | |
| 			}
 | |
| 
 | |
| 			dwTime++;
 | |
| 		}
 | |
| 		DBG( DBG_IO, "ioP98OpenScanPath() failed!\n" );
 | |
| 		return _FALSE;
 | |
| 	}
 | |
| #ifdef DEBUG
 | |
| 	else
 | |
| 		DBG( DBG_IO, "!!!! Path already open (%u)!!!!\n", ps->IO.bOpenCount );
 | |
| #endif
 | |
| 
 | |
| 	ps->IO.bOpenCount++;			/* increment the opened count */
 | |
| 	return _TRUE;
 | |
| }
 | |
| 
 | |
| /** Switch back to printer mode.
 | |
|  * Restore the printer control/data port value.
 | |
|  */
 | |
| static void ioCloseScanPath( pScanData ps )
 | |
| {
 | |
| 	if( ps->IO.bOpenCount && !(--ps->IO.bOpenCount)) {
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 		ps->IO.bOpenCount = 1;
 | |
| #endif
 | |
| 		IORegisterToScanner( ps, 0xff );
 | |
| 
 | |
| 		/*
 | |
| 		 * back to pass-through printer mode
 | |
| 		 */
 | |
| 		IORegisterToScanner( ps, ps->RegSwitchBus );
 | |
| #ifdef DEBUG
 | |
|         ps->IO.bOpenCount = 0;
 | |
| #endif
 | |
| 		ps->IO.useEPPCmdMode = _FALSE;
 | |
| 
 | |
| 		ioRestoreParallelMode( ps );
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /** check the memory to see that the data-transfers will work.
 | |
|  * (ASIC 9800x only)
 | |
|  */
 | |
| static int ioP98ReadWriteTest( pScanData ps )
 | |
| {
 | |
| 	UChar  tmp;
 | |
| 	ULong  ul;
 | |
| 	pUChar buffer;
 | |
| 	int	   retval;
 | |
| 
 | |
| 	DBG( DBG_LOW, "ioP98ReadWriteTest()\n" );
 | |
| 
 | |
| 	/* _MEMTEST_SIZE: Read, _MEMTEST_SIZE:Write */
 | |
| 	buffer = _KALLOC( sizeof(UChar) * _MEMTEST_SIZE*2, GFP_KERNEL );
 | |
| 	if( NULL == buffer )
 | |
| 		return _E_ALLOC;
 | |
| 
 | |
| 	/* prepare content */
 | |
| 	for( ul = 0; ul < _MEMTEST_SIZE; ul++ )
 | |
| 	    buffer[ul] = (UChar)ul;
 | |
| 
 | |
| 	ps->OpenScanPath(ps);
 | |
| 
 | |
| 	/* avoid switching to Lamp0, when previously scanned in transp./neg mode */
 | |
| 	tmp = ps->bLastLampStatus + _SCAN_BYTEMODE;
 | |
| 	IODataToRegister( ps, ps->RegScanControl, tmp );
 | |
| 
 | |
| 	IODataToRegister( ps, ps->RegModelControl, (_LED_ACTIVITY | _LED_CONTROL));
 | |
| 
 | |
| 	IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
 | |
| 	IODataToRegister( ps, ps->RegMemoryLow,  0 );
 | |
| 	IODataToRegister( ps, ps->RegMemoryHigh, 0 );
 | |
| 
 | |
| 	/* fill to buffer */
 | |
| 	IOMoveDataToScanner( ps, buffer, _MEMTEST_SIZE );
 | |
| 
 | |
| 	IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
 | |
| 	IODataToRegister( ps, ps->RegMemoryLow,  0 );
 | |
| 	IODataToRegister( ps, ps->RegMemoryHigh, 0 );
 | |
| 	IODataToRegister( ps, ps->RegWidthPixelsLow,  0 );
 | |
| 	IODataToRegister( ps, ps->RegWidthPixelsHigh, 5 );
 | |
| 
 | |
| 	ps->AsicReg.RD_ModeControl = _ModeReadMappingMem;
 | |
| 
 | |
| 	if( _ASIC_IS_98001 == ps->sCaps.AsicID )
 | |
| 		ps->CloseScanPath( ps );
 | |
| 
 | |
| 	IOReadScannerImageData( ps, buffer + _MEMTEST_SIZE, _MEMTEST_SIZE );
 | |
| 
 | |
| 	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
 | |
| 		ps->CloseScanPath( ps );
 | |
| 
 | |
| 	/* check the result ! */
 | |
| 	retval = _OK;
 | |
| 
 | |
| 	for( ul = 0; ul < _MEMTEST_SIZE; ul++ ) {
 | |
| 		if( buffer[ul] != buffer[ul+_MEMTEST_SIZE] ) {
 | |
| 			DBG( DBG_HIGH, "Error in memory test at pos %u (%u != %u)\n",
 | |
| 				 ul, buffer[ul], buffer[ul+_MEMTEST_SIZE] );
 | |
| 			retval = _E_NO_DEV;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	_KFREE(buffer);
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /** Put data to DATA port and trigger hardware through CONTROL port to read it.
 | |
|  */
 | |
| static void ioSPPWrite( pScanData ps, pUChar pBuffer, ULong size )
 | |
| {
 | |
| 	DBG( DBG_IO , "Moving %u bytes to scanner, IODELAY = %u...\n",
 | |
| 					size, ps->IO.delay );
 | |
| 	switch( ps->IO.delay ) {
 | |
| 
 | |
| 		case 0:
 | |
| 		    for (; size; size--, pBuffer++) {
 | |
| 				_OUTB_DATA( ps, *pBuffer );
 | |
| 				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
 | |
| 				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
 | |
|         	}
 | |
| 			break;
 | |
| 
 | |
| 		case 1:
 | |
| 		case 2:
 | |
| 		    for (; size; size--, pBuffer++) {
 | |
| 				_OUTB_DATA( ps, *pBuffer );
 | |
| 				_DO_UDELAY( 1 );
 | |
| 				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
 | |
| 				_DO_UDELAY( 1 );
 | |
| 				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
 | |
| 				_DO_UDELAY( 2 );
 | |
|         	}
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 		    for (; size; size--, pBuffer++) {
 | |
| 				_OUTB_DATA( ps, *pBuffer );
 | |
| 				_DO_UDELAY( 1 );
 | |
| 				_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
 | |
| 				_DO_UDELAY( 2 );
 | |
| 				_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
 | |
| 				_DO_UDELAY( 3 );
 | |
|         	}
 | |
| 			break;
 | |
| 	}
 | |
| 	DBG( DBG_IO , "... done.\n" );
 | |
| }
 | |
| 
 | |
| /** set the scanner to "read" data mode
 | |
|  */
 | |
| static void ioEnterReadMode( pScanData ps )
 | |
| {
 | |
| 	if( ps->IO.portMode != _PORT_SPP ) {
 | |
| 
 | |
| 		_DO_UDELAY( 1 );
 | |
| 		IORegisterToScanner( ps, ps->RegEPPEnable );
 | |
| 
 | |
| 		if( _IS_ASIC98( ps->sCaps.AsicID ))
 | |
| 			ps->IO.useEPPCmdMode = _TRUE;
 | |
| 	}
 | |
| 
 | |
| 	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
 | |
| 		ps->IO.bOldControlValue = _INB_CTRL( ps );
 | |
| 
 | |
| 	/* ask ASIC to enter read mode */
 | |
| 	IORegisterToScanner( ps, ps->RegReadDataMode );
 | |
| }
 | |
| 
 | |
| /************************ exported functions *********************************/
 | |
| 
 | |
| /** here we do some init work
 | |
|  */
 | |
| _LOC int IOInitialize( pScanData ps )
 | |
| {
 | |
| 	DBG( DBG_HIGH, "IOInitialize()\n" );
 | |
| 
 | |
| 	if( NULL == ps )
 | |
| 		return _E_NULLPTR;
 | |
| 
 | |
| 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
 | |
| 
 | |
| 		ps->OpenScanPath  = ioP98OpenScanPath;
 | |
| 		ps->ReadWriteTest = ioP98ReadWriteTest;
 | |
| 
 | |
| 	} else if( _IS_ASIC96(ps->sCaps.AsicID)) {
 | |
| 
 | |
| 		ps->OpenScanPath = ioP96OpenScanPath;
 | |
| 
 | |
| 	} else {
 | |
| 
 | |
| 		DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" );
 | |
| 		return _E_NOSUPP;
 | |
| 	}
 | |
| 
 | |
| 	ps->CloseScanPath   = ioCloseScanPath;
 | |
| 	ps->Device.ReadData = ioReadFunc[ps->IO.portMode].func;
 | |
| 	DBG( DBG_HIGH, "* using readfunction >%s<\n",
 | |
| 	                  ioReadFunc[ps->IO.portMode].name );
 | |
| 	return _OK;
 | |
| }
 | |
| 
 | |
| /** Write specific length buffer to scanner
 | |
|  * The scan path is already established
 | |
|  */
 | |
| _LOC void IOMoveDataToScanner( pScanData ps, pUChar pBuffer, ULong size )
 | |
| {
 | |
| #ifdef DEBUG
 | |
| 	if( 0 == ps->IO.bOpenCount )
 | |
| 		DBG( DBG_IO, "IOMoveDataToScanner - no connection!\n" );
 | |
| #endif
 | |
| 
 | |
| 	IORegisterToScanner( ps, ps->RegInitDataFifo );
 | |
| 	IORegisterToScanner( ps, ps->RegWriteDataMode );
 | |
| 
 | |
| 	ioSPPWrite( ps, pBuffer, size );
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path is established.
 | |
|  * download a scanstate-table
 | |
|  */
 | |
| _LOC void IODownloadScanStates( pScanData ps )
 | |
| {
 | |
| 	TimerDef timer;
 | |
| #ifdef DEBUG
 | |
| 	if( 0 == ps->IO.bOpenCount )
 | |
| 		DBG( DBG_IO, "IODownloadScanStates - no connection!\n" );
 | |
| #endif
 | |
| 
 | |
| 	IORegisterToScanner( ps, ps->RegScanStateControl );
 | |
| 
 | |
| 	ioSPPWrite( ps, ps->a_nbNewAdrPointer, _SCANSTATE_BYTES );
 | |
| 
 | |
| 	if( ps->Scan.fRefreshState ) {
 | |
| 
 | |
| 		IORegisterToScanner( ps, ps->RegRefreshScanState );
 | |
| 
 | |
| 		MiscStartTimer( &timer, (_SECOND/2));
 | |
| 		do {
 | |
| 
 | |
| 			if (!( IOGetScanState( ps, _TRUE) & _SCANSTATE_STOP))
 | |
| 				break;
 | |
| 		}
 | |
| 		while( !MiscCheckTimer(&timer));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path is established.
 | |
|  * Write a data to asic
 | |
|  */
 | |
| _LOC void IODataToScanner( pScanData ps, Byte bValue )
 | |
| {
 | |
| 	ULong deltime = 4;
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 	if( 0 == ps->IO.bOpenCount )
 | |
|         DBG( DBG_IO, "IODataToScanner - no connection!\n" );
 | |
| #endif
 | |
| 
 | |
| 	if( ps->IO.delay < 2 )
 | |
| 		deltime = 2;
 | |
| 
 | |
|     /* output data */
 | |
|    	_OUTB_DATA( ps, bValue );
 | |
| 	_DO_UDELAY( deltime );
 | |
| 
 | |
| 	/* notify asic there is data */
 | |
|     _OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
 | |
| 	_DO_UDELAY( deltime );
 | |
| 
 | |
| 		/* end write cycle */
 | |
|    	_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
 | |
| 	_DO_UDELAY( deltime-1 );
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path is established.
 | |
|  * Write a data to specific asic's register
 | |
|  */
 | |
| _LOC void IODataToRegister( pScanData ps, Byte bReg, Byte bData )
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     if( 0 == ps->IO.bOpenCount )
 | |
|         DBG( DBG_IO, "IODataToRegister - no connection!\n" );
 | |
| #endif
 | |
| 
 | |
| 	/* specify register */
 | |
|     IORegisterToScanner( ps, bReg );
 | |
| 
 | |
| 	/* then write the content */
 | |
| 	IODataToScanner( ps, bData );
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path is established.
 | |
|  * Read the content of specific asic's register
 | |
|  */
 | |
| _LOC Byte IODataFromRegister( pScanData ps, Byte bReg )
 | |
| {
 | |
| 	IORegisterToScanner( ps, bReg );
 | |
| 
 | |
| 	if( 0 == ps->IO.delay )
 | |
| 		return ioDataFromSPPFast( ps );
 | |
| 	else if( 1 == ps->IO.delay )
 | |
| 		return ioDataFromSPPMiddle( ps );
 | |
| 	else if( 2 == ps->IO.delay )
 | |
| 		return ioDataFromSPPSlow( ps );
 | |
| 	else
 | |
| 		return ioDataFromSPPSlowest( ps );
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path is established.
 | |
|  * Write a register to asic (used for a command without parameter)
 | |
|  */
 | |
| _LOC void IORegisterToScanner( pScanData ps, Byte bReg )
 | |
| {
 | |
| #ifdef DEBUG
 | |
|     if( 0 == ps->IO.bOpenCount )
 | |
|         DBG( DBG_IO, "IORegisterToScanner - no connection!\n" );
 | |
| #endif
 | |
| 
 | |
|     /*
 | |
|      * write data to port
 | |
|      */
 | |
| 	_OUTB_DATA( ps, bReg );
 | |
| 
 | |
|     /*
 | |
|      * depending on the mode, generate the trigger signals
 | |
|      */
 | |
|     if( ps->IO.useEPPCmdMode ) {
 | |
| 
 | |
| 		_DO_UDELAY( 5 );
 | |
| 
 | |
| 		_OUTB_CTRL( ps, _CTRL_EPPSIGNAL_WRITE);	/* 0xc5 */
 | |
| 		_DO_UDELAY( 5 );
 | |
| 
 | |
| 		_OUTB_CTRL( ps, _CTRL_EPPTRIG_REGWRITE);/* 0xcd */
 | |
| 		_DO_UDELAY( 5 );
 | |
| 
 | |
| 		_OUTB_CTRL( ps, _CTRL_EPPSIGNAL_WRITE);	/* 0xc5 */
 | |
| 		_DO_UDELAY( 5 );
 | |
| 
 | |
| 		_OUTB_CTRL( ps, _CTRL_END_REGWRITE);    /* 0xc4 */
 | |
| 
 | |
|     } else {
 | |
| 		if( ps->IO.delay < 2 ) {
 | |
| 
 | |
| 			_DO_UDELAY( 1 );
 | |
| 			_OUTB_CTRL( ps, _CTRL_START_REGWRITE);
 | |
| 			_DO_UDELAY( 1 );
 | |
| 			_OUTB_CTRL( ps, _CTRL_END_REGWRITE);
 | |
| 		} else {
 | |
| 
 | |
| 			_DO_UDELAY( 2 );
 | |
| 			_OUTB_CTRL( ps, _CTRL_START_REGWRITE);
 | |
| 			_DO_UDELAY( 2 );
 | |
| 			_OUTB_CTRL( ps, _CTRL_END_REGWRITE);
 | |
| 			_DO_UDELAY( 2 );
 | |
| 		}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /** write data to the DAC - ASIC 98001/3 only
 | |
|  */
 | |
| _LOC void IODataRegisterToDAC( pScanData ps, Byte bReg, Byte bData )
 | |
| {
 | |
|     ULong i;
 | |
| 
 | |
| 	IODataToRegister( ps, ps->RegADCAddress, bReg );
 | |
|     IODataToRegister( ps, ps->RegADCData,    bData );
 | |
|     IODataToRegister( ps, ps->RegADCSerialOutStr, bData );
 | |
| 
 | |
|     /* TEST: ORG was 1 ms for ASIC 98001 */
 | |
|     _DO_UDELAY( 12 );
 | |
| 
 | |
|     for( i = 4; i; i-- ) {
 | |
| 
 | |
|     	_OUTB_CTRL( ps, _CTRL_START_DATAWRITE );
 | |
|         _DO_UDELAY( 5 );
 | |
|     	_OUTB_CTRL( ps, _CTRL_END_DATAWRITE );
 | |
|         _DO_UDELAY( 12 );
 | |
|     }
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path was not established.
 | |
|  * Read the content of specific asics' register
 | |
|  */
 | |
| _LOC Byte IODataRegisterFromScanner( pScanData ps, Byte bReg )
 | |
| {
 | |
|     Byte bData;
 | |
| 
 | |
|     ps->OpenScanPath( ps );
 | |
|     bData = IODataFromRegister( ps, bReg );
 | |
|     ps->CloseScanPath( ps );
 | |
| 
 | |
|     return bData;
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path not established.
 | |
|  * Write a value of register to asic
 | |
|  */
 | |
| _LOC void IOCmdRegisterToScanner( pScanData ps, Byte bReg, Byte bData )
 | |
| {
 | |
|     ps->OpenScanPath( ps );
 | |
|     IODataToRegister( ps, bReg, bData );
 | |
|     ps->CloseScanPath( ps );
 | |
| }
 | |
| 
 | |
| /** Calling SITUATION: Scanner path not established.
 | |
|  * Write a register to asic (used for a command without parameter)
 | |
|  */
 | |
| _LOC void IORegisterDirectToScanner( pScanData ps, Byte bReg )
 | |
| {
 | |
|     ps->OpenScanPath( ps );				/* establish the connection */
 | |
|     IORegisterToScanner( ps, bReg );	/* write register to asic	*/
 | |
|     ps->CloseScanPath( ps );			/* disconnect				*/
 | |
| }
 | |
| 
 | |
| /** perform a SW reset of ASIC 98003 models
 | |
|  */
 | |
| _LOC void IOSoftwareReset( pScanData ps )
 | |
| {
 | |
|     if( _ASIC_IS_98003 != ps->sCaps.AsicID )
 | |
|         return;
 | |
| 
 | |
|     ps->OpenScanPath( ps );
 | |
| 
 | |
|     IODataToRegister( ps, ps->RegTestMode, _SW_TESTMODE );
 | |
| 
 | |
|     ioSwitchToSPPMode( ps );
 | |
| 
 | |
|     _OUTB_DATA( ps, _RESET1ST );
 | |
|     _DODELAY( 5 );
 | |
| 
 | |
|     _OUTB_DATA( ps, _RESET2ND );
 | |
|     _DODELAY( 5 );
 | |
| 
 | |
|     _OUTB_DATA( ps, _RESET3RD );
 | |
|     _DODELAY( 5 );
 | |
| 
 | |
|     _OUTB_DATA( ps, _RESET4TH );
 | |
|     _DODELAY( 5 );
 | |
| 
 | |
|     ioRestoreParallelMode( ps );
 | |
| 
 | |
|     /* reset test mode register */
 | |
|     IODataToRegister( ps, ps->RegTestMode, 0 );
 | |
|     IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
 | |
| 
 | |
|     ps->CloseScanPath( ps );
 | |
| }
 | |
| 
 | |
| /** Read specific length data from scanner and the method depends on the
 | |
|  *  mode defined in registry.
 | |
|  */
 | |
| _LOC void IOReadScannerImageData( pScanData ps, pUChar pBuf, ULong size )
 | |
| {
 | |
| 	if( _ASIC_IS_98003 != ps->sCaps.AsicID )
 | |
| 		ps->OpenScanPath( ps);
 | |
| 
 | |
| 	if( _IS_ASIC98( ps->sCaps.AsicID))
 | |
| 		IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );
 | |
| 
 | |
| 	/* enter read mode */
 | |
| 	ioEnterReadMode( ps );
 | |
| 
 | |
| 	/* call corresponding read proc */
 | |
| 	ps->Device.ReadData( ps, pBuf, size );
 | |
| 
 | |
| 	/* Clear EPP/ECP read mode by simply close scanner path and re-open it */
 | |
| 	ps->CloseScanPath( ps );
 | |
| 
 | |
| 	if( _ASIC_IS_98003 == ps->sCaps.AsicID )
 | |
| 		ps->OpenScanPath( ps );
 | |
| }
 | |
| 
 | |
| #ifdef __KERNEL__
 | |
| 
 | |
| /** the wrapper functions to support delayed and non-delayed I/O
 | |
|  */
 | |
| _LOC void IOOut( Byte data, UShort port )
 | |
| {
 | |
| 	DBG( DBG_IOF, "outb(0x%04x, 0x%02x)\n", port, data );
 | |
| 	outb( data, port );
 | |
| }
 | |
| 
 | |
| _LOC void IOOutDelayed( Byte data, UShort port )
 | |
| {
 | |
| 	DBG( DBG_IOF, "outb_p(0x%04x, 0x%02x)\n", port, data );
 | |
| 	outb_p( data, port );
 | |
| }
 | |
| 
 | |
| _LOC Byte IOIn( UShort port )
 | |
| {
 | |
| #ifdef DEBUG
 | |
| 	Byte data = inb( port );
 | |
| 
 | |
| 	DBG( DBG_IOF, "inb(0x%04x) = 0x%02x\n", port, data );
 | |
| 	return data;
 | |
| #else
 | |
| 	return inb( port );
 | |
| #endif
 | |
| }
 | |
| 
 | |
| _LOC Byte IOInDelayed( UShort port )
 | |
| {
 | |
| #ifdef DEBUG
 | |
| 	Byte data = inb_p( port );
 | |
| 
 | |
| 	DBG( DBG_IOF, "inb_p(0x%04x) = 0x%02x\n", port, data );
 | |
| 	return data;
 | |
| #else
 | |
| 	return inb_p( port );
 | |
| #endif
 | |
| }
 | |
| #endif /* guard __KERNEL__ */
 | |
| 
 | |
| /* END PLUSTEK-PP_IO.C ......................................................*/
 |