summaryrefslogtreecommitdiff
path: root/backend/plustek-pp_detect.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/plustek-pp_detect.c')
-rw-r--r--backend/plustek-pp_detect.c526
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 ..................................................*/