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 ......................................................*/
|