kopia lustrzana https://gitlab.com/sane-project/backends
524 wiersze
14 KiB
C
524 wiersze
14 KiB
C
/* @file plustek-pp_detect.c
|
|
* @brief automatic scanner detection
|
|
*
|
|
* based on sources acquired from Plustek Inc.
|
|
* Copyright (C) 1998 Plustek Inc.
|
|
* Copyright (C) 2000-2006 Gerhard Jaeger <gerhard@gjaeger.de>
|
|
* also based on the work done by Rick Bronson
|
|
*
|
|
* History:
|
|
* - 0.30 - initial version
|
|
* - 0.31 - no changes
|
|
* - 0.32 - no changes
|
|
* - 0.33 - added portmode check
|
|
* - 0.34 - no changes
|
|
* - 0.35 - no changes
|
|
* - 0.36 - added some debug messages
|
|
* - replace the old _OUTB/_INB macros
|
|
* - 0.37 - cosmetic changes
|
|
* - added speed-test for the parallel-port
|
|
* - 0.38 - added P12 stuff - replaced detectP9636 by detectAsic9800x
|
|
* - added detectResetPort() function
|
|
* - 0.39 - fixed problem in ASIC9800x detection
|
|
* - 0.40 - no changes
|
|
* - 0.41 - no changes
|
|
* - 0.42 - changed include names
|
|
* - 0.43 - cleanup
|
|
* .
|
|
* <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"
|
|
|
|
/************************** local definitions ********************************/
|
|
|
|
/*************************** local functions *********************************/
|
|
|
|
/** as the name says...
|
|
*/
|
|
static void detectResetPort( pScanData ps )
|
|
{
|
|
UChar control;
|
|
|
|
DBG( DBG_HIGH, "ResetPort()\n" );
|
|
|
|
control = _INB_CTRL( ps );
|
|
_DO_UDELAY( 2 );
|
|
|
|
_OUTB_CTRL( ps, _CTRL_RESERVED ); /* reset, 0xc0 */
|
|
_DO_UDELAY( 2 );
|
|
|
|
_OUTB_CTRL( ps, control ); /* and restore... */
|
|
_DO_UDELAY( 2 );
|
|
}
|
|
|
|
/** Check: will the status port changed between printer/scanner path changed?
|
|
* Write out data and read in to compare
|
|
*/
|
|
static int detectScannerConnection( pScanData ps )
|
|
{
|
|
UChar data, control, status;
|
|
int retval = _E_NO_CONN;
|
|
|
|
#ifdef __KERNEL__
|
|
DBG( DBG_LOW, "Dataport = 0x%04x\n", ps->IO.pbSppDataPort );
|
|
DBG( DBG_LOW, "Ctrlport = 0x%04x\n", ps->IO.pbControlPort );
|
|
#endif
|
|
|
|
detectResetPort( ps );
|
|
|
|
/*
|
|
* as we're called during InitPorts, we can be sure
|
|
* to operate in EPP-mode (hopefuly ;-)
|
|
*/
|
|
control = _INB_CTRL( ps );
|
|
|
|
/*
|
|
* go ahead and do some checks
|
|
*/
|
|
_OUTB_CTRL( ps, _CTRL_GENSIGNAL );
|
|
_DO_UDELAY( 5 );
|
|
|
|
_OUTB_DATA( ps, 0x55 );
|
|
_DO_UDELAY( 5 );
|
|
|
|
data = _INB_DATA( ps );
|
|
|
|
if (0x55 == data) {
|
|
|
|
DBG( DBG_HIGH, "Test 0x55\n" );
|
|
|
|
_OUTB_DATA( ps, 0xAA );
|
|
_DO_UDELAY( 5 );
|
|
|
|
data = _INB_DATA( ps );
|
|
|
|
if (0xAA == data) {
|
|
|
|
DBG( DBG_HIGH, "Test 0xAA\n" );
|
|
|
|
_OUTB_DATA( ps, 0x0 );
|
|
_DO_UDELAY( 5 );
|
|
|
|
data = _INB_STATUS( ps );
|
|
|
|
ps->OpenScanPath( ps );
|
|
|
|
_OUTB_DATA( ps, 0x0 );
|
|
_DO_UDELAY( 5 );
|
|
|
|
status = _INB_STATUS( ps );
|
|
|
|
ps->CloseScanPath( ps );
|
|
|
|
/*
|
|
* so we're done 'til now...
|
|
*/
|
|
DBG( DBG_HIGH, "Compare data=0x%x and status=0x%x, port=0x%x\n",
|
|
data, status, ps->IO.portBase );
|
|
|
|
if( data != status ) {
|
|
|
|
_ASSERT( ps->ReadWriteTest );
|
|
|
|
/*
|
|
* here we try to detect the operation speed of our parallel
|
|
* port if we have tested all the stuff and had no success,
|
|
* retval will contain the error-code
|
|
*/
|
|
for( ps->IO.delay = 0; ps->IO.delay < 5; ps->IO.delay++ ) {
|
|
|
|
retval = ps->ReadWriteTest( ps );
|
|
|
|
/* break on OK or when the ASIC detection fails */
|
|
if((_OK == retval) || (_E_NO_ASIC == retval))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* work on the result */
|
|
if ( _OK == retval ) {
|
|
#ifdef __KERNEL__
|
|
ps->sCaps.wIOBase = ps->IO.pbSppDataPort;
|
|
#else
|
|
ps->sCaps.wIOBase = ps->pardev;
|
|
#endif
|
|
ps->PutToIdleMode( ps );
|
|
|
|
} else {
|
|
ps->sCaps.wIOBase = _NO_BASE;
|
|
}
|
|
|
|
/*
|
|
* restore control port value
|
|
*/
|
|
_OUTB_CTRL( ps, control );
|
|
_DO_UDELAY( 5 );
|
|
|
|
DBG( DBG_HIGH, "detectScannerConnection() returns %i.\n", retval );
|
|
|
|
return retval;
|
|
}
|
|
|
|
/** we need some memory...
|
|
*/
|
|
static int detectSetupBuffers( pScanData ps )
|
|
{
|
|
DBG( DBG_LOW, "*** setupBuffers ***\n" );
|
|
|
|
/* bad news ?
|
|
*/
|
|
if ( 0 == ps->TotalBufferRequire ) {
|
|
|
|
#ifdef __KERNEL__
|
|
_PRINT(
|
|
#else
|
|
DBG( DBG_HIGH,
|
|
#endif
|
|
"pt_drv: asic 0x%x probably not supported\n", ps->sCaps.AsicID);
|
|
|
|
return _E_ALLOC; /* Out of memory */
|
|
|
|
} else {
|
|
|
|
/*
|
|
* allocate and clear
|
|
*/
|
|
DBG(DBG_LOW,"Driverbuf(%lu bytes) needed !\n", ps->TotalBufferRequire);
|
|
ps->driverbuf = (pUChar)_VMALLOC(ps->TotalBufferRequire);
|
|
|
|
if ( NULL == ps->driverbuf ) {
|
|
|
|
#ifdef __KERNEL__
|
|
_PRINT(
|
|
#else
|
|
DBG( DBG_HIGH,
|
|
#endif
|
|
"pt_drv: Not enough kernel memory %ld\n",
|
|
ps->TotalBufferRequire);
|
|
return _E_ALLOC; /* Out of memory */
|
|
}
|
|
|
|
memset( ps->driverbuf, 0, ps->TotalBufferRequire );
|
|
}
|
|
|
|
ps->pPrescan16 = ps->driverbuf;
|
|
ps->pPrescan8 = ps->pPrescan16 + ps->BufferFor1stColor;
|
|
ps->pScanBuffer1 = ps->pPrescan8 + ps->BufferFor2ndColor;
|
|
|
|
/* CHECK: Should we adjust that !!!
|
|
*/
|
|
ps->pEndBufR = ps->pPrescan8;
|
|
ps->pEndBufG = ps->pScanBuffer1;
|
|
ps->pColorRunTable = ps->pScanBuffer1 + ps->BufferForDataRead1;
|
|
|
|
DBG( DBG_LOW, "pColorRunTab = 0x%0lx - 0x%0lx\n",
|
|
(ULong)ps->pColorRunTable,
|
|
(ULong)((pUChar)ps->driverbuf + ps->TotalBufferRequire));
|
|
|
|
if ( _ASIC_IS_98001 == ps->sCaps.AsicID ) {
|
|
|
|
DBG( DBG_LOW, "Adjust for 98001 ASIC\n" );
|
|
|
|
ps->pScanBuffer2 = ps->pPrescan16;
|
|
ps->pScanBuffer1 = ps->pScanBuffer2 + _LINE_BUFSIZE1;
|
|
ps->pColorRunTable = ps->pScanBuffer1 + _LINE_BUFSIZE * 2UL;
|
|
ps->pProcessingBuf = ps->pColorRunTable + ps->BufferForColorRunTable;
|
|
DBG( DBG_LOW, "sb2 = 0x%lx, sb1 = 0x%lx, Color = 0x%lx\n",
|
|
(ULong)ps->pScanBuffer2, (ULong)ps->pScanBuffer1,
|
|
(ULong)ps->pColorRunTable );
|
|
DBG( DBG_LOW, "Pro = 0x%lx, size = %ld\n",
|
|
(ULong)ps->pProcessingBuf, ps->TotalBufferRequire );
|
|
|
|
ps->dwShadow = (_DEF_BRIGHTEST_SKIP + _DEF_DARKEST_SKIP) * 5400UL * 2UL * 3UL;
|
|
|
|
ps->Shade.pHilight = _VMALLOC( ps->dwShadow );
|
|
|
|
if ( NULL != ps->Shade.pHilight ) {
|
|
|
|
memset( ps->Shade.pHilight, 0, ps->dwShadow );
|
|
|
|
ps->dwHilight = _DEF_BRIGHTEST_SKIP * 5400UL * 3UL;
|
|
ps->dwShadow = _DEF_DARKEST_SKIP * 5400UL * 3UL;
|
|
ps->pwShadow = (pUShort)ps->Shade.pHilight + ps->dwHilight;
|
|
ps->Shade.dwDiv = 32UL - _DEF_BRIGHTEST_SKIP - _DEF_DARKEST_SKIP;
|
|
|
|
ps->dwHilightCh = ps->dwHilight / 3UL;
|
|
ps->dwShadowCh = ps->dwShadow / 3UL;
|
|
}
|
|
} else if ( _ASIC_IS_98003 == ps->sCaps.AsicID ) {
|
|
|
|
DBG( DBG_LOW, "Adjust for 98003 ASIC\n" );
|
|
|
|
ps->Bufs.b1.pReadBuf = ps->driverbuf;
|
|
ps->Bufs.b2.pSumBuf = ps->Bufs.b1.pReadBuf + _SizeDataBuf;
|
|
ps->Bufs.TpaBuf.pb = &((pUChar)ps->Bufs.b2.pSumBuf)[_SizeShadingSumBuf];
|
|
|
|
/* CHECK: We might should play around with these values... */
|
|
ps->Shade.skipHilight = _DEF_BRIGHTEST_SKIP;
|
|
ps->Shade.skipShadow = _DEF_DARKEST_SKIP;
|
|
|
|
if( ps->Shade.skipHilight && ps->Shade.skipShadow ) {
|
|
|
|
ULong skipSize;
|
|
|
|
skipSize = (ULong)((ps->Shade.skipHilight + ps->Shade.skipShadow)
|
|
* _SizeDataBuf * 3);
|
|
|
|
ps->Shade.pHilight = _VMALLOC( skipSize );
|
|
|
|
if( NULL != ps->Shade.pHilight ) {
|
|
ps->Shade.dwDiv = (ULong)(32UL - ps->Shade.skipHilight -
|
|
ps->Shade.skipShadow);
|
|
}
|
|
} else
|
|
ps->Shade.pHilight = NULL;
|
|
}
|
|
|
|
return _OK;
|
|
}
|
|
|
|
/** model 48xx detection or any other model using the 96001/3 ASIC
|
|
*/
|
|
static int detectP48xx( pScanData ps )
|
|
{
|
|
int result;
|
|
|
|
DBG( DBG_LOW, "************ DETECTP48xx ************\n" );
|
|
|
|
/* increase the delay-time */
|
|
ps->IO.delay = 4;
|
|
|
|
ModelSet4800( ps );
|
|
|
|
result = P48xxInitAsic( ps );
|
|
if( _OK != result )
|
|
return result;
|
|
|
|
return detectScannerConnection( ps );
|
|
}
|
|
|
|
/** ASIC 98003 model detection
|
|
*/
|
|
static int detectAsic98003( pScanData ps )
|
|
{
|
|
int result;
|
|
|
|
DBG( DBG_LOW, "************* ASIC98003 *************\n" );
|
|
|
|
/* increase the delay-time */
|
|
ps->IO.delay = 4;
|
|
|
|
ModelSetP12( ps );
|
|
|
|
result = P12InitAsic( ps );
|
|
if( _OK != result )
|
|
return result;
|
|
|
|
IOSoftwareReset( ps );
|
|
|
|
return detectScannerConnection( ps );
|
|
}
|
|
|
|
/** ASIC 98001 model detection
|
|
*/
|
|
static int detectAsic98001( pScanData ps )
|
|
{
|
|
int result;
|
|
|
|
DBG( DBG_LOW, "************* ASIC98001 *************\n" );
|
|
|
|
/* increase the delay-time */
|
|
ps->IO.delay = 4;
|
|
|
|
ModelSet9636( ps );
|
|
|
|
result = P9636InitAsic( ps );
|
|
#ifndef _ASIC_98001_SIM
|
|
if( _OK != result )
|
|
return result;
|
|
|
|
return detectScannerConnection( ps );
|
|
#else
|
|
#ifdef __KERNEL__
|
|
_PRINT(
|
|
#else
|
|
DBG( DBG_HIGH,
|
|
#endif
|
|
"!!!! WARNING, have a look at function detectAsic98001() !!!!\n" );
|
|
ps->sCaps.AsicID = _ASIC_IS_98001;
|
|
ps->sCaps.wIOBase = ps->IO.pbSppDataPort;
|
|
return _OK;
|
|
#endif
|
|
}
|
|
|
|
/************************ exported functions *********************************/
|
|
|
|
/** here we try to find the scanner, depending on the mode
|
|
*/
|
|
_LOC int DetectScanner( pScanData ps, int mode )
|
|
{
|
|
Byte asic;
|
|
int result = _E_INTERNAL;
|
|
|
|
/*
|
|
* before doing anything else, check the port-mode
|
|
*/
|
|
if((ps->IO.portMode != _PORT_EPP) && (ps->IO.portMode != _PORT_SPP) &&
|
|
(ps->IO.portMode != _PORT_BIDI)) {
|
|
|
|
DBG( DBG_LOW, "!!! Portmode (%u)not supported !!!\n", ps->IO.portMode );
|
|
return _E_INTERNAL;
|
|
}
|
|
|
|
/* autodetection ?
|
|
*/
|
|
if( 0 == mode ) {
|
|
|
|
DBG( DBG_HIGH, "Starting Scanner-Autodetection\n" );
|
|
|
|
/* try to find a 48xx Scanner
|
|
* (or even a scanner based on the 96001/3) ASIC
|
|
*/
|
|
result = detectP48xx( ps );
|
|
|
|
if( _OK != result ) {
|
|
|
|
DBG( DBG_LOW, "************* ASIC9800x *************\n" );
|
|
|
|
/* get the ASIC ID by using the OpenScanPath stuff from Asic9600x based
|
|
* models - only difference: change the ReadHigh/ReadLow signals before
|
|
*/
|
|
ps->CtrlReadHighNibble = _CTRL_GENSIGNAL+_CTRL_AUTOLF+_CTRL_STROBE;
|
|
ps->CtrlReadLowNibble = _CTRL_GENSIGNAL+_CTRL_AUTOLF;
|
|
|
|
/* read Register 0x18 (AsicID Register) of Asic9800x based devices */
|
|
#ifdef _ASIC_98001_SIM
|
|
#ifdef __KERNEL__
|
|
_PRINT(
|
|
#else
|
|
DBG( DBG_HIGH,
|
|
#endif
|
|
"!!!! WARNING, SW-Emulation active !!!!\n" );
|
|
asic = _ASIC_IS_98001;
|
|
#else
|
|
detectResetPort( ps );
|
|
|
|
/* do some presettings to make IODataRegisterFromScanner() work */
|
|
ps->RegAsicID = 0x18;
|
|
ps->IO.useEPPCmdMode = _FALSE;
|
|
ps->sCaps.AsicID = _ASIC_IS_98001;
|
|
IOInitialize( ps );
|
|
|
|
asic = IODataRegisterFromScanner( ps, ps->RegAsicID );
|
|
|
|
DBG( DBG_HIGH, "ASIC = 0x%02X\n", asic );
|
|
#endif
|
|
|
|
/* depending on what we have found, perform some extra tests */
|
|
switch( asic ) {
|
|
|
|
case _ASIC_IS_98001:
|
|
result = detectAsic98001( ps );
|
|
break;
|
|
|
|
case _ASIC_IS_98003:
|
|
|
|
/* as the reading of the ASIC ID causes trouble,
|
|
* we reset the device
|
|
*/
|
|
ps->IO.useEPPCmdMode = _FALSE;
|
|
ps->sCaps.AsicID = _ASIC_IS_98003;
|
|
IOInitialize( ps );
|
|
IOSoftwareReset( ps );
|
|
|
|
result = detectAsic98003( ps );
|
|
break;
|
|
|
|
default:
|
|
DBG( DBG_HIGH, "Unknown ASIC-ID\n" );
|
|
result = _E_NO_DEV;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
/* this will be called each time before operating on a previously
|
|
* detected device, to make sure we are still operating on the same one
|
|
*/
|
|
if( _ASIC_IS_98001 == mode ) {
|
|
|
|
DBG( DBG_HIGH, "Starting Scanner-detection (ASIC 98001)\n" );
|
|
result = detectAsic98001( ps );
|
|
|
|
} else if( _ASIC_IS_98003 == mode ) {
|
|
|
|
DBG( DBG_HIGH, "Starting Scanner-detection (ASIC 98003)\n" );
|
|
result = detectAsic98003( ps );
|
|
|
|
} else {
|
|
|
|
DBG( DBG_HIGH, "Starting Scanner-detection (ASIC 96001/3)\n" );
|
|
result = detectP48xx( ps );
|
|
}
|
|
}
|
|
|
|
if( _OK == result ) {
|
|
|
|
_ASSERT( ps->SetupScannerVariables );
|
|
ps->SetupScannerVariables( ps );
|
|
|
|
detectSetupBuffers( ps );
|
|
|
|
} else {
|
|
/* CHECK - we should not need that anymore - paranoia code ??!!!!
|
|
*/
|
|
ps->sCaps.wIOBase = _NO_BASE;
|
|
}
|
|
|
|
DBG( DBG_LOW, "*** DETECTION DONE, result: %i ***\n", result );
|
|
return result;
|
|
}
|
|
|
|
/* END PLUSTEK-PP_DETECT.C ..................................................*/
|