From 6e9c41a892ed0e0da326e0278b3221ce3f5713b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 6 Oct 2014 14:00:40 +0200 Subject: Initial import of sane-backends version 1.0.24-1.2 --- backend/plustek-pp_motor.c | 3348 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3348 insertions(+) create mode 100644 backend/plustek-pp_motor.c (limited to 'backend/plustek-pp_motor.c') diff --git a/backend/plustek-pp_motor.c b/backend/plustek-pp_motor.c new file mode 100644 index 0000000..f377b7e --- /dev/null +++ b/backend/plustek-pp_motor.c @@ -0,0 +1,3348 @@ +/* @file plustek-pp_motor.c + * @brief all functions for motor control + * + * based on sources acquired from Plustek Inc. + * Copyright (C) 1998 Plustek Inc. + * Copyright (C) 2000-2013 Gerhard Jaeger + * also based on the work done by Rick Bronson + * + * History: + * - 0.30 - initial version + * - 0.31 - no changes + * - 0.32 - slight cosmetic changes + * - added function MotorToHomePosition() + * - 0.33 - added additional debug-messages + * - increased speed for returning to homeposition for Models >= 9630 + * (and ASIC 96003) + * - 0.34 - added FIFO overflow check in motorP96SetSpeed + * - removed WaitBack() function from pScanData structure + * - removed wStayMaxStep from pScanData structure + * - 0.35 - changed motorP96UpdateDataCurrentReadLine() to handle proper + * - work of ASIC96003 based 600dpi models + * - 0.36 - merged motorP96WaitBack and motorP98WaitBack to motorWaitBack + * - merged motorP96SetSpeed and motorP98SetSpedd to motorSetSpeed + * - added Sensor-Check in function MotorToHomePosition + * - reduced number of forward steps for MotorToHomePosition + * - 0.37 - removed function motorP96GetStartStopGap() - no longer used + * - removed a_bStepDown1Table and a_bStepUp1Table + * - removed // comments + * - added A3I stuff + * - 0.38 - cosmetic changes + * - added P12 stuff + * - 0.39 - Did some finetuning in MotorP98003ModuleForwardBackward() + * - Fixed a problem, that could cause the driver to throw a + * kernel exception + * - 0.40 - changed back to build 0.39-3 (disabled A3I stuff) + * - 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 + * . + *
+ * 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. + *
+ */ +#include "plustek-pp_scan.h" + +/*************************** some definitons *********************************/ + +/* #define _A3I_EN */ + +/* + * adjustments for scanning in negative and tranparency mode + */ +#define _NEG_SCANNINGPOS 770 +#define _POS_SCANNINGPOS 660 /* original value was 710 */ + +#define _P98_BACKMOVES 0x3d +#define _P98_FORWARDMOVES 0x3b /* Origin = 3c */ + +#define _P98003_BACKSTEPS 120 +#define _P98003_FORWARDSTEPS 120 + +#define _P96_BACKMOVES 130 +#define _P96_FORWARDMOVES 87 /* 95 */ +#define _P96_FIFOOVERFLOWTHRESH 180 + + +#define _COLORRUNTABLE_RED 0x11 +#define _COLORRUNTABLE_GREEN 0x22 +#define _COLORRUNTABLE_BLUE 0x44 + +#define _BW_ORIGIN 0x0D +#define _GRAY_ORIGIN 0x0B +#define _COLOR_ORIGIN 0x0B + +#define _P98003_YOFFSET 300 + +/**************************** local vars *************************************/ + +static TimerDef p98003MotorTimer; + +static UShort a_wMoveStepTable [_NUMBER_OF_SCANSTEPS]; +static Byte a_bScanStateTable[_SCANSTATE_TABLE_SIZE]; +static Byte a_bHalfStepTable [_NUMBER_OF_SCANSTEPS]; +static Byte a_bColorByteTable[_NUMBER_OF_SCANSTEPS]; +static Byte a_bColorsSum[8] = {0, 1, 1, 2, 1, 2, 2, 3}; + +static pUShort pwEndMoveStepTable = a_wMoveStepTable + _NUMBER_OF_SCANSTEPS; +static pUChar pbEndColorByteTable = a_bColorByteTable + _NUMBER_OF_SCANSTEPS; +static pUChar pbEndHalfStepTable = a_bHalfStepTable + _NUMBER_OF_SCANSTEPS; + +/* + * for the 96001/3 based units + */ +static UShort wP96BaseDpi = 0; + +static Byte a_bStepDown1Table[20] = {3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static Byte a_bStepUp1Table[20] = {4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static Byte a_bMotorDown2Table[20] = {0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; + +#ifndef _A3I_EN +static Byte a_bHalfStep2Table[32] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static Byte a_bHalfStep4Table[16] = {2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; +static Byte a_bHalfStep6Table[12] = {3,3,3,3,3,3,3,3,3,3,3,3}; +static Byte a_bHalfStep8Table[8] = {4,4,4,4,4,4,4,4}; +static Byte a_bHalfStep10Table[8] = {5,5,5,5,5,5,5,5}; +static Byte a_bHalfStep12Table[6] = {6,6,6,6,6,6}; +static Byte a_bHalfStep14Table[6] = {7,7,7,7,7,7}; +static Byte a_bHalfStep16Table[4] = {8,8,8,8}; +static Byte a_bHalfStep18Table[4] = {9,9,9,9}; +static Byte a_bHalfStep20Table[4] = {10,10,10,10}; +static Byte a_bHalfStep22Table[4] = {11,11,11,11}; +static Byte a_bHalfStep24Table[4] = {12,12,12,12}; +static Byte a_bHalfStep26Table[4] = {13,13,13,13}; +static Byte a_bHalfStep28Table[4] = {14,14,14,14}; +static Byte a_bHalfStep30Table[4] = {15,15,15,15}; +static Byte a_bHalfStep32Table[2] = {16,16}; +static Byte a_bHalfStep34Table[2] = {17,17}; +static Byte a_bHalfStep36Table[2] = {18,18}; +static Byte a_bHalfStep38Table[2] = {19,19}; +static Byte a_bHalfStep40Table[2] = {20,20}; + + +static pUChar a_pbHalfStepTables[20] = { + a_bHalfStep2Table, a_bHalfStep4Table, + a_bHalfStep6Table, a_bHalfStep8Table, + a_bHalfStep10Table, a_bHalfStep12Table, + a_bHalfStep14Table, a_bHalfStep16Table, + a_bHalfStep18Table, a_bHalfStep20Table, + a_bHalfStep22Table, a_bHalfStep24Table, + a_bHalfStep26Table, a_bHalfStep28Table, + a_bHalfStep30Table, a_bHalfStep32Table, + a_bHalfStep34Table, a_bHalfStep36Table, + a_bHalfStep38Table, a_bHalfStep40Table +}; +#endif + +/*************************** local functions *********************************/ + +/*............................................................................. + * + */ +static void motorP96GetStartStopGap( pScanData ps, Bool fCheckState ) +{ + UChar bMotorCountDownIndex; + + if( fCheckState ) { + + ps->bMotorStepTableNo = 0xff; + if( ps->Scan.bModuleState == _MotorInNormalState ) + return; + } + + bMotorCountDownIndex = ps->bMotorSpeedData / 2; + + if( ps->bCurrentSpeed == 4 && ps->AsicReg.RD_Dpi < 80 ) + ps->bMotorStepTableNo = 4; + else + if( ps->Scan.bModuleState == _MotorGoBackward ) + ps->bMotorStepTableNo = a_bStepUp1Table[bMotorCountDownIndex]; + else + ps->bMotorStepTableNo = a_bStepDown1Table[bMotorCountDownIndex]; +} + + + +/*............................................................................. + * wait for the ScanState stop or ScanState reachs the dwScanStateCount + */ +static Bool motorCheckMotorPresetLength( pScanData ps ) +{ + Byte bScanState; + TimerDef timer; + + MiscStartTimer( &timer, (_SECOND * 4)); + do { + + bScanState = IOGetScanState( ps, _FALSE ); + + if (ps->fFullLength) { + if (!(bScanState & _SCANSTATE_STOP)) /* still running */ + if ((ULong)(bScanState & _SCANSTATE_MASK) != ps->dwScanStateCount ) + continue; + return ps->fFullLength; + } + + if (bScanState & _SCANSTATE_STOP) + break; + + /* + * the code may work for all units + */ + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + if (bScanState < ps->bOldStateCount) + bScanState += _NUMBER_OF_SCANSTEPS; + + bScanState -= ps->bOldStateCount; + + if (bScanState >= 40) + return ps->fFullLength; + } + + } while ( !MiscCheckTimer( &timer )); + + _DODELAY(1); /* delay one ms */ + + return ps->fFullLength; +} + +/*............................................................................. + * 1) Keep the valid content of a_bColorByteTable, and fill others to 0: + * BeginFill = ((bCurrentLineCount + DL) < 64) ? bCurrentLineCount + DL : + * bCurrentLineCount + DL - 64; + * FillLength = 64 - DL + * [NOTE] Keep the content of a_bColorByteTable that begin at + * bCurrentLineCount and in DL bytes + * 2) Keep the valid content of a_bHalfStepTable, and fill the others to 0: + * BeginFill = ((bCurrentLineCount + bCurrentSpeed / 2 + 1) < 64) ? + * bCurrentLineCount + bCurrentSpeed / 2 + 1 : + * bCurrentLineCount + bCurrentSpeed / 2 + 1 - 64; + * FillLength = 64 - (bMotorSpeedData / 2 + 1); + */ +static void motorClearColorByteTableLoop0( pScanData ps, Byte bColors ) +{ + ULong dw; + pUChar pb; + + if ((ps->bCurrentLineCount + bColors) >= _NUMBER_OF_SCANSTEPS) { + pb = a_bColorByteTable + (ULong)(ps->bCurrentLineCount + bColors - + _NUMBER_OF_SCANSTEPS); + } else { + pb = a_bColorByteTable + (ULong)(ps->bCurrentLineCount + bColors); + } + + for (dw = _NUMBER_OF_SCANSTEPS - bColors; dw; dw--) { + + *pb++ = 0; + if (pb >= pbEndColorByteTable) + pb = a_bColorByteTable; + } + + if ((ps->bCurrentLineCount+ps->bCurrentSpeed/2+1) >= _NUMBER_OF_SCANSTEPS) { + + pb = a_bHalfStepTable + (ULong)(ps->bCurrentLineCount + + ps->bCurrentSpeed / 2 + 1 - _NUMBER_OF_SCANSTEPS); + } else { + pb = a_bHalfStepTable + + (ULong)(ps->bCurrentLineCount + ps->bCurrentSpeed / 2 + 1); + } + + for (dw = _NUMBER_OF_SCANSTEPS - ps->bMotorSpeedData / 2 - 1; dw; dw--) { + *pb++ = 0; + if (pb >= pbEndHalfStepTable) + pb = a_bHalfStepTable; + } +} + +/*............................................................................. + * motorClearColorByteTableLoop1 () + * 1) Adjust bNewGap: + * bNewGap = (bNewGap <= bNewCurrentLineCountGap) ? + * 0 : bNewGap - bNewCurrentLineCount - 1; + * 2) Fill the 0 to a_bColorByteTable: + * FillIndex = ((bCurrentLineCount + bNewGap + 1) < 64) ? + * bCurrentLineCount + bNewGap + 1 : + * bCurrentLineCount + bNewGap + 1 - 64; + * FillCount = 64 - bNewGap - 1; + * 3) Adjust bNewGap: + * bNewGap = (bCurrentLineCount <= bNewCurrentLineCountGap) ? + * 0 : bNewGap - bNewCurrentLineCount - 1; + * 4) Fill the a_bHalfStepTable: + * FillIndex = ((bCurrentLineCount + bNewGap + 1) < 64) ? + * bCurrentLineCount + bNewGap + 1 : + * bCurrentLineCount + bNewGap + 1 - 64; + * FillCount = 64 - bNewGap - 1; + */ +static void motorClearColorByteTableLoop1( pScanData ps ) +{ + ULong dw = _NUMBER_OF_SCANSTEPS - 1; + pUChar pb; + + if (ps->bNewGap > ps->bNewCurrentLineCountGap) { + ps->bNewGap = ps->bNewGap - ps->bNewCurrentLineCountGap - 1; + dw -= (ULong)ps->bNewGap; + } else { + ps->bNewGap = 0; + } + + if ((ps->bCurrentLineCount + ps->bNewGap + 1) >= _NUMBER_OF_SCANSTEPS) { + pb = a_bColorByteTable + + (ULong)(ps->bCurrentLineCount+ps->bNewGap+1-_NUMBER_OF_SCANSTEPS); + } else { + pb = a_bColorByteTable + + (ULong)(ps->bCurrentLineCount + ps->bNewGap + 1); + } + + for (; dw; dw--) { + *pb++ = 0; + if (pb >= pbEndColorByteTable) + pb = a_bColorByteTable; + } + + if (ps->bCurrentSpeed > ps->bNewCurrentLineCountGap) { + ps->bNewGap = ps->bCurrentSpeed - ps->bNewCurrentLineCountGap; + dw = _NUMBER_OF_SCANSTEPS - 1 - (ULong)ps->bNewGap; + } else { + dw = _NUMBER_OF_SCANSTEPS - 1; + ps->bNewGap = 0; + } + + if ((ps->bCurrentLineCount + ps->bNewGap + 1) >= _NUMBER_OF_SCANSTEPS) { + pb = a_bHalfStepTable + (ULong)(ps->bCurrentLineCount + + ps->bNewGap + 1 - _NUMBER_OF_SCANSTEPS); + } else { + pb = a_bHalfStepTable + (ULong)(ps->bCurrentLineCount+ps->bNewGap +1); + } + + for (; dw; dw--) { + *pb++ = 0; + if (pb >= pbEndHalfStepTable) + pb = a_bHalfStepTable; + } +} + +/*............................................................................. + * According the flag to set motor direction + */ +static void motorSetRunPositionRegister( pScanData ps ) +{ + Byte bData; + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + if( ps->Scan.fMotorBackward ) { + bData = ps->AsicReg.RD_Motor0Control & ~_MotorDirForward; + } else { + bData = ps->AsicReg.RD_Motor0Control | _MotorDirForward; + } + + IOCmdRegisterToScanner( ps, ps->RegMotor0Control, bData ); + + } else { + + if( ps->Scan.fMotorBackward ) { + bData = ps->Asic96Reg.RD_MotorControl & ~_MotorDirForward; + } else { + bData = ps->Asic96Reg.RD_MotorControl | _MotorDirForward; + } + + IOCmdRegisterToScanner( ps, ps->RegMotorControl, bData ); + } +} + +/*............................................................................. + * + */ +static void motorPauseColorMotorRunStates( pScanData ps ) +{ + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES); + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + ps->a_nbNewAdrPointer[2] = 0x77; /* Read color at the same time */ + + } else { + ps->a_nbNewAdrPointer[2] = 1; + ps->a_nbNewAdrPointer[3] = 3; + ps->a_nbNewAdrPointer[4] = 2; + } + + MotorSetConstantMove( ps, 0 ); +} + +/*............................................................................. + * Setup the a_nbNewAdrPointer for ASIC stepping register + */ +static void motorP98FillDataToColorTable( pScanData ps, + Byte bIndex, ULong dwSteps) +{ + pUChar pb; + pUShort pw; + Byte bColor; + UShort w; + + for ( pb = &a_bColorByteTable[bIndex], + pw = &a_wMoveStepTable[bIndex]; dwSteps; dwSteps-- ) { + + if (*pw) { /* valid state */ + + if( *pw >= ps->BufferForColorRunTable ) { + DBG( DBG_LOW, "*pw = %u > %u !!\n", + *pw, ps->BufferForColorRunTable ); + } else { + bColor = ps->pColorRunTable[*pw]; /* get the colors */ + if (a_bColorsSum[bColor & 7]) /* need to read data */ + *pb = bColor & 7; + } + } + + if (++pw >= pwEndMoveStepTable) { + pw = a_wMoveStepTable; + pb = a_bColorByteTable; + } else + pb++; + } + + /* ToCondense */ + pb = a_bColorByteTable; + + for (w = 0; w < _SCANSTATE_BYTES; w++, pb += 2) + ps->a_nbNewAdrPointer[w] = (Byte)((*pb & 7) + ((*(pb + 1) & 7) << 4)); + + /* ToCondenseMotor */ + for (pb = a_bHalfStepTable, w = 0; w < _SCANSTATE_BYTES; w++) { + if (*pb++) + ps->a_nbNewAdrPointer [w] |= 8; + + if (*pb++) + ps->a_nbNewAdrPointer [w] |= 0x80; + } +} + +/*............................................................................. + * + */ +static void motorP98FillHalfStepTable( pScanData ps ) +{ + pUChar pbHalfStepTbl, pb; + pUShort pwMoveStep; + DataType Data; + ULong dw; + + if (1 == ps->bMotorSpeedData) { + for (dw = 0; dw < _NUMBER_OF_SCANSTEPS; dw++) + a_bHalfStepTable [dw] = + (a_wMoveStepTable [dw] > ps->wMaxMoveStep) ? 0: 1; + } else { + pwMoveStep = &a_wMoveStepTable[ps->bCurrentLineCount]; + pbHalfStepTbl = &a_bHalfStepTable[ps->bCurrentLineCount]; + + if (ps->DataInf.wAppDataType >= COLOR_TRUE24) + Data.dwValue = _NUMBER_OF_SCANSTEPS - 1; + else + Data.dwValue = _NUMBER_OF_SCANSTEPS; + + for (; Data.dwValue; Data.dwValue--, pbHalfStepTbl++, pwMoveStep++ ) { + + if (pwMoveStep >= pwEndMoveStepTable) { + pbHalfStepTbl = a_bHalfStepTable; + pwMoveStep = a_wMoveStepTable; + } + + if (*pwMoveStep) { /* need to exposure */ + + dw = (ULong)ps->bMotorSpeedData; + if (Data.bValue < ps->bMotorSpeedData) + *pwMoveStep = 0; + else { + *pbHalfStepTbl = 1; + + if (ps->dwFullStateSpeed) { + dw -= ps->dwFullStateSpeed; + for (pb = pbHalfStepTbl; dw; + dw -= ps->dwFullStateSpeed) { + pb += ps->dwFullStateSpeed; + if (pb >= pbEndHalfStepTable) + pb -= _NUMBER_OF_SCANSTEPS; + *pb = 1; + } + } + } + } + } + } +} + +/*............................................................................. + * + */ +static void motorP98FillBackColorDataTable( pScanData ps ) +{ + Byte bIndex; + + if ((bIndex = ps->bCurrentLineCount + ps->bNewCurrentLineCountGap + 1) >= + _NUMBER_OF_SCANSTEPS) { + bIndex -= _NUMBER_OF_SCANSTEPS; + } + + motorP98FillDataToColorTable( ps, bIndex, (ULong)(_NUMBER_OF_SCANSTEPS - + ps->bNewCurrentLineCountGap)); +} + +/*............................................................................. + * i/p: + * pScanStep = pColorRunTable if forward, a_bScanStateTable if backward + * dwState = how many states is requested to process + * NOTE: + * The content of pScanStep contain: + * 0: Idle state + * 0xff: End mark + * others: The motor speed value + */ +static void motorP98FillBackLoop( pScanData ps, + pUChar pScanStep, ULong dwStates ) +{ + for (ps->fFullLength = _FALSE; dwStates; dwStates--) { + + if (*pScanStep == 0xff ) { + + ULong dw = ps->dwScanStateCount; + + for (; dwStates; dwStates--) { + ps->a_nbNewAdrPointer [dw / 2] &= ((dw & 1) ? 0x7f: 0xf7); + dw = (dw + 1U) & _SCANSTATE_MASK; + } + if (!ps->dwScanStateCount) + ps->dwScanStateCount = _NUMBER_OF_SCANSTEPS; + + ps->dwScanStateCount--; + ps->fFullLength = _TRUE; + break; + } else { + ps->a_nbNewAdrPointer [ps->dwScanStateCount / 2] |= + ((ps->dwScanStateCount & 1) ? 0x80 : 0x08); + if (++ps->dwScanStateCount == _NUMBER_OF_SCANSTEPS) + ps->dwScanStateCount = 0; /* reset to begin */ + + pScanStep++; + } + } + IOSetToMotorStepCount( ps ); /* put all scan states to ASIC */ +} + +/*............................................................................. + * + */ +static void motorP98SetRunFullStep( pScanData ps ) +{ + ps->OpenScanPath( ps ); + + ps->AsicReg.RD_StepControl = _MOTOR0_SCANSTATE; + IODataToRegister( ps, ps->RegStepControl, + ps->AsicReg.RD_StepControl ); + IODataToRegister( ps, ps->RegLineControl, 96 ); + + if ( ps->bFastMoveFlag == _FastMove_Low_C75_G150_Back ) { + IODataToRegister( ps, ps->RegMotor0Control, + (_MotorHQuarterStep + _MotorOn + _MotorDirBackward)); + } else { + IODataToRegister( ps, ps->RegMotor0Control, + (_MotorHQuarterStep + _MotorOn + _MotorDirForward)); + } + + if (ps->bFastMoveFlag == _FastMove_Film_150) { + ps->AsicReg.RD_XStepTime = 12; + } else { + if (ps->bFastMoveFlag == _FastMove_Fast_C50_G100) { + ps->AsicReg.RD_XStepTime = + ((ps->DataInf.wPhyDataType >= COLOR_TRUE24) ? 4 : 8); + } else { + ps->AsicReg.RD_XStepTime = + ((ps->DataInf.wPhyDataType >= COLOR_TRUE24) ? 6 : 12); + } + } + + DBG( DBG_LOW, "XStepTime = %u\n", ps->AsicReg.RD_XStepTime ); + IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime); + ps->CloseScanPath( ps ); +} + +/*............................................................................. + * moves the sensor back home... + */ +static int motorP98BackToHomeSensor( pScanData ps ) +{ + int result = _OK; + TimerDef timer; + + MotorSetConstantMove( ps, 1 ); + + ps->OpenScanPath( ps ); + + ps->AsicReg.RD_StepControl = + (_MOTOR_FREERUN + _MOTOR0_SCANSTATE+ _MOTOR0_ONESTEP); + IODataToRegister( ps, ps->RegStepControl, ps->AsicReg.RD_StepControl); + + ps->AsicReg.RD_ModeControl = _ModeScan; + IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl ); + + ps->AsicReg.RD_Motor0Control = _MotorHQuarterStep + + _MotorOn + _MotorDirBackward; + IODataToRegister( ps, ps->RegMotor0Control, ps->AsicReg.RD_Motor0Control ); + + + if( ps->DataInf.wPhyDataType >= COLOR_TRUE24) { + ps->AsicReg.RD_XStepTime = ps->bSpeed24; + } else { + ps->AsicReg.RD_XStepTime = ps->bSpeed12; + } + + DBG( DBG_HIGH, "XStepTime = %u\n", ps->AsicReg.RD_XStepTime ); + + IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime ); + IORegisterToScanner( ps, ps->RegRefreshScanState ); + + /* CHANGE: We allow up to 25 seconds for returning (org. val was 10) */ + MiscStartTimer( &timer, _SECOND * 25 ); + + do { + if (IODataFromRegister( ps, ps->RegStatus) & _FLAG_P98_PAPER ) { + IODataToRegister( ps, ps->RegModelControl, + (Byte)(ps->AsicReg.RD_ModelControl | _HOME_SENSOR_POLARITY)); + if(!(IODataFromRegister(ps, ps->RegStatus) & _FLAG_P98_PAPER)) + break; + } + _DODELAY( 10 ); /* delay 10 ms */ + + } while ( !(result = MiscCheckTimer( &timer ))); + + ps->CloseScanPath( ps ); + + if( _OK != result ) + return result; + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + IOSetToMotorRegister( ps ); + + return _OK; +} + +/*............................................................................. + * 1) Clear scan states + * 2) Adjust the new scan state + */ +static void motorP98FillRunNewAdrPointer1( pScanData ps ) +{ + ScanState sState; + Byte bTemp; + + IOGetCurrentStateCount( ps, &sState); + bTemp = sState.bStep; + if (sState.bStep < ps->bOldStateCount) { + sState.bStep += _NUMBER_OF_SCANSTEPS;/* over table (table just can */ + } /* holds 64 step, then reset to */ + /* 0, so if less than means over*/ + /* the table) */ + sState.bStep -= ps->bOldStateCount; /* how many states passed */ + ps->pScanState += sState.bStep; + + /* + * if current state != no stepped or stepped a cycle, fill the table with + * 1 in NOT STEPPED length. (1 means to this state has to be processing). + */ + ps->bOldStateCount = bTemp; + ps->dwScanStateCount = (ULong)((bTemp + 1) & _SCANSTATE_MASK); + + motorP98FillBackLoop( ps, ps->pScanState, _NUMBER_OF_SCANSTEPS ); +} + +/*............................................................................. + * + */ +static void motorP98FillRunNewAdrPointer( pScanData ps ) +{ + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + motorP98FillRunNewAdrPointer1( ps ); +} + +/*............................................................................. + * move the sensor to a specific Y-position + */ +static void motorP98PositionYProc( pScanData ps, ULong dwStates ) +{ + ScanState sState; + + memset( ps->pColorRunTable, 1, dwStates ); + memset( ps->pColorRunTable + dwStates, 0xff, (3800UL - dwStates)); + + IOGetCurrentStateCount( ps, &sState); + + ps->bOldStateCount = sState.bStep; + + ps->OpenScanPath( ps ); + IODataToRegister( ps, ps->RegMotor0Control, + (Byte)(_MotorOn + _MotorHEightStep +(ps->Scan.fMotorBackward)? + _MotorDirBackward : _MotorDirForward)); + + DBG( DBG_LOW, "XStepTime = %u\n", ps->bSpeed6 ); + IODataToRegister( ps, ps->RegXStepTime, ps->bSpeed6 ); + ps->CloseScanPath( ps ); + + ps->pScanState = ps->pColorRunTable; + + ps->FillRunNewAdrPointer( ps ); + + while(!motorCheckMotorPresetLength( ps )) + motorP98FillRunNewAdrPointer1( ps ); +} + +/*............................................................................. + * checks if the sensor is in itīs home position and moves it back if necessary + */ +static int motorP98CheckSensorInHome( pScanData ps ) +{ + int result; + + if (!(IODataRegisterFromScanner(ps,ps->RegStatus) & _FLAG_P98_PAPER)){ + + MotorSetConstantMove( ps, 1 ); + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = 0; + motorP98PositionYProc( ps, 20 ); + + result = motorP98BackToHomeSensor( ps ); + if( _OK != result ) + return result; + + _DODELAY( 250 ); + } + + return _OK; +} + +/*............................................................................. + * move the sensor to the scan-start position + */ +static void motorP98WaitForPositionY( pScanData ps ) +{ + ULong dw; + ULong dwBX, dwDX; + + if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) { + + motorP98BackToHomeSensor( ps ); + _DODELAY( 100 ); + +/* CHECK do we need this block ? was test code in the original source code */ + ps->OpenScanPath( ps ); + IODataToRegister( ps, ps->RegModelControl, ps->AsicReg.RD_ModelControl); + IODataToRegister( ps, ps->RegStepControl, (Byte)(_MOTOR_FREERUN + + _MOTOR0_SCANSTATE + _MOTOR0_ONESTEP)); + IODataToRegister( ps, ps->RegMotor0Control, (Byte)(_MotorOn + + _MotorHQuarterStep + _MotorDirForward)); + ps->CloseScanPath( ps ); + + for (dw=1000; dw; dw--) { + if (IODataRegisterFromScanner( ps, ps->RegStatus) & _FLAG_P98_PAPER) { + IORegisterDirectToScanner( ps, ps->RegForceStep ); + _DODELAY( 1000 / 400 ); + } + } +/*-*/ + ps->AsicReg.RD_ModeControl = _ModeScan; + IOCmdRegisterToScanner( ps, ps->RegModeControl, + ps->AsicReg.RD_ModeControl ); + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = 0; + ps->bFastMoveFlag = _FastMove_Film_150; + + if (ps->DataInf.dwScanFlag & SCANDEF_Negative) { + MotorP98GoFullStep(ps, (ps->DataInf.crImage.y+_NEG_SCANNINGPOS)/2); + } else { + MotorP98GoFullStep(ps, (ps->DataInf.crImage.y+_POS_SCANNINGPOS)/2); + } + + return; + } + + ps->AsicReg.RD_ModeControl = _ModeScan; + + IOCmdRegisterToScanner( ps, ps->RegModeControl, + ps->AsicReg.RD_ModeControl ); + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = 0; + + /* SetStartPoint */ + dw = ps->wInitialStep + ps->DataInf.crImage.y; + + /* + * CHANGE: when checking out the values from the NT registry + * I found that the values are NOT 0 + */ + switch (ps->DataInf.wPhyDataType) { + case COLOR_BW: dw += _BW_ORIGIN; break; + case COLOR_256GRAY: dw += _GRAY_ORIGIN; break; + default: dw += _COLOR_ORIGIN; break; + } + + if (dw & 0x80000000) + dw = 0; /* negative */ + + if (dw > 180) { + if (ps->bSetScanModeFlag & _ScanMode_Mono) { + dwBX = 90; /* go via 150 dpi, so 180 / 2 = 90 */ + dwDX = (dw -180) % 3; + dw = (dw -180) / 3; /* 100 dpi */ + } else { + dwBX = 45; /* go via 75 dpi, so 180 / 4 = 45 */ + dwDX = (dw -180) % 6; + dw = (dw -180) / 6; /* 50 dpi */ + } + + dwDX = (dwDX * 3 + 1) / 2 + dwBX; + + /* + * 100/50 dpi lines is 3/2 times of 150/75 + * eax = (remainder * 3 + 1) / 2 + 180 / (2 or 4) lines + */ + ps->bFastMoveFlag = _FastMove_Low_C75_G150; + MotorP98GoFullStep( ps, dwDX); + + if (dw) { + DBG( DBG_LOW, "FAST MOVE MODE !!!\n" ); + ps->bFastMoveFlag = _FastMove_Fast_C50_G100; + MotorP98GoFullStep( ps, dw); + } + } else { + dwBX = ((ps->bSetScanModeFlag & _ScanMode_Mono) ? 2: 4); + dw = (dw + dwBX/2) / dwBX; + ps->bFastMoveFlag = _FastMove_Low_C75_G150; + + MotorP98GoFullStep(ps, dw); + } +} + +/*............................................................................. + * PreMove/EndMove + * PreMove is only in ADF and CFB mode + * In ADF version, there is a distance gap between Paper flag and Real initial + * position and it need premove to real initial position and turn the motor + * Inverse and start Fast move to start scan position + * In CFB version , PreMove 1 mm to avoid bouncing of PaperFlag sensor then + * fast move + * In CIS and CSP although there have not PreMove but there have End move + * when paper out there still have several mm need to read, + * So it need EndMove 2mm and set Inverse Paper + */ +static Bool motorP98GotoShadingPosition( pScanData ps ) +{ + int result; + + DBG( DBG_LOW, "motorP98GotoShadingPosition()\n" ); + + /* Modify Lamp Back to Home step for Scan twice in short time */ + result = motorP98CheckSensorInHome( ps ); + + if( _OK != result ) + return _FALSE; + + MotorSetConstantMove( ps, 0 ); /* clear scan states */ + + IOCmdRegisterToScanner( ps, ps->RegModelControl, + ps->AsicReg.RD_ModelControl ); + + ps->Scan.fMotorBackward = _FALSE; /* forward */ + ps->bExtraMotorCtrl = 0; + + if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) { + + ps->bFastMoveFlag = _FastMove_Low_C75_G150; + MotorP98GoFullStep( ps, 0x40 ); + + ps->bFastMoveFlag = _FastMove_Middle_C75_G150; + MotorP98GoFullStep( ps, ps->Device.dwModelOriginY ); + } + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + IOSetToMotorRegister( ps ); + + return _TRUE; +} + +/*............................................................................. + * round to the next physical available value + */ +static void motorP98SetMaxDpiAndLength( pScanData ps, + pUShort wLengthY, pUShort wBaseDpi ) +{ + if (ps->DataInf.xyAppDpi.y > 600) + *wLengthY = ps->LensInf.rExtentY.wMax * 4 + 200; + else + *wLengthY = ps->LensInf.rExtentY.wMax * 2 + 200; + + if ((ps->DataInf.wPhyDataType >= COLOR_TRUE24) && + (ps->DataInf.xyAppDpi.y <= ps->wMinCmpDpi)) { + *wBaseDpi = ps->wMinCmpDpi; + } else { + if ((ps->DataInf.wPhyDataType < COLOR_TRUE24) && + (ps->DataInf.xyAppDpi.y <= 75)) { + *wBaseDpi = 75; + } else { + if (ps->DataInf.xyAppDpi.y <= 150) { + *wBaseDpi = 150; + } else { + if (ps->DataInf.xyAppDpi.y <= 300) { + *wBaseDpi = 300; + } else { + if (ps->DataInf.xyAppDpi.y <= 600) + *wBaseDpi = 600; + else + *wBaseDpi = 1200; + } + } + } + } + + DBG( DBG_LOW, "wBaseDPI = %u, %u\n", *wBaseDpi, ps->wMinCmpDpi ); +} + +/*............................................................................. + * + */ +static void motorP98FillGBColorRunTable( pScanData ps, pUChar pTable, + Byte bHi, Byte bLo, UShort wBaseDpi ) +{ + + if( ps->Device.f0_8_16 ) { + + if (wBaseDpi == ps->wMinCmpDpi) { + *pTable |= bHi; + *(pTable + 1) |= bLo; + } else { + switch (wBaseDpi) { + case 150: + *(pTable + 2) |= bHi; + *(pTable + 4) |= bLo; + break; + + case 300: + *(pTable + 4) |= bHi; + *(pTable + 8) |= bLo; + break; + + case 600: + *(pTable + 8) |= bHi; + *(pTable + 16) |= bLo; + break; + + default: + *(pTable + 16) |= bHi; + *(pTable + 32) |= bLo; + break; + } + } + } else { + + if (wBaseDpi == ps->wMinCmpDpi) { + *pTable |= bHi; + *(pTable + 1) |= bLo; + } else { + switch(wBaseDpi) { + + case 150: + *(pTable + 1) |= bHi; + *(pTable + 2) |= bLo; + break; + + case 300: + *(pTable + 2) |= bHi; + *(pTable + 4) |= bLo; + break; + + case 600: + *(pTable + 4) |= bHi; + *(pTable + 8) |= bLo; + break; + + default: + *(pTable + 8) |= bHi; + *(pTable + 16) |= bLo; + break; + } + } + } +} + +/*............................................................................. + * + */ +static void motorP98SetupRunTable( pScanData ps ) +{ + UShort wDpi, w, wBaseDpi, wLengthY; + pUChar pTable; + + motorP98SetMaxDpiAndLength( ps, &wLengthY, &wBaseDpi ); + + /*ClearColorRunTable(); */ + memset( ps->pColorRunTable, 0, ps->BufferForColorRunTable ); + + wDpi = wBaseDpi; + w = wLengthY + 1000; + pTable = ps->pColorRunTable + (_NUMBER_OF_SCANSTEPS / 4); + + if( ps->DataInf.wPhyDataType >= COLOR_TRUE24) { + + for(; w; w--, pTable++) { + if((short)(wDpi -= ps->DataInf.xyPhyDpi.y) <= 0) { + wDpi += wBaseDpi; + *pTable |= 0x44; + motorP98FillGBColorRunTable( ps, pTable, 0x22, 0x11, wBaseDpi ); + } + } + } else { + for(; w; w--, pTable++) { + if((short)(wDpi -= ps->DataInf.xyPhyDpi.y) <= 0) { + wDpi += wBaseDpi; + *pTable = 0x22; + } + } + } + ps->dwColorRunIndex = 0; +} + +/*............................................................................. + * + */ +static void motorP98UpdateDataCurrentReadLine( pScanData ps ) +{ + if(!(ps->Scan.bNowScanState & _SCANSTATE_STOP)) { + + Byte b; + + if (ps->Scan.bNowScanState >= ps->bCurrentLineCount) + b = ps->Scan.bNowScanState - ps->bCurrentLineCount; + else + b = ps->Scan.bNowScanState + _NUMBER_OF_SCANSTEPS - ps->bCurrentLineCount; + + if (b < 40) + return; + } + + ps->SetMotorSpeed( ps, ps->bCurrentSpeed, _TRUE ); + IOSetToMotorRegister( ps ); + + ps->Scan.bModuleState = _MotorAdvancing; +} + +/*............................................................................. + * Byte - Scan State Index (0-63) and StopStep bit + * pScanState->bStep - Scan State Index (0-63) + * pScanState->bStatus - Scanner Status Register value + */ +static void motorP96GetScanStateAndStatus( pScanData ps, pScanState pScanStep ) +{ + ps->OpenScanPath( ps ); + + pScanStep->bStep = IOGetScanState(ps, _TRUE); + pScanStep->bStep &= _SCANSTATE_MASK; /* org was. ~_ScanStateStop; */ + pScanStep->bStatus = IODataFromRegister( ps, ps->RegStatus ); + + ps->CloseScanPath( ps ); +} + +/*............................................................................. + * Capture the image data and average them. + */ +static Byte motorP96ReadDarkData( pScanData ps ) +{ + Byte bFifoOffset; + UShort wSum, w; + TimerDef timer; + + MiscStartTimer( &timer, _SECOND/2); + + do { + + bFifoOffset = IODataRegisterFromScanner( ps, ps->RegFifoOffset ); + + /* stepped 1 block */ + if( bFifoOffset ) { + + /* read data */ + IOReadScannerImageData( ps, ps->pScanBuffer1, 512UL); + + /* 320 = 192 + 128 (128 is size to fetch data) */ + for (w = 192, wSum = 0; w < 320; w++) + wSum += (UShort)ps->pScanBuffer1[w];/* average data from */ + /* offset 192 and size 128*/ + return (Byte)(wSum >> 7); /* divided by 128 */ + } + + } while (!MiscCheckTimer(&timer)); + + return 0xff; /* timed-out */ +} + +/*............................................................................. + * move the sensor to a specific Y-position + */ +static void motorP96PositionYProc( pScanData ps, ULong dwStates ) +{ + ScanState sState; + + memset( ps->pColorRunTable, 1, dwStates ); + +#ifdef DEBUG + if( dwStates > 800UL ) + DBG( DBG_HIGH, "!!!!! RUNTABLE OVERFLOW !!!!!\n" ); +#endif + memset( ps->pColorRunTable + dwStates, 0xff, 800UL - dwStates ); + + IOGetCurrentStateCount( ps, &sState ); + ps->bOldStateCount = sState.bStep; + + /* TurnOnMotorAndSetDirection (); */ + if( ps->Scan.fMotorBackward ) { + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + (Byte)(ps->IgnorePF | ps->MotorOn)); + } else { + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + (Byte)(ps->IgnorePF | ps->MotorOn | _MotorDirForward)); + } + + ps->pScanState = ps->pColorRunTable; + do { + ps->FillRunNewAdrPointer( ps ); + + } while (!motorCheckMotorPresetLength( ps )); +} + +/*............................................................................. + * move the sensor to the scan-start position + */ +static void motorP96WaitForPositionY( pScanData ps ) +{ +/* scheint OKAY zu sein fuer OP4830 */ +#ifdef _A3I_EN +#warning "compiling for A3I" + ULong dw; + ScanState sState; + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + ps->Asic96Reg.RD_MotorControl = ps->IgnorePF|ps->MotorOn|_MotorDirForward; + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = ps->IgnorePF; + + if( ps->DataInf.xyAppDpi.y <= ps->PhysicalDpi ) + dw = 30UL; + else + dw = 46UL; + + dw = (dw + ps->DataInf.crImage.y) * 4 / 3; + + if( ps->DataInf.wPhyDataType == COLOR_TRUE24 ) + dw += 99; /* dwStepsForColor; */ + + else if( ps->DataInf.wPhyDataType == COLOR_256GRAY ) + dw += 99; /* dwStepsForGray; */ + else + dw += 99; /* dwStepsForBW; */ + + if( dw >= 130UL ) { + + dw -= 100UL; + dw <<= 1; + /* GoFullStep (dw); */ + + memset( ps->pColorRunTable, 1, dw ); + memset( ps->pColorRunTable + dw, 0xff, ps->BufferForColorRunTable - dw ); + + IOGetCurrentStateCount( ps, &sState ); + ps->bOldStateCount = sState.bStep; + + /* AdjustMotorTime () */ + IOCmdRegisterToScanner( ps, ps->RegLineControl, 31 ); + + /* SetRunHalfStep () */ + if( ps->Scan.fMotorBackward ) + IOCmdRegisterToScanner( ps, ps->RegMotorControl, _Motor1FullStep | + ps->IgnorePF | ps->MotorOn ); + else + IOCmdRegisterToScanner( ps, ps->RegMotorControl, ps->IgnorePF | + ps->MotorOn | _MotorDirForward ); + + ps->pScanState = ps->pColorRunTable; + + do { + ps->FillRunNewAdrPointer( ps ); + + } while (!motorCheckMotorPresetLength(ps)); + + /* RestoreMotorTime () */ + IOCmdRegisterToScanner( ps, ps->RegLineControl, + ps->AsicReg.RD_LineControl ); + + dw = 100UL; + } + + if( ps->DataInf.wPhyDataType != COLOR_TRUE24 ) + dw += 20; + + motorP96PositionYProc( ps, dw ); + +#else + + ULong dw; + ScanState sState; + + TimerDef timer; + + MiscStartTimer( &timer, _SECOND / 4); + while (!MiscCheckTimer( &timer )); + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + + ps->Asic96Reg.RD_MotorControl = ps->IgnorePF|ps->MotorOn|_MotorDirForward; + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = ps->IgnorePF; + + if ((ps->DataInf.wPhyDataType >= COLOR_TRUE24) || + (ps->DataInf.xyAppDpi.y <= 300)) { + dw = 6UL; + + } else { + + if (ps->DataInf.xyAppDpi.y <= 600) { + /* 50 is from 6/300 */ + dw = (ULong)ps->DataInf.xyAppDpi.y / 50UL + 3UL; + } else + dw = 15; /* 6UL * 600UL / 300UL + 3; */ + } + + dw += ps->DataInf.crImage.y; + + if (dw >= 180UL) { + + dw -= 180UL; + /* GoFullStep (ps, dw);----------------------------------------------*/ + memset( ps->pColorRunTable, 1, dw ); +#ifdef DEBUG + if( dw > 8000UL ) + DBG( DBG_HIGH, "!!!!! RUNTABLE OVERFLOW !!!!!\n" ); +#endif + memset( ps->pColorRunTable + dw, 0xff, 8000UL - dw ); + + IOGetCurrentStateCount( ps, &sState ); + ps->bOldStateCount = sState.bStep; + + /* SetRunFullStep (ps) */ + if( ps->Scan.fMotorBackward ) { + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + (Byte)(ps->FullStep | ps->IgnorePF | ps->MotorOn)); + } else { + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + (Byte)(ps->FullStep | ps->IgnorePF | ps->MotorOn | + _MotorDirForward)); + } + + ps->pScanState = ps->pColorRunTable; + + do { + ps->FillRunNewAdrPointer (ps); + + } while (!motorCheckMotorPresetLength(ps)); + + /*-------------------------------------------------------------------*/ + + dw = 180UL; + } + + if (ps->DataInf.wPhyDataType != COLOR_TRUE24) + dw = dw * 2 + 16; + else + dw *= 2; + + motorP96PositionYProc( ps, dw ); +#endif +} + +/*............................................................................. + * Position Scan Module to specified line number (Forward or Backward & wait + * for paper flag ON) + */ +static void motorP96ConstantMoveProc1( pScanData ps, ULong dwLines ) +{ + Byte bRemainder, bLastState; + UShort wQuotient; + ULong dwDelayMaxTime; + ScanState StateStatus; + TimerDef timer; + Bool fTimeout = _FALSE; + + /* state cycles */ + wQuotient = (UShort)(dwLines / _NUMBER_OF_SCANSTEPS); + bRemainder = (Byte)(dwLines % _NUMBER_OF_SCANSTEPS); + + /* 3.3 ms per line */ +#ifdef _A3I_EN + dwDelayMaxTime = dwLines * _MOTOR_ONE_LINE_TIME + _SECOND * 2; +#else + dwDelayMaxTime = dwLines * _MOTOR_ONE_LINE_TIME + _SECOND * 20; +#endif + + /* step every time */ + MotorSetConstantMove( ps, 1 ); + + ps->OpenScanPath( ps ); + + ps->AsicReg.RD_ModeControl = _ModeScan; + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + + ps->Asic96Reg.RD_MotorControl = ps->MotorFreeRun | + ps->MotorOn | _MotorDirForward; + IODataToRegister( ps, ps->RegMotorControl, ps->Asic96Reg.RD_MotorControl ); + + ps->CloseScanPath( ps ); + + bLastState = 0; + + MiscStartTimer( &timer, dwDelayMaxTime ); + + do { + + /* GetStatusAndScanStateAddr () */ + motorP96GetScanStateAndStatus( ps, &StateStatus ); + if (StateStatus.bStatus & _FLAG_P96_PAPER ) { + if (wQuotient) { + + if (StateStatus.bStep != bLastState) { + bLastState = StateStatus.bStep; + + if (!bLastState) + wQuotient--; + } + } else + if (StateStatus.bStep >= bRemainder) + break; + } else + break; + } while (!(fTimeout = MiscCheckTimer( &timer ))); + + if (!fTimeout) { + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + IOSetToMotorRegister( ps ); + } +} + +/*............................................................................. + * PreMove/EndMove + * PreMove is only in ADF and CFB mode + * In ADF version, there is a distance gap between Paper flag and Real initial + * position and it need premove to real initial position and turn the motor + * Inverse and start Fast move to start scan position + * In CFB version , PreMove 1 mm to avoid bouncing of PaperFlag sensor then + * fast move + * In CIS and CSP although there have not PreMove but there have End move + * when paper out there still have several mm need to read, + * So it need EndMove 2mm and set Inverse Paper + */ +static Bool motorP96GotoShadingPosition( pScanData ps ) +{ + DBG( DBG_LOW, "motorP96GotoShadingPosition()\n" ); + + MotorSetConstantMove( ps, 0 ); /* clear scan states */ + ps->Scan.fMotorBackward = _FALSE; /* forward */ + ps->bExtraMotorCtrl = ps->IgnorePF; + + MotorP96ConstantMoveProc( ps, 15 * 12 ); /* forward 180 lines */ + + if (IODataRegisterFromScanner(ps, ps->RegStatus) & _FLAG_P96_PAPER ) { + ps->Asic96Reg.RD_MotorControl = 0; + IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 ); + + DBG( DBG_LOW, "motorP96GotoShadingPosition() failed\n" ); + return _FALSE; + } + ps->Scan.fMotorBackward = _TRUE; /* backward */ + ps->bExtraMotorCtrl = 0; /* no extra action for motor */ + + /* backward a few thousand lines to touch sensor */ + MotorP96ConstantMoveProc( ps, ps->BackwardSteps ); + + _DODELAY( 250 ); + + IOCmdRegisterToScanner( ps, ps->RegModelControl, + (Byte)(ps->AsicReg.RD_ModelControl | _ModelInvertPF)); + + ps->Scan.fMotorBackward = _FALSE; /* forward */ + motorP96ConstantMoveProc1( ps, 14 * 12 * 2); /* ahead 336 lines */ + + if( MODEL_OP_A3I == ps->sCaps.Model ) { + + motorP96PositionYProc( ps, 80 ); + + } else { + /* forward 24 + pScanData->wOverBlue lines */ + if (!ps->fColorMoreRedFlag) + motorP96PositionYProc( ps, ps->wOverBlue + 12 * 2); + } + + if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) { + ps->Scan.fMotorBackward = _FALSE; + ps->bExtraMotorCtrl = ps->IgnorePF; + MotorP96ConstantMoveProc( ps, 1200 ); + } + + IOCmdRegisterToScanner( ps, ps->RegModelControl, + ps->AsicReg.RD_ModelControl ); + return _TRUE; +} + +/*............................................................................. + * + */ +static void motorP96FillHalfStepTable( pScanData ps ) +{ +#ifdef _A3I_EN + if ( ps->Scan.bModuleState == _MotorInStopState ) { + + /* clear the table and get the step value */ + memset( a_bHalfStepTable, 0, _NUMBER_OF_SCANSTEPS ); + ps->bMotorStepTableNo = a_bMotorDown2Table[(ps->bMotorSpeedData-1)/2]; + } + + /* the fastest stepping */ + if( ps->bMotorSpeedData & 1 ) { + + memset( a_bHalfStepTable, + ((ps->Scan.bModuleState != _MotorInStopState) ? 1 : 0), + _NUMBER_OF_SCANSTEPS ); + } else { + + pUChar pbHalfStepTbl; + Byte bHalfSteps; + pUShort pwMoveStep; + DataType Data; + + bHalfSteps = ps->bMotorSpeedData / 2; + pwMoveStep = &a_wMoveStepTable[ps->bCurrentLineCount]; + pbHalfStepTbl = &a_bHalfStepTable[ps->bCurrentLineCount]; + + if( ps->DataInf.wAppDataType == COLOR_TRUE24) + Data.dwValue = _NUMBER_OF_SCANSTEPS - 1; + else + Data.dwValue = _NUMBER_OF_SCANSTEPS; + + /* FillDataToHalfStepTable */ + for(; Data.dwValue; Data.dwValue-- ) { + + if( *pwMoveStep ) { /* need to exposure */ + + if( Data.bValue >= bHalfSteps ) { + + pUChar pb = pbHalfStepTbl + bHalfSteps; + + /* AdjustHalfStepStart */ + if( ps->DataInf.wAppDataType == COLOR_TRUE24 ) { + + if (bHalfSteps >= 2) + pb -= (bHalfSteps - 1); + } + if( pb >= pbEndHalfStepTable ) + pb -= _NUMBER_OF_SCANSTEPS; + + if( wP96BaseDpi <= ps->PhysicalDpi && *pwMoveStep != 2 ) + *pb = 1; + + pb += bHalfSteps; + + if( pb >= pbEndHalfStepTable ) + pb -= _NUMBER_OF_SCANSTEPS; + + *pb = 1; + } + else + *pwMoveStep = 0; /* idle state */ + } + if( ++pwMoveStep >= pwEndMoveStepTable ) { + pwMoveStep = a_wMoveStepTable; + + pbHalfStepTbl = a_bHalfStepTable; + } + else + pbHalfStepTbl++; + } + } + +#else + +#ifdef DEBUG + if( 0 == wP96BaseDpi ) + DBG( DBG_HIGH, "!!!! WARNING - motorP96FillHalfStepTable(), " + "wP96BaseDpi == 0 !!!!\n" ); +#endif + + if ( ps->Scan.bModuleState == _MotorInStopState ) { + + /* clear the table and get the step value */ + memset( a_bHalfStepTable, 0, _NUMBER_OF_SCANSTEPS ); + ps->bMotorStepTableNo = a_bMotorDown2Table[(ps->bMotorSpeedData-1)/2]; + } + + /* the fastest stepping */ + if( ps->bMotorSpeedData & 1 ) { + + memset( a_bHalfStepTable, + ((ps->Scan.bModuleState != _MotorInStopState) ? 1 : 0), + _NUMBER_OF_SCANSTEPS ); + } else { + + pUChar pbHalfStepTbl, pbHalfStepContent; + pUShort pwMoveStep; + DataType Data; + + pbHalfStepContent = a_pbHalfStepTables[ps->bMotorSpeedData / 2 - 1]; + + pwMoveStep = &a_wMoveStepTable[ps->bCurrentLineCount]; + pbHalfStepTbl = &a_bHalfStepTable[ps->bCurrentLineCount]; + + if (ps->DataInf.wAppDataType == COLOR_TRUE24) + Data.dwValue = _NUMBER_OF_SCANSTEPS - 1; + else + Data.dwValue = _NUMBER_OF_SCANSTEPS; + + /* FillDataToHalfStepTable */ + for (; Data.dwValue; Data.dwValue--) { + + if (*pwMoveStep) { /* need to exposure */ + + if (Data.bValue >= *pbHalfStepContent) { + + pUChar pb = pbHalfStepTbl + *pbHalfStepContent; + + if (pb >= pbEndHalfStepTable) + pb -= _NUMBER_OF_SCANSTEPS; + + /* JudgeStep1 () */ + if ((wP96BaseDpi != 600) && (*pwMoveStep != 2)) { + if (ps->Scan.bModuleState != _MotorInStopState) { + *pb = 1; + } else { + if (ps->bMotorStepTableNo) { + ps->bMotorStepTableNo--; + *pb = 1; + } + } + } + + pb += *pbHalfStepContent; + if (pb >= pbEndHalfStepTable) + pb -= _NUMBER_OF_SCANSTEPS; + + /* JudgeStep2 () */ + if (ps->Scan.bModuleState == _MotorInStopState) { + if (ps->bMotorStepTableNo) { + ps->bMotorStepTableNo--; + *pb = 1; + } + } else { + *pb = 1; + } + + pbHalfStepContent++; + } else { + *pwMoveStep = 0; /* idle state */ + } + } + + if (++pwMoveStep >= pwEndMoveStepTable) { + pwMoveStep = a_wMoveStepTable; + pbHalfStepTbl = a_bHalfStepTable; + } else { + pbHalfStepTbl++; + } + } + } +#endif +} + +/*............................................................................. + * + */ +static void motorP96FillDataToColorTable( pScanData ps, + Byte bIndex, ULong dwSteps) +{ + Byte bColor, bColors; + pUChar pb, pb1; + pUShort pw; + DataType Data; + + for (pb = &a_bColorByteTable[bIndex], + pw = &a_wMoveStepTable[bIndex]; dwSteps; dwSteps--) { + + if (*pw) { /* valid state */ + + if( *pw >= ps->BufferForColorRunTable ) { + DBG( DBG_LOW, "*pw = %u > %u !!\n", + *pw, ps->BufferForColorRunTable ); + } else { + + bColor = ps->pColorRunTable [*pw]; /* get the colors */ + bColors = a_bColorsSum [bColor & 7];/* number of colors */ + + if (bColors) { /* need to read data */ + if (dwSteps >= bColors) { /* enough room */ + + /* separate the colors to byte */ + pb1 = pb; + if (bColor & ps->b1stColor) { + + *pb1 = ps->b1stColorByte; + if (++pb1 >= pbEndColorByteTable) + pb1 = a_bColorByteTable; + } + + if (bColor & ps->b2ndColor) { + + *pb1 = ps->b2ndColorByte; + if (++pb1 >= pbEndColorByteTable) + pb1 = a_bColorByteTable; + } + + if (bColor & ps->b3rdColor) + *pb1 = ps->b3rdColorByte; + } else + *pw = 0; + } + } + } + + if (++pw >= pwEndMoveStepTable) { + pw = a_wMoveStepTable; + pb = a_bColorByteTable; + } else + pb++; + } + +/* ps->bOldSpeed = ps->bMotorRunStatus; non functional */ + + /* ToCondense, CondenseColorByteTable */ + for (dwSteps = _SCANSTATE_BYTES, pw = (pUShort)a_bColorByteTable, + pb = ps->a_nbNewAdrPointer; dwSteps; dwSteps--, pw++, pb++) { + + Data.wValue = *pw & 0x0303; + *pb = Data.wOverlap.b1st | (Data.wOverlap.b2nd << 4); + } + + /* ToCondenseMotor */ + for (dwSteps = _SCANSTATE_BYTES, pb1 = a_bHalfStepTable, + pb = ps->a_nbNewAdrPointer; dwSteps; dwSteps--, pb1++, pb++) { + + if (*pb1++) + *pb |= 4; + + if (*pb1) + *pb |= 0x40; + } +} + +/*............................................................................. + * + */ +static void motorP96FillBackColorDataTable( pScanData ps ) +{ + Byte bIndex; + ULong dw; + + if ((ps->bCurrentLineCount + ps->bNewCurrentLineCountGap + 1) >= + _NUMBER_OF_SCANSTEPS){ + bIndex = ps->bCurrentLineCount + ps->bNewCurrentLineCountGap + 1 - + _NUMBER_OF_SCANSTEPS; + } else { + bIndex = ps->bCurrentLineCount + ps->bNewCurrentLineCountGap + 1; + } + dw = _NUMBER_OF_SCANSTEPS - ps->bNewCurrentLineCountGap; + + motorP96FillDataToColorTable( ps, bIndex, dw ); +} + +/*............................................................................. + * i/p: + * pScanStep = pScanData->pColorRunTable if forward, a_bScanStateTable if backward + * dwState = how many states is requested to process + * NOTE: + * The content of pScanStep contain: + * 0: Idle state + * 0xff: End mark + * others: The motor speed value + */ +static void motorP96FillBackLoop( pScanData ps, + pUChar pScanStep, ULong dwStates ) +{ + for (; dwStates; dwStates--) { + + if (*pScanStep == 0xff) + break; /* end of states */ + + if (*pScanStep) { + if (*pScanStep == 1) { /* speed == 1, this state has to step */ + + if (ps->dwScanStateCount & 1) + ps->a_nbNewAdrPointer[ps->dwScanStateCount / 2] |= 0x40; + else + ps->a_nbNewAdrPointer[ps->dwScanStateCount / 2] |= 0x04; + } + + *pScanStep -= 1; /* speed decrease by 1 */ + + if (!(*pScanStep)) + pScanStep++; /* state processed */ + } else + pScanStep++; /* skip this state */ + + if (++ps->dwScanStateCount == _NUMBER_OF_SCANSTEPS) + ps->dwScanStateCount = 0; /* reset to begin */ + } + + if (*pScanStep != 0xff) + ps->fFullLength = _FALSE; + else + ps->fFullLength = _TRUE; + + IOSetToMotorStepCount( ps ); /* put all scan states to ASIC */ +} + +/*............................................................................. + * 1) Clear scan states + * 2) Adjust the new scan state + */ +static void motorP96FillRunNewAdrPointer( pScanData ps ) +{ + ScanState sState; + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES); + + IOGetCurrentStateCount( ps, &sState ); + + if (sState.bStep < ps->bOldStateCount ) + sState.bStep += _NUMBER_OF_SCANSTEPS;/* over table (table just can */ + /* holds 64 step, then reset to */ + /* 0, so if less than means over*/ + /* the table) */ + + sState.bStep -= ps->bOldStateCount; /* how many states passed */ + ps->pScanState += sState.bStep; + + /* + * if current state != no stepped or stepped a cycle, fill the table with + * 1 in NOT STEPPED length. (1 means to this state has to be processing). + */ + if (sState.bStep && sState.bStep != (_NUMBER_OF_SCANSTEPS - 1)) + memset( ps->pScanState, 1, _NUMBER_OF_SCANSTEPS - sState.bStep - 1 ); + + IOGetCurrentStateCount( ps, &sState); + ps->bOldStateCount = sState.bStep; /* update current state */ + ps->dwScanStateCount = (ULong)((sState.bStep + 1) & (_NUMBER_OF_SCANSTEPS - 1)); + + /* fill begin at next step */ + motorP96FillBackLoop( ps, ps->pScanState, (_NUMBER_OF_SCANSTEPS - 1)); +} + +/*............................................................................. + * + */ +static void motorP96SetupRunTable( pScanData ps ) +{ + Short siSum; + UShort wLoop; + UShort wLengthY; + DataPointer p; + + DBG( DBG_LOW, "motorP96SetupRunTable()\n" ); + + /* SetMaxDpiAndLength (ps) */ +#ifdef _A3I_EN + if( ps->DataInf.xyPhyDpi.y > ps->PhysicalDpi ) { + + wLengthY = 6800 * 2; + wP96BaseDpi = ps->PhysicalDpi *2; + } else { + wLengthY = 6800; + wP96BaseDpi = ps->LensInf.rDpiY.wPhyMax >> 1; + } +#else + if( ps->DataInf.xyPhyDpi.y > (ps->LensInf.rDpiY.wPhyMax / 2)) { + + wLengthY = ps->LensInf.rExtentY.wMax << 1; + wP96BaseDpi = ps->LensInf.rDpiY.wPhyMax; + } else { + wLengthY = ps->LensInf.rExtentY.wMax; + wP96BaseDpi = ps->LensInf.rDpiY.wPhyMax >> 1; + } +#endif + + DBG( DBG_LOW, "wLengthY = %u, wP96BaseDpi = %u\n", wLengthY, wP96BaseDpi ); + + /* ClearColorRunTable (ps) */ + memset( ps->pColorRunTable, 0, ps->BufferForColorRunTable ); /*wLengthY + 0x60 ); */ + + p.pb = ps->pColorRunTable + _SCANSTATE_BYTES; +#ifdef _A3I_EN + wLoop = wLengthY + 200; +#else + wLoop = wLengthY + 0x20; +#endif + siSum = (Short)wP96BaseDpi; + + if (ps->DataInf.wPhyDataType != COLOR_TRUE24) { + for (; wLoop; wLoop--, p.pb++) { + if ((siSum -= (Short)ps->DataInf.xyPhyDpi.y) <= 0) { + siSum += (Short)wP96BaseDpi; + *p.pb = _COLORRUNTABLE_GREEN; + } + } + +#ifdef _A3I_EN + memset( ps->pColorRunTable + _NUMBER_OF_SCANSTEPS / 8 + wLengthY, + 0x77, 0x100 ); +#endif + } else { + /* CalColorRunTable */ + DataType Data; + + if (ps->fSonyCCD) { + + if((ps->sCaps.Model == MODEL_OP_12000P) || + (ps->sCaps.Model == MODEL_OP_A3I)) { + Data.wValue = (_COLORRUNTABLE_RED << 8) | _COLORRUNTABLE_BLUE; + } else { + Data.wValue = (_COLORRUNTABLE_GREEN << 8) | _COLORRUNTABLE_BLUE; + } + } else { + Data.wValue = (_COLORRUNTABLE_BLUE << 8) | _COLORRUNTABLE_GREEN; + } + + for (; wLoop; wLoop--, p.pb++) { + + if ((siSum -= (Short)ps->DataInf.xyPhyDpi.y) <= 0) { + siSum += (Short)wP96BaseDpi; + + if((ps->sCaps.Model == MODEL_OP_12000P)|| + (ps->sCaps.Model == MODEL_OP_A3I)) { + *p.pb |= _COLORRUNTABLE_GREEN; + } else { + *p.pb |= _COLORRUNTABLE_RED; + } + + /* Sony:Green,Toshiba:Blue */ + *(p.pb + 8) |= Data.wOverlap.b2nd; + *(p.pb + 16) |= Data.wOverlap.b1st; + } + } + +#ifdef _A3I_EN + memset( ps->pColorRunTable + _NUMBER_OF_SCANSTEPS / 8 + wLengthY, + 0x77, 0x100 ); +#endif + if (ps->DataInf.xyPhyDpi.y < 100) { + + Byte bColor; + + /* CheckColorTable () */ + if (ps->fSonyCCD) + Data.wValue = 0xdd22; + else + Data.wValue = 0xbb44; + + for (wLoop = wLengthY - _SCANSTATE_BYTES, + p.pb = ps->pColorRunTable + _SCANSTATE_BYTES; + wLoop; wLoop--, p.pb++) { + bColor = 0; + + switch (a_bColorsSum[*p.pb & 0x0f]) { + + case 3: + if (*(p.pb + 2)) + bColor = 1; + case 2: + if (*(p.pb + 1)) + bColor++; + if (bColor == 2) { + *p.pb &= ~_COLORRUNTABLE_RED; + *(p.pb - 2) = _COLORRUNTABLE_RED; + } + + if (bColor) { + if (*p.pb & ps->RedDataReady) { + *p.pb &= ~_COLORRUNTABLE_RED; + *(p.pb - 1) = _COLORRUNTABLE_RED; + } else { + *p.pb &= Data.wOverlap.b2nd; + *(p.pb - 1) = Data.wOverlap.b1st; + } + } + } + } + } + } +} + +/*............................................................................. + * + */ +static void motorP96UpdateDataCurrentReadLine( pScanData ps ) +{ + ScanState State1, State2; + TimerDef timer; + + IOGetCurrentStateCount( ps, &State1 ); + IOGetCurrentStateCount( ps, &State2 ); + + if (State1.bStatus == State2.bStatus) { + + if (!(State2.bStatus & _SCANSTATE_STOP)) { + + /* motor still running */ + if (State2.bStep < ps->bCurrentLineCount) { + State2.bStep = State2.bStep + _NUMBER_OF_SCANSTEPS - + ps->bCurrentLineCount; + } else + State2.bStep -= ps->bCurrentLineCount; + + if (State2.bStep >= (_NUMBER_OF_SCANSTEPS - 3)) { + + MiscStartTimer( &timer, _SECOND ); + + do { + State2.bStatus = IOGetScanState( ps, _FALSE ); + + } while (!(State2.bStatus & _SCANSTATE_STOP) && + !MiscCheckTimer( &timer )); + } else + if (State2.bStep < 40) + return; + } + +#ifdef _A3I_EN + if( ps->bFifoCount >= 140) { +#else + if( ps->bFifoCount >= 20) { +#endif + if( 1 == ps->bCurrentSpeed ) { + ps->bCurrentSpeed *= 2; + } else { + if( COLOR_TRUE24 == ps->DataInf.wPhyDataType ) + ps->bCurrentSpeed += 4; + else + ps->bCurrentSpeed += 2; + } + + MotorP96AdjustCurrentSpeed( ps, ps->bCurrentSpeed ); + } + + /* + * when using the full-step speed on 600 dpi models, then set + * the motor into half-step mode, to avoid that the scanner hits + * the back of its bed + */ +/* HEINER:A3I */ +#if 1 + if((600 == ps->PhysicalDpi) && (1 == ps->bCurrentSpeed)) { + + if( ps->Asic96Reg.RD_MotorControl & ps->FullStep ) { + ps->Asic96Reg.RD_MotorControl &= ~ps->FullStep; + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + ps->Asic96Reg.RD_MotorControl ); + } + } +#endif + ps->SetMotorSpeed( ps, ps->bCurrentSpeed, _TRUE ); + + IOSetToMotorRegister( ps); + } +} + +/*............................................................................. + * 1) Save the current scan state + * 2) Set the motor direction + */ +static void motorGoHalfStep1( pScanData ps ) +{ + ScanState sState; + + IOGetCurrentStateCount( ps, &sState ); + + ps->bOldStateCount = sState.bStep; + + motorSetRunPositionRegister(ps); + ps->pScanState = a_bScanStateTable; + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + ps->FillRunNewAdrPointer( ps ); + + while (!motorCheckMotorPresetLength(ps)) + motorP98FillRunNewAdrPointer1( ps ); + } else { + + while (!motorCheckMotorPresetLength( ps )) + ps->FillRunNewAdrPointer( ps ); + } +} + +/*............................................................................. + * when loosing data, we use this function to go back some lines and read them + * again... + */ +static void motorP96WaitBack( pScanData ps ) +{ + DataPointer p; + DataType Data; + ULong dw; + UShort w; + UShort wStayMaxStep; + + /* FindMaxMoveStepIndex () */ + + p.pw = a_wMoveStepTable; + + for( Data.dwValue = _NUMBER_OF_SCANSTEPS, wStayMaxStep = 1; Data.dwValue; + Data.dwValue--, p.pw++ ) + if( *p.pw > wStayMaxStep ) + wStayMaxStep = *p.pw; /* save the largest step number */ + + if( ps->DataInf.xyPhyDpi.y > ps->PhysicalDpi ) + wStayMaxStep -= 40; + else + wStayMaxStep -= 20; + + IORegisterDirectToScanner( ps, ps->RegInitDataFifo ); + + memset( a_bScanStateTable, 1, _P96_BACKMOVES ); + memset(&a_bScanStateTable[_P96_BACKMOVES], 0xff, 250 - _P96_BACKMOVES ); + + ps->Scan.fMotorBackward = _TRUE; + motorGoHalfStep1( ps ); /* backward 130 lines */ + + _DODELAY(200); /* let the motor stable */ + + if( ps->DataInf.xyPhyDpi.y <= ps->PhysicalDpi ) { + if( ps->DataInf.wPhyDataType == COLOR_TRUE24 ) { + dw = _P96_FORWARDMOVES - 1; + } else { + dw = _P96_FORWARDMOVES - 2; + } + } else { + dw = _P96_FORWARDMOVES; + } + + memset( a_bScanStateTable, 1, dw ); + memset(&a_bScanStateTable[dw], 0xff, 250 - dw ); + + ps->Scan.fMotorBackward = _FALSE; + motorGoHalfStep1( ps ); /* move forward */ + + /* GetNowStepTable () */ + ps->bCurrentLineCount = IOGetScanState( ps, _FALSE ) & _SCANSTATE_MASK; + ps->bNewCurrentLineCountGap = 0; + + /* ClearColorByteTable () */ + memset( a_bColorByteTable, 0, _NUMBER_OF_SCANSTEPS ); + + /* ClearHalfStepTable () */ + memset( a_bHalfStepTable, 0, _NUMBER_OF_SCANSTEPS ); + + /* FillWaitMoveStepTable () */ + p.pw = &a_wMoveStepTable[((ps->bCurrentLineCount + 1) & 0x3f)]; + *p.pw = 1; + p.pw++; + + for(w = wStayMaxStep, Data.bValue = ps->bMotorSpeedData, dw = 60;dw;dw--) { + + if( p.pw >= pwEndMoveStepTable ) /* make sure pointer in range */ + p.pw = a_wMoveStepTable; + + if (--Data.bValue) + *p.pw = 0; /* don't step */ + else { + Data.bValue = ps->bMotorSpeedData; /* speed value */ + *p.pw = w; /* the ptr to pColorRunTable */ + w++; /* pointer++ */ + } + + p.pw++; /* to next entry */ + } + motorP96FillHalfStepTable( ps ); + motorP96FillBackColorDataTable( ps ); +} + +/*............................................................................. + * when loosing data, we use this function to go back some lines and read them + * again... + */ +static void motorP98WaitBack( pScanData ps ) +{ + DataPointer p; + DataType Data; + ULong dw; + UShort w; + UShort wStayMaxStep; + UShort back, forward; + + p.pw = &a_wMoveStepTable[ps->bCurrentLineCount]; + + if (0 == *p.pw) { + + for (w = _NUMBER_OF_SCANSTEPS; w && !*p.pw; w--) { + p.pw--; + if (p.pw < a_wMoveStepTable) + p.pw = &a_wMoveStepTable[_NUMBER_OF_SCANSTEPS - 1]; + } + wStayMaxStep = *p.pw + 1; + } else { + wStayMaxStep = *p.pw; /* save the largest step number */ + } + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + forward = _P98_FORWARDMOVES; + back = _P98_BACKMOVES; + } else { + forward = _P96_FORWARDMOVES; + back = _P96_BACKMOVES; + } + + /* + * Off to avoid the problem of block data re-read/lost + */ + memset( a_bScanStateTable, 1, back ); + memset( &a_bScanStateTable[back], 0xff, (_SCANSTATE_TABLE_SIZE - back)); + ps->Scan.fMotorBackward = _TRUE; + motorGoHalfStep1( ps ); + + _DODELAY(200); /* let the motor stable */ + + memset(a_bScanStateTable, 1, forward ); + memset(&a_bScanStateTable[forward], 0xff, (_SCANSTATE_TABLE_SIZE-forward)); + ps->Scan.fMotorBackward = _FALSE; + motorGoHalfStep1( ps ); + + ps->bNewCurrentLineCountGap = 0; + + memset( a_bColorByteTable, 0, _NUMBER_OF_SCANSTEPS ); + memset( a_bHalfStepTable, 0, _NUMBER_OF_SCANSTEPS ); + + ps->bCurrentLineCount = (ps->bCurrentLineCount + 1) & 0x3f; + + p.pw = &a_wMoveStepTable[ps->bCurrentLineCount]; + + for (w = wStayMaxStep, Data.bValue = ps->bMotorSpeedData, + dw = _NUMBER_OF_SCANSTEPS; dw; dw--) { + if (--Data.bValue) { + *p.pw = 0; /* don't step */ + } else { + + /* speed value */ + Data.bValue = ps->bMotorSpeedData; + *p.pw = w; /* the pointer to pColorRunTable*/ + w++; /* pointer++ */ + } + /* make sure pointer in range */ + if (++p.pw >= pwEndMoveStepTable) + p.pw = a_wMoveStepTable; + } + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + motorP98FillHalfStepTable( ps ); + motorP98FillBackColorDataTable( ps ); + } else { + motorP96FillHalfStepTable( ps ); + motorP96FillBackColorDataTable( ps ); + } +} + +/*............................................................................. + * + */ +static void motorFillMoveStepTable( pScanData ps, + UShort wIndex, Byte bStep, pUShort pw ) +{ + UShort w; + Byte b; + + if (++pw >= pwEndMoveStepTable ) + pw = a_wMoveStepTable; + + wIndex++; + + b = ps->bMotorSpeedData; + + for (w = _NUMBER_OF_SCANSTEPS - bStep; w; w--) { + if (b == 1) { + b = ps->bMotorSpeedData; + *pw = wIndex; + wIndex++; + } else { + b--; + *pw = 0; + } + if (++pw >= pwEndMoveStepTable) + pw = a_wMoveStepTable; + } + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + motorP98FillHalfStepTable( ps ); + else + motorP96FillHalfStepTable( ps ); + + if ((ps->bCurrentLineCount + 1) >= _NUMBER_OF_SCANSTEPS) { + b = ps->bCurrentLineCount + 1 - _NUMBER_OF_SCANSTEPS; + } else { + b = ps->bCurrentLineCount + 1; + } + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + motorP98FillDataToColorTable( ps, b, _NUMBER_OF_SCANSTEPS - 1); + else + motorP96FillDataToColorTable( ps, b, _NUMBER_OF_SCANSTEPS - 1); +} + +/*............................................................................. + * + */ +static void noMotorRunStatusStop( pScanData ps, Byte bScanState ) +{ + Byte b, b1, bCur; + pUShort pw; + pByte pb; + UShort w; + + ps->bCurrentLineCount = (bScanState & _SCANSTATE_MASK); + + ps->Scan.fRefreshState = _FALSE; + + IORegisterDirectToScanner( ps, ps->RegRefreshScanState ); + + bCur = ps->bCurrentLineCount; + pw = &a_wMoveStepTable[bCur]; + pb = ps->pColorRunTable; + b = 0; + b1 = 0; + w = _NUMBER_OF_SCANSTEPS; + + if (*pw) { + b = a_bColorsSum[pb [*pw] >> 4]; + if (b) { + motorClearColorByteTableLoop0( ps, b ); + ps->bNewCurrentLineCountGap = b; + + motorFillMoveStepTable( ps, *pw, 1, pw ); + return; + } + b1++; + bCur--; + + if (--pw < a_wMoveStepTable) { + pw = &a_wMoveStepTable [_NUMBER_OF_SCANSTEPS - 1]; + bCur = _NUMBER_OF_SCANSTEPS - 1; + } + } + + for(; w; w--) { + if (*pw) { + if (*pw < _SCANSTATE_BYTES) { + b = 0; + break; + } else + if ((b = a_bColorsSum [pb [*pw] >> 4])) + break; + } + b1++; + bCur--; + + if (--pw < a_wMoveStepTable) { + pw = &a_wMoveStepTable [_NUMBER_OF_SCANSTEPS - 1]; + bCur = _NUMBER_OF_SCANSTEPS - 1; + } + } + + if (b1 == _NUMBER_OF_SCANSTEPS) { + ps->bNewCurrentLineCountGap = 0; + ps->bNewGap = 0; + } else { + ps->bNewCurrentLineCountGap = b1; + ps->bNewGap = b; + } + + motorClearColorByteTableLoop1( ps ); + + motorFillMoveStepTable( ps, *pw, 0, pw); +} + +/*............................................................................. + * + */ +static void motorP96SetSpeed( pScanData ps, Byte bSpeed, Bool fSetRunState ) +{ +#if 0 + PUCHAR pb; + Byte bScanState; +#endif + Byte bState, bData; + UShort wMoveStep; + pUShort pw; + ULong dw; + TimerDef timer; + + if( fSetRunState ) + ps->Scan.bModuleState = _MotorInNormalState; + + ps->bMotorSpeedData = bSpeed; + + if( ps->bMoveDataOutFlag == _DataAfterRefreshState) { + + ps->bMoveDataOutFlag = _DataInNormalState; + + MiscStartTimer( &timer, (_SECOND /2)); + + while (!MiscCheckTimer(&timer)) { + if ((bState = IOGetScanState( ps, _FALSE)) & _SCANSTATE_STOP) { + ps->bCurrentLineCount = bState & ~_SCANSTATE_STOP; + motorP96WaitBack( ps ); + return; + } + } + } + + bState = IOGetScanState( ps, _FALSE ); + + if((ps->Scan.bModuleState != _MotorInStopState) || + !(bState & _SCANSTATE_STOP)) { + + /* Try to find the available step for all rest steps. + * 1) if current step is valid (with data request), fill all steps + * after it + * 2) if current step is NULL (for delay purpose), backward search the + * valid entry, then fill all steps after it + * 3) if no step is valid, fill all entries + */ + Byte bColors = 0; + UShort w; + + /* NoMotorRunStatusStop () */ + ps->bCurrentLineCount = (bState &= _SCANSTATE_MASK); + ps->Scan.fRefreshState = _TRUE; + + IORegisterDirectToScanner( ps, ps->RegRefreshScanState ); + + pw = &a_wMoveStepTable[bState]; + bData = 0; + bState = ps->bCurrentLineCount; + dw = _NUMBER_OF_SCANSTEPS; + + if( (wMoveStep = *pw) ) { + + bColors = a_bColorsSum[ ps->pColorRunTable[*pw] / 16]; + + if( bColors ) { + + motorClearColorByteTableLoop0( ps, bColors ); + ps->bNewCurrentLineCountGap = bColors; + bColors = 1; + goto FillMoveStepTable; + + } else { + + bData++; + dw--; + if( --pw < a_wMoveStepTable ) { + pw = a_wMoveStepTable + _NUMBER_OF_SCANSTEPS - 1; + bState = _NUMBER_OF_SCANSTEPS - 1; + } + else + bState--; + } + } + + /* FindNextStep */ + while( dw-- ) { + + if( (wMoveStep = *pw) ) { + if (wMoveStep < (_NUMBER_OF_SCANSTEPS / 2)) { + bColors = 0; + break; + } + if((bColors = a_bColorsSum [ps->pColorRunTable[wMoveStep] / 16])) + break; + } + + bData++; + if( --pw < a_wMoveStepTable ) { + pw = a_wMoveStepTable + _NUMBER_OF_SCANSTEPS - 1; + bState = _NUMBER_OF_SCANSTEPS - 1; + } + else + bState--; + } + + if (bData == _NUMBER_OF_SCANSTEPS ) + bData = bColors = 0; + + ps->bNewCurrentLineCountGap = bData; + ps->bNewGap = bColors; + motorClearColorByteTableLoop1( ps ); + bColors = 0; + + /* use pw (new pointer) and new speed to recreate MoveStepTable + * wMoveStep = Index number from a_wMoveStepTable ([esi]) + * bColors = number of steps should be reserved + * pw = where to fill + */ + +FillMoveStepTable: + + motorP96GetStartStopGap( ps, _TRUE ); + + if( !ps->bMotorStepTableNo ) + ps->bMotorStepTableNo = 1; + + if( ps->bMotorStepTableNo != 0xff && ps->IO.portMode == _PORT_SPP && + ps->DataInf.xyPhyDpi.y <= 200) { + ps->bMotorStepTableNo++; + } + + if (++pw >= pwEndMoveStepTable) + pw = a_wMoveStepTable; + + for( dw = _NUMBER_OF_SCANSTEPS - bColors, wMoveStep++, + bData = ps->bMotorSpeedData; dw; dw-- ) { + if( bData == 1 ) { + + bData = ps->bMotorSpeedData; + if( ps->bMotorStepTableNo ) { + + ps->bMotorStepTableNo--; + w = wMoveStep; + wMoveStep++; + + } else { + bData--; + w = 0; + } + } else { + bData--; + w = 0; + } + *pw = w; + + if (++pw >= pwEndMoveStepTable) + pw = a_wMoveStepTable; + } + + motorP96FillHalfStepTable( ps ); + + /* FillColorBytesTable */ + if((ps->bCurrentLineCount + 1) < _NUMBER_OF_SCANSTEPS ) + bState = ps->bCurrentLineCount + 1; + else + bState = ps->bCurrentLineCount + 1 - _NUMBER_OF_SCANSTEPS; + + motorP96FillDataToColorTable( ps, bState, _NUMBER_OF_SCANSTEPS - 1); + } +} + +/*............................................................................. + * + */ +static void motorP98SetSpeed( pScanData ps, Byte bSpeed, Bool fSetRunState ) +{ + static Byte lastFifoState = 0; + + Bool overflow; + Byte bOld1ScanState, bData; + + if( fSetRunState ) + ps->Scan.bModuleState = _MotorInNormalState; + + ps->bMotorSpeedData = bSpeed; + overflow = _FALSE; + + if( _ASIC_IS_98001 != ps->sCaps.AsicID ) { + ps->bMoveDataOutFlag = _DataInNormalState; + + bData = IODataRegisterFromScanner( ps, ps->RegFifoOffset ); + + if((lastFifoState > _P96_FIFOOVERFLOWTHRESH) && + (bData < lastFifoState)) { + DBG( DBG_HIGH, "FIFO OVERFLOW, loosing data !!\n" ); + overflow = _TRUE; + } + lastFifoState = bData; + } + + bOld1ScanState = IOGetScanState( ps, _FALSE ); + + if(!(bOld1ScanState & _SCANSTATE_STOP) && !overflow) + noMotorRunStatusStop( ps, bOld1ScanState ); + else { + ps->bCurrentLineCount = (bOld1ScanState & 0x3f); + ps->Scan.bModuleState = _MotorGoBackward; + + motorP98WaitBack( ps ); + + if( overflow ) + lastFifoState = 0; + + if( _ASIC_IS_98001 != ps->sCaps.AsicID ) + ps->bMoveDataOutFlag = _DataFromStopState; + } +} + +/*............................................................................. + * + */ +static void motorP98003ModuleFreeRun( pScanData ps, ULong steps ) +{ + IODataToRegister( ps, ps->RegMotorFreeRunCount1, (_HIBYTE(steps))); + IODataToRegister( ps, ps->RegMotorFreeRunCount0, (_LOBYTE(steps))); + IORegisterToScanner( ps, ps->RegMotorFreeRunTrigger ); +} + +/*............................................................................. + * + */ +static void motorP98003ModuleToHome( pScanData ps ) +{ + if(!(IODataFromRegister( ps, ps->RegStatus ) & _FLAG_P98_PAPER)) { + + IODataToRegister( ps, ps->RegMotor0Control, + (Byte)(ps->AsicReg.RD_Motor0Control|_MotorDirForward)); + + MotorP98003PositionYProc( ps, 40 ); + MotorP98003BackToHomeSensor( ps ); + _DODELAY( 250 ); + } +} + +/*............................................................................. + * + */ +static void motorP98003DownloadNullScanStates( pScanData ps ) +{ + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + IODownloadScanStates( ps ); +} + +/*............................................................................. + * + */ +static void motorP98003Force16Steps( pScanData ps ) +{ + ULong dw; + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_ONESTEP); + IODataToRegister( ps, ps->RegMotor0Control, _FORWARD_MOTOR ); + + for(dw = 16; dw; dw--) { + IORegisterToScanner( ps, ps->RegForceStep ); + _DODELAY( 10 ); + } + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_SCANSTATE ); +} + +/*............................................................................. + * + */ +static void motorP98003WaitForPositionY( pScanData ps ) +{ + Byte bXStep; + ULong dwBeginY; + + dwBeginY = (ULong)ps->DataInf.crImage.y * 4 + ps->Scan.dwScanOrigin; + + if( ps->DataInf.wPhyDataType <= COLOR_256GRAY ) { + if( ps->Device.f0_8_16 ) + dwBeginY += 16; + else + dwBeginY += 8; + } + + bXStep = (Byte)((ps->DataInf.wPhyDataType <= COLOR_256GRAY) ? + ps->Device.XStepMono : ps->Device.XStepColor); + + if( ps->Shade.bIntermediate & _ScanMode_AverageOut ) + bXStep = 8; + + motorP98003Force16Steps( ps); + dwBeginY -= 16; + + if (dwBeginY > (_RFT_SCANNING_ORG + _P98003_YOFFSET) && + bXStep < ps->AsicReg.RD_XStepTime) { + + IODataToRegister( ps, ps->RegMotorDriverType, ps->Scan.motorPower ); + _DODELAY( 12 ); + IODataToRegister( ps, ps->RegXStepTime, bXStep); + IODataToRegister( ps, ps->RegExtendedXStep, 0 ); + IODataToRegister( ps, ps->RegScanControl1, + (UChar)(ps->AsicReg.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE)); + MotorP98003PositionYProc( ps, dwBeginY - 64 ); + dwBeginY = 64; + } + + IODataToRegister( ps, ps->RegFifoFullLength0, _LOBYTE(ps->AsicReg.RD_BufFullSize)); + IODataToRegister( ps, ps->RegFifoFullLength1, _HIBYTE(ps->AsicReg.RD_BufFullSize)); + IODataToRegister( ps, ps->RegFifoFullLength2, _LOBYTE(_HIWORD(ps->AsicReg.RD_BufFullSize))); + + IODataToRegister( ps, ps->RegMotorDriverType, ps->AsicReg.RD_MotorDriverType); + _DODELAY( 12 ); + + if(!ps->Device.f2003 || (ps->Shade.bIntermediate & _ScanMode_AverageOut) || + ( ps->DataInf.xyAppDpi.y <= 75 && + ps->DataInf.wPhyDataType <= COLOR_256GRAY)) { + IODataToRegister( ps, ps->RegMotorDriverType, + (Byte)(ps->Scan.motorPower & (_MOTORR_MASK | _MOTORR_STRONG))); + } else { + IODataToRegister( ps, ps->RegMotorDriverType, + ps->AsicReg.RD_MotorDriverType ); + } + + IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime ); + IODataToRegister( ps, ps->RegExtendedXStep, ps->AsicReg.RD_ExtXStepTime ); + IODataToRegister( ps, ps->RegScanControl1, + (Byte)(ps->AsicReg.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE)); + + if( ps->DataInf.dwVxdFlag & _VF_PREVIEW ) { + + TimerDef timer; + + motorP98003ModuleFreeRun( ps, dwBeginY ); + _DODELAY( 15 ); + + MiscStartTimer( &timer, (_SECOND * 20)); + + while(( IOGetExtendedStatus( ps ) & _STILL_FREE_RUNNING) && + !MiscCheckTimer(&timer)); + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + } else { + MotorP98003PositionYProc( ps, dwBeginY ); + IORegisterToScanner( ps, ps->RegRefreshScanState ); + } +} + +/*............................................................................. + * move the sensor to the appropriate shading position + */ +static Bool motorP98003GotoShadingPosition( pScanData ps ) +{ + motorP98003ModuleToHome( ps ); + + /* position to somewhere under the transparency adapter */ + if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) { + + MotorP98003ForceToLeaveHomePos( ps ); + motorP98003DownloadNullScanStates( ps ); + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_SCANSTATE ); + IODataToRegister( ps, ps->RegModeControl, _ModeScan); + IODataToRegister( ps, ps->RegMotor0Control, _FORWARD_MOTOR ); + IODataToRegister( ps, ps->RegXStepTime, 6); + IODataToRegister( ps, ps->RegExtendedXStep, 0); + IODataToRegister( ps, ps->RegScanControl1, _MFRC_BY_XSTEP); + + MotorP98003PositionYProc( ps, _TPA_P98003_SHADINGORG ); + } + + return _TRUE; +} + +/*............................................................................. + * initialize this module and setup the correct function pointer according + * to the ASIC + */ +static void motorP98003PositionModuleToHome( pScanData ps ) +{ + Byte save, saveModel; + + saveModel = ps->AsicReg.RD_ModelControl; + + ps->Scan.fRefreshState = _FALSE; + motorP98003DownloadNullScanStates( ps ); + + _DODELAY( 1000UL / 8UL); + + save = ps->Shade.bIntermediate; + + ps->Shade.bIntermediate = _ScanMode_AverageOut; + ps->ReInitAsic( ps, _FALSE ); + ps->Shade.bIntermediate = save; + + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + IORegisterToScanner( ps, ps->RegResetMTSC ); + IODataToRegister( ps, ps->RegScanControl1, 0 ); + + IODataToRegister( ps, ps->RegModelControl, + ps->Device.ModelCtrl | _ModelDpi300 ); + + IODataToRegister( ps, ps->RegLineControl, 80); + IODataToRegister( ps, ps->RegXStepTime, ps->Device.XStepBack); + IODataToRegister( ps, ps->RegMotorDriverType, ps->Scan.motorPower); + + _DODELAY( 12 ); + + IODataToRegister( ps, ps->RegMotor0Control, + (_MotorHHomeStop | _MotorOn | _MotorHQuarterStep | + _MotorPowerEnable)); + IODataToRegister( ps, ps->RegStepControl, + (_MOTOR0_SCANSTATE | _MOTOR_FREERUN)); + + memset( ps->a_nbNewAdrPointer, 0x88, _SCANSTATE_BYTES ); + IODownloadScanStates( ps ); + IORegisterToScanner( ps, ps->RegRefreshScanState ); + + ps->AsicReg.RD_ModelControl = saveModel; +} + +/************************ exported functions *********************************/ + +/*............................................................................. + * initialize this module and setup the correct function pointer according + * to the ASIC + */ +_LOC int MotorInitialize( pScanData ps ) +{ + DBG( DBG_HIGH, "MotorInitialize()\n" ); + + if( NULL == ps ) + return _E_NULLPTR; + + ps->a_wMoveStepTable = a_wMoveStepTable; + ps->a_bColorByteTable = a_bColorByteTable; + wP96BaseDpi = 0; + + ps->PauseColorMotorRunStates = motorPauseColorMotorRunStates; + + /* + * depending on the asic, we set some functions + */ + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + ps->WaitForPositionY = motorP98WaitForPositionY; + ps->GotoShadingPosition = motorP98GotoShadingPosition; + ps->FillRunNewAdrPointer = motorP98FillRunNewAdrPointer; + ps->SetupMotorRunTable = motorP98SetupRunTable; + ps->UpdateDataCurrentReadLine = motorP98UpdateDataCurrentReadLine; + ps->SetMotorSpeed = motorP98SetSpeed; + + } else if( _ASIC_IS_98003 == ps->sCaps.AsicID ) { + + ps->WaitForPositionY = motorP98003WaitForPositionY; + ps->GotoShadingPosition = motorP98003GotoShadingPosition; + ps->SetMotorSpeed = motorP98SetSpeed; + + } else if( _IS_ASIC96(ps->sCaps.AsicID)) { + + ps->WaitForPositionY = motorP96WaitForPositionY; + ps->GotoShadingPosition = motorP96GotoShadingPosition; + ps->FillRunNewAdrPointer = motorP96FillRunNewAdrPointer; + ps->SetupMotorRunTable = motorP96SetupRunTable; + ps->UpdateDataCurrentReadLine = motorP96UpdateDataCurrentReadLine; + ps->SetMotorSpeed = motorP96SetSpeed; + + } else { + + DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" ); + return _E_NOSUPP; + } + return _OK; +} + +/*............................................................................. + * + */ +_LOC void MotorSetConstantMove( pScanData ps, Byte bMovePerStep ) +{ + DataPointer p; + ULong dw; + + p.pb = ps->a_nbNewAdrPointer; + + switch( bMovePerStep ) + { + case 0: /* doesn't move at all */ + for (dw = _NUMBER_OF_SCANSTEPS / 8; dw; dw--, p.pdw++) { + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + *p.pdw &= 0x77777777; + else + *p.pdw &= 0xbbbbbbbb; + } + break; + + case 1: + for (dw = _NUMBER_OF_SCANSTEPS / 8; dw; dw--, p.pdw++) { + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + *p.pdw |= 0x88888888; + else + *p.pdw |= 0x44444444; + } + break; + + case 2: + for (dw = _NUMBER_OF_SCANSTEPS / 8; dw; dw--, p.pdw++) { + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + *p.pdw |= 0x80808080; + else + *p.pdw |= 0x40404040; + } + break; + + default: + { + Byte bMoves = bMovePerStep; + + for (dw = _SCANSTATE_BYTES; dw; dw--, p.pb++) { + if (!(--bMoves)) { + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + *p.pb |= 8; + else + *p.pb |= 4; + bMoves = bMovePerStep; + } + if (!(--bMoves)) { + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) + *p.pb |= 0x80; + else + *p.pb |= 0x40; + bMoves = bMovePerStep; + } + } + } + } + IOSetToMotorRegister( ps ); +} + +/*............................................................................. + * function to bring the sensor back home + */ +_LOC void MotorToHomePosition( pScanData ps ) +{ + TimerDef timer; + ScanState StateStatus; + + DBG( DBG_HIGH, "Waiting for Sensor to be back in position\n" ); + _DODELAY( 250 ); + + if( _ASIC_IS_98001 == ps->sCaps.AsicID ) { + + if (!(IODataRegisterFromScanner(ps,ps->RegStatus) & _FLAG_P98_PAPER)){ + ps->GotoShadingPosition( ps ); + } + } else if( _ASIC_IS_98003 == ps->sCaps.AsicID ) { + + ps->OpenScanPath( ps ); + + if( !(IODataFromRegister( ps, ps->RegStatus ) & _FLAG_P98_PAPER)) { + + motorP98003PositionModuleToHome( ps ); + + MiscStartTimer( &timer, _SECOND * 20); + do { + + if( IODataFromRegister( ps, ps->RegStatus ) & _FLAG_P98_PAPER) + break; + } while( !MiscCheckTimer( &timer)); + } + ps->CloseScanPath( ps ); + + } else { + + if( ps->sCaps.Model >= MODEL_OP_9630P ) { + if( ps->sCaps.Model == MODEL_OP_A3I ) + IOCmdRegisterToScanner( ps, ps->RegLineControl, 0x34 ); + else + IOCmdRegisterToScanner( ps, ps->RegLineControl, 0x30 ); + } + + ps->bExtraMotorCtrl = 0; + ps->Scan.fMotorBackward = _FALSE; + MotorP96ConstantMoveProc( ps, 25 ); + + ps->Scan.fMotorBackward = _TRUE; + for(;;) { + + motorP96GetScanStateAndStatus( ps, &StateStatus ); + + if ( StateStatus.bStatus & _FLAG_P96_PAPER ) { + break; + } + + MotorP96ConstantMoveProc( ps, 50000 ); + } + + ps->Scan.fMotorBackward = _FALSE; + ps->Asic96Reg.RD_MotorControl = 0; + IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 ); + + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + IOSetToMotorRegister( ps ); + _DODELAY(250); + + ps->Asic96Reg.RD_LedControl = 0; + IOCmdRegisterToScanner(ps, ps->RegLedControl, ps->Asic96Reg.RD_LedControl); + } + + DBG( DBG_HIGH, "- done !\n" ); +} + +/*............................................................................. + * + */ +_LOC void MotorP98GoFullStep( pScanData ps, ULong dwStep ) +{ + memset( ps->pColorRunTable, 1, dwStep ); + memset( ps->pColorRunTable + dwStep, 0xff, 0x40); + + ps->bOldStateCount = IOGetScanState( ps, _FALSE ) & _SCANSTATE_MASK; + motorP98SetRunFullStep( ps ); + + ps->pScanState = ps->pColorRunTable; + ps->FillRunNewAdrPointer( ps ); + + while(!motorCheckMotorPresetLength( ps )) + motorP98FillRunNewAdrPointer1( ps ); +} + +/*............................................................................. + * + */ +_LOC void MotorP96SetSpeedToStopProc( pScanData ps ) +{ + Byte bData; + TimerDef timer; + + MiscStartTimer( &timer, _SECOND); + while( !MiscCheckTimer( &timer )) { + + bData = IODataRegisterFromScanner( ps, ps->RegFifoOffset ); + + if ((bData > ps->bMinReadFifo) && (bData != ps->bFifoCount)) + break; + } + bData = IOGetScanState( ps, _FALSE ); + + if (!(bData & _SCANSTATE_STOP)) { + + MiscStartTimer( &timer, (_SECOND / 2)); + + while (!MiscCheckTimer( &timer )) { + + if (IOGetScanState( ps, _FALSE) != bData ) + break; + } + } + + ps->Scan.bModuleState = _MotorInStopState; + ps->SetMotorSpeed( ps, ps->bCurrentSpeed, _FALSE ); + + IOSetToMotorRegister( ps ); +} + +/*............................................................................. + * Position Scan Module to specified line number (Forward or Backward & wait + * for paper flag ON) + */ +_LOC void MotorP96ConstantMoveProc( pScanData ps, ULong dwLines ) +{ + Byte bRemainder, bLastState; + UShort wQuotient; + ULong dwDelayMaxTime; + ScanState StateStatus; + TimerDef timer; + Bool fTimeout = _FALSE; + + wQuotient = (UShort)(dwLines / _NUMBER_OF_SCANSTEPS); /* state cycles */ + bRemainder = (Byte)(dwLines % _NUMBER_OF_SCANSTEPS); + + /* 3.3 ms per line */ + dwDelayMaxTime = dwLines * _MOTOR_ONE_LINE_TIME + _SECOND * 2; + + MotorSetConstantMove( ps, 1 ); /* step every time */ + + ps->OpenScanPath( ps ); + + ps->AsicReg.RD_ModeControl = _ModeScan; + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + + if( ps->Scan.fMotorBackward ) { + ps->Asic96Reg.RD_MotorControl = (ps->MotorFreeRun | ps->MotorOn | + ps->FullStep | ps->bExtraMotorCtrl); + } else { + ps->Asic96Reg.RD_MotorControl = (ps->MotorFreeRun | ps->MotorOn | + _MotorDirForward | ps->bExtraMotorCtrl); + } + + IODataToRegister( ps, ps->RegMotorControl, ps->Asic96Reg.RD_MotorControl ); + ps->CloseScanPath( ps ); + + bLastState = 0; + + MiscStartTimer( &timer, dwDelayMaxTime ); + + do { + + motorP96GetScanStateAndStatus( ps, &StateStatus ); + + if( ps->Scan.fMotorBackward && (StateStatus.bStatus&_FLAG_P96_PAPER)) { + break; + } else { + + /* + * 1) Forward will not reach the sensor. + * 2) Backwarding, doesn't reach the sensor + */ + if (wQuotient) { + + /* stepped */ + if (StateStatus.bStep != bLastState) { + bLastState = StateStatus.bStep; + if (!bLastState) /* done a cycle! */ + wQuotient--; + } + } else { + if (StateStatus.bStep >= bRemainder) { + break; + } + } + } + + fTimeout = MiscCheckTimer( &timer ); + + } while ( _OK == fTimeout ); + + if ( _OK == fTimeout ) { + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + IOSetToMotorRegister( ps ); + } +} + +/*............................................................................. + * + */ +_LOC Bool MotorP96AheadToDarkArea( pScanData ps ) +{ + Byte bDark; + UShort wTL; + UShort wTotalLastLine; + TimerDef timer; + + ps->fColorMoreRedFlag = _FALSE; + ps->fColorMoreBlueFlag = _FALSE; + ps->wOverBlue = 0; + + /* FillToDarkCounter () */ + memset( ps->a_nbNewAdrPointer, 0x30, _SCANSTATE_BYTES); + MotorSetConstantMove( ps, 2 ); + + /* SetToDarkRegister () */ + ps->AsicReg.RD_ModeControl = _ModeScan; + ps->AsicReg.RD_ScanControl = ps->bLampOn | _SCAN_BYTEMODE; + ps->Asic96Reg.RD_MotorControl = _MotorDirForward | ps->FullStep; + ps->AsicReg.RD_ModelControl = ps->Device.ModelCtrl | _ModelWhiteIs0; + + ps->AsicReg.RD_Dpi = 300; + wTL = 296; +/* if( MODEL_OP_A3I == ps->sCaps.Model ) { */ + if( ps->PhysicalDpi > 300 ) { + wTL = 400; + ps->AsicReg.RD_Origin = (UShort)(ps->Offset70 + 64 + 8 + 2048); + } else { + ps->AsicReg.RD_Origin = (UShort)(ps->Offset70 + 64 + 8 + 1024); + } + ps->AsicReg.RD_Pixels = 512; + + IOPutOnAllRegisters( ps ); + + ps->Asic96Reg.RD_MotorControl = (ps->MotorFreeRun | ps->IgnorePF | + ps->MotorOn | _MotorDirForward ); + + IOCmdRegisterToScanner( ps, ps->RegMotorControl, + ps->Asic96Reg.RD_MotorControl ); + + MiscStartTimer( &timer, _SECOND * 2 ); + wTotalLastLine = 0; + +#ifdef _A3I_EN + while( !MiscCheckTimer( &timer )) { + + bDark = motorP96ReadDarkData( ps ); + + wTotalLastLine++; + if((bDark < 0x80) || (wTotalLastLine==wTL)) { + + IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 ); + return _TRUE; + } + } +#else + while (!MiscCheckTimer( &timer )) { + + bDark = motorP96ReadDarkData( ps ); + + wTotalLastLine++; + if (((ps->sCaps.AsicID == _ASIC_IS_96001) && (bDark > 0x80)) || + ((ps->sCaps.AsicID != _ASIC_IS_96001) && (bDark < 0x80)) || + (wTotalLastLine==wTL)) { + + IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeProgram ); + + if (wTotalLastLine <= 24) + ps->fColorMoreRedFlag = _TRUE; + else + if (wTotalLastLine >= 120) { + ps->wOverBlue = wTotalLastLine - 80; + ps->fColorMoreBlueFlag = _TRUE; + } + + return _TRUE; + } + } +#endif + + return _FALSE; /* already timed out */ +} + +/*............................................................................. + * limit the speed settings for 96001/3 based models + */ +_LOC void MotorP96AdjustCurrentSpeed( pScanData ps, Byte bSpeed ) +{ + if (bSpeed != 1) { + + if (bSpeed > 34) + ps->bCurrentSpeed = 34; + else + ps->bCurrentSpeed = (bSpeed + 1) & 0xfe; + } +} + +/*............................................................................. + * + */ +_LOC void MotorP98003ForceToLeaveHomePos( pScanData ps ) +{ + TimerDef timer; + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_ONESTEP ); + IODataToRegister( ps, ps->RegMotor0Control, _FORWARD_MOTOR ); + + MiscStartTimer( &timer, _SECOND ); + + do { + if( !(IODataFromRegister( ps, ps->RegStatus ) & _FLAG_P98_PAPER)) + break; + + IORegisterToScanner( ps, ps->RegForceStep ); + _DODELAY( 10 ); + + } while( _OK == MiscCheckTimer( &timer )); + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_SCANSTATE ); +} + +/*............................................................................. + * + */ +_LOC void MotorP98003BackToHomeSensor( pScanData ps ) +{ + TimerDef timer; + + DBG( DBG_HIGH, "MotorP98003BackToHomeSensor()\n" ); + + IODataToRegister( ps, ps->RegStepControl, _MOTOR0_SCANSTATE ); + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + + /* stepping every state */ + memset( ps->a_nbNewAdrPointer, 0x88, _SCANSTATE_BYTES ); + IODownloadScanStates( ps ); + + MiscStartTimer( &timer, _SECOND * 2 ); + + while(!(IOGetScanState( ps, _TRUE ) & _SCANSTATE_STOP) && + !MiscCheckTimer( &timer )); + + _DODELAY( 1000UL ); + + ps->AsicReg.RD_ModeControl = _ModeScan; + + if (!(ps->DataInf.dwScanFlag & SCANDEF_TPA)) { + IODataToRegister( ps, ps->RegLineControl, _LOBYTE(ps->Shade.wExposure)); + IODataToRegister( ps, ps->RegXStepTime, _LOBYTE(ps->Shade.wXStep)); + + } else { + IODataToRegister( ps, ps->RegLineControl, _DEFAULT_LINESCANTIME ); + IODataToRegister( ps, ps->RegXStepTime, 6); + } + + IODataToRegister( ps, ps->RegStepControl, + (_MOTOR_FREERUN | _MOTOR0_SCANSTATE)); + IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl ); + IODataToRegister( ps, ps->RegMotor0Control, + (_MotorHQuarterStep | _MotorOn | _MotorDirBackward | + _MotorPowerEnable | _MotorHHomeStop)); + IORegisterToScanner( ps, ps->RegRefreshScanState ); + + MiscStartTimer( &timer, _SECOND * 5 ); + + do { + if( IODataFromRegister( ps, ps->RegStatus ) & _FLAG_P98_PAPER ) + break; + + _DODELAY( 55 ); + + } while( !MiscCheckTimer( &timer )); + + IODataToRegister( ps, ps->RegLineControl, ps->AsicReg.RD_LineControl); + IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime); + + DBG( DBG_HIGH, "LineCtrl=%u, XStepTime=%u\n", + ps->AsicReg.RD_LineControl, ps->AsicReg.RD_XStepTime ); + + motorP98003DownloadNullScanStates( ps ); +} + +/*............................................................................. + * + */ +_LOC void MotorP98003ModuleForwardBackward( pScanData ps ) +{ + switch( ps->Scan.bModuleState ) { + + case _MotorInNormalState: + ps->Scan.bModuleState = _MotorGoBackward; + IODataToRegister( ps, ps->RegScanControl1, + (UChar)(ps->AsicReg.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE)); + IODataToRegister( ps, ps->RegMotor0Control, + (UChar)(ps->AsicReg.RD_Motor0Control & ~_MotorDirForward)); + motorP98003ModuleFreeRun( ps, _P98003_BACKSTEPS ); + MiscStartTimer( &p98003MotorTimer, (15 * _MSECOND)); + break; + + case _MotorGoBackward: + if( MiscCheckTimer(& p98003MotorTimer)) { + if (!(IOGetExtendedStatus( ps ) & _STILL_FREE_RUNNING )) { + ps->Scan.bModuleState = _MotorInStopState; + MiscStartTimer( &p98003MotorTimer, (50 *_MSECOND)); + } + } + break; + + case _MotorInStopState: + if( MiscCheckTimer(&p98003MotorTimer)) { + + if( IOReadFifoLength( ps ) < ps->Scan.dwMaxReadFifo ) { + ps->Scan.bModuleState = _MotorAdvancing; + IODataToRegister( ps, ps->RegScanControl1, ps->AsicReg.RD_ScanControl1); + IODataToRegister( ps, ps->RegMotor0Control, ps->AsicReg.RD_Motor0Control); + motorP98003ModuleFreeRun( ps, _P98003_FORWARDSTEPS ); + MiscStartTimer( &p98003MotorTimer, (15 * _MSECOND)); + } + } + break; + + case _MotorAdvancing: + if( MiscCheckTimer(&p98003MotorTimer)) { + if( !(IOGetScanState( ps, _TRUE ) & _SCANSTATE_STOP)) + ps->Scan.bModuleState = _MotorInNormalState; + else { + if (!(IOGetExtendedStatus( ps ) & _STILL_FREE_RUNNING )) { + IORegisterToScanner( ps, ps->RegRefreshScanState ); + ps->Scan.bModuleState = _MotorInNormalState; + } + } + } + break; + } +} + +/*............................................................................. + * + */ +_LOC void MotorP98003PositionYProc( pScanData ps, ULong steps) +{ + TimerDef timer; + + DBG( DBG_HIGH, "MotorP98003PositionYProc()\n" ); + + MiscStartTimer( &timer, _SECOND * 5 ); + + while(!(IOGetScanState( ps, _TRUE ) & _SCANSTATE_STOP) && + (!MiscCheckTimer( &timer ))); + + _DODELAY( 12 ); + + motorP98003ModuleFreeRun( ps, steps ); + + _DODELAY( 15 ); + + MiscStartTimer( &timer, _SECOND * 30 ); + + do { + if (!(IOGetExtendedStatus( ps ) & _STILL_FREE_RUNNING) || + !(IOGetScanState( ps, _TRUE ) & _SCANSTATE_STOP)) + break; + + } while( !MiscCheckTimer( &timer )); + + DBG( DBG_HIGH, "MotorP98003PositionYProc() - done\n" ); +} + +/* END PLUSTEK-PP_MOTOR.C ...................................................*/ -- cgit v1.2.3