diff options
Diffstat (limited to 'backend/plustek-pp_detect.c')
-rw-r--r-- | backend/plustek-pp_detect.c | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/backend/plustek-pp_detect.c b/backend/plustek-pp_detect.c new file mode 100644 index 0000000..51fad69 --- /dev/null +++ b/backend/plustek-pp_detect.c @@ -0,0 +1,526 @@ +/* @file plustek-pp_detect.c + * @brief automatic scanner detection + * + * based on sources acquired from Plustek Inc. + * Copyright (C) 1998 Plustek Inc. + * Copyright (C) 2000-2013 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 + * - 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" + +/************************** 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(%u 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 %d\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", + (unsigned long)ps->pColorRunTable, + (unsigned long)((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", + (unsigned long)ps->pScanBuffer2, + (unsigned long)ps->pScanBuffer1, + (unsigned long)ps->pColorRunTable ); + DBG( DBG_LOW, "Pro = 0x%lx, size = %d\n", + (unsigned long)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 ..................................................*/ |