diff options
Diffstat (limited to 'backend/plustek-pp_io.c')
-rw-r--r-- | backend/plustek-pp_io.c | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/backend/plustek-pp_io.c b/backend/plustek-pp_io.c new file mode 100644 index 0000000..ba68599 --- /dev/null +++ b/backend/plustek-pp_io.c @@ -0,0 +1,999 @@ +/* @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 ......................................................*/ |