Logo Search packages:      
Sourcecode: sane-backends version File versions

plustek-pp_dac.c

/* @file plustek-pp_dac.c
 * @brief all the shading function formerly found in shading.c.
 *        don't ask me why I called this file dac.c...
 *
 * based on sources acquired from Plustek Inc.
 * Copyright (C) 1998 Plustek Inc.
 * Copyright (C) 2000-2004 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 some comments
 * - 0.34 - slight changes
 * - 0.35 - removed SetInitialGainRAM from structure pScanData
 * - 0.36 - added dacP96001WaitForShading and changed dacP96WaitForShading to
 *          dacP96003WaitForShading
 *        - changes, due to define renaming
 * - 0.37 - removed dacP98FillShadingDarkToShadingRegister()
 *        - removed // comments
 *        - some code cleanup
 * - 0.38 - added P12 stuff
 * - 0.39 - no changes
 * - 0.40 - disabled the A3I stuff
 * - 0.41 - no changes
 * - 0.42 - changed include names
 * - 0.43 - no changes
 * .
 * <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 ********************************/

/***************************** global vars ***********************************/

static const Byte a_bCorrectTimesTable[4] = {0, 1, 2, 4};

static ULong dwADCPipeLine = 4 * 4;
static ULong dwReadyLen;

/*************************** local functions *********************************/

/**
 */
static void dacP98AdjustGainAverage( pScanData ps )
{
      pUChar pDest, pSrce;
    ULong  dw, dw1;
    UShort wSum;

    pDest = pSrce = ps->pScanBuffer1;

    for (dw1 = 0; dw1 < (2560 * 3) / 16; dw1++, pDest++) {
            for (dw = 0, wSum = 0; dw < 16; dw++, pSrce++)
                wSum += *pSrce;

            *pDest = wSum / 16;
    }
}

/**
 */
static void dacP98FillDarkDAC( pScanData ps )
{
    IODataRegisterToDAC( ps, 0x20, ps->bRedDAC   );
    IODataRegisterToDAC( ps, 0x21, ps->bGreenDAC );
    IODataRegisterToDAC( ps, 0x22, ps->bBlueDAC  );
}

/**
 */
static void dacP98SetReadFBKRegister( pScanData ps )
{
    IODataToRegister( ps, ps->RegModeControl, _ModeIdle );

    ps->AsicReg.RD_ScanControl = _SCAN_12BITMODE + _SCAN_1ST_AVERAGE;

    IOSelectLampSource( ps );
    IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );

      ps->AsicReg.RD_Motor0Control = _MotorOn;
      ps->AsicReg.RD_StepControl     = _MOTOR0_SCANSTATE;
      ps->AsicReg.RD_Origin          = 4;
      ps->AsicReg.RD_Pixels          = 512;
      ps->AsicReg.RD_Motor1Control = 0;
      ps->AsicReg.RD_Motor0Control = 0;

      ps->AsicReg.RD_ModelControl  = _LED_CONTROL + _LED_ACTIVITY;

    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
            ps->AsicReg.RD_Dpi = 300;
            ps->AsicReg.RD_ModelControl += _ModelDpi300;

    } else {
            ps->AsicReg.RD_Dpi = 600;
            ps->AsicReg.RD_ModelControl += _ModelDpi600;
    }
}

/**
 */
static UShort dacP98CalDarkOff( pScanData ps, UShort wChDarkOff,
                                              UShort wDACCompareHigh, UShort wDACOffset )
{
    UShort wTemp;

    if ((_CCD_518 == ps->Device.bCCDID) || (_CCD_535 == ps->Device.bCCDID)) {
            wTemp = wChDarkOff + wDACOffset;
      } else  {

            if (_CCD_3797 == ps->Device.bCCDID) {
                if (wChDarkOff > wDACOffset) {
                        wTemp = wChDarkOff - wDACOffset;
                  } else {
                        wTemp = 0;
                  }
            } else {
                if (wChDarkOff > wDACCompareHigh) {
                        wTemp = wChDarkOff - wDACCompareHigh;
                  } else {
                        wTemp = 0;
                  }
            }
    }
    return wTemp;
}

/**
 */
static Bool dacP98AdjustDAC( UShort DarkOff, UShort wHigh,
                                           UShort wLow, pUChar pbReg, Bool *fDACStopFlag )
{
    if (DarkOff > wHigh) {
            if ((DarkOff - wHigh) > 10) {
                if ((DarkOff - wHigh) > 2550)
                        *pbReg += ((DarkOff - wHigh) / 20);
                else
                  *pbReg += ((DarkOff - wHigh) / 10);
            } else
            *pbReg += 1;

            if (!(*pbReg))
                *pbReg = 0xff;

            *fDACStopFlag = _FALSE;
            return _FALSE;

    } else {
            if (DarkOff < wLow) {
                if (DarkOff > 0)
                        *pbReg -= 2;
                else
                        *pbReg -= 10;

                *fDACStopFlag = _FALSE;
                return _FALSE;
            } else
                return _TRUE;
      }
}

/**
 */
static Bool dacP98CheckChannelDarkLevel( pScanData ps )
{
      Bool fDACStopFlag = _TRUE;

    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Red,
                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Red,
                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Red,
                           &ps->bRedDAC, &fDACStopFlag );
    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Green,
                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Green,
                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Green,
                           &ps->bGreenDAC, &fDACStopFlag );
    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Blue,
                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue,
                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Blue,
                           &ps->bBlueDAC, &fDACStopFlag );

    return  fDACStopFlag;
}

/** Average left offset 30, 16 pixels as each color's dark level
 */
static void dacP98FillChannelDarkLevelControl( pScanData ps )
{
    DataPointer p;
      ULong     dwPos, dw, dwSum;

    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
            dwPos = 0x10 * 3;
      } else {
            dwPos = 0x20 * 2;
      }

    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos), dwSum = 0, dw = 16;
           dw; dw--, p.pw++) {
            dwSum += (ULong)(*p.pw);
      }

      ps->Shade.DarkOffset.Colors.Red = (UShort)(dwSum / 16);

    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos + 1024), dwSum = 0, dw = 16;
          dw; dw--, p.pw++) {
            dwSum += (ULong)(*p.pw);
      }

    ps->Shade.DarkOffset.Colors.Green = (UShort)(dwSum / 16);

    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos + 1024 * 2), dwSum = 0, dw = 16;
          dw; dw--, p.pw++) {
            dwSum += (ULong)(*p.pw);
      }

      ps->Shade.DarkOffset.Colors.Blue = (UShort)(dwSum / 16);
}

/**
 */
static void dacP98AdjustGain( pScanData ps )
{
      DataPointer p;
      ULong       dw;
      UShort            w;
    Byte          b[3];
    pUChar        pbReg[3];

    dacP98AdjustGainAverage( ps );

    pbReg[0] = &ps->bRedGainIndex;
    pbReg[1] = &ps->bGreenGainIndex;
    pbReg[2] = &ps->bBlueGainIndex;

    for (w = 0, p.pb = ps->pScanBuffer1; w < 3; w++) {

            for (dw = 2560 / 16, b [w] = 0; dw; dw--, p.pb++) {
                if (b [w] < *p.pb)
                        b [w] = *p.pb;
            }
            if (b[w] < _GAIN_LOW) {
                if ((_GAIN_P98_HIGH - b[w]) < b[w])
                        *(pbReg[w]) += 1;
                else
                        *(pbReg[w]) += 4;
            } else {
                if (b[w] > _GAIN_P98_HIGH)
                        *(pbReg[w]) -= 1;
            }
    }
}

/**
 */
static void dacP98CheckLastGain( pScanData ps )
{
    DataPointer p;
      ULong     dw;
    UShort      w;
    Byte        b[3];
    pUChar      pbReg[3];

    dacP98AdjustGainAverage( ps );

    pbReg[0] = &ps->bRedGainIndex;
    pbReg[1] = &ps->bGreenGainIndex;
    pbReg[2] = &ps->bBlueGainIndex;

    for (w = 0, p.pb = ps->pScanBuffer1; w < 3; w++) {
            for (dw = 2560 / 16, b [w] = 0; dw; dw--, p.pb++) {
                if (b[w] < *p.pb)
                        b[w] = *p.pb;
            }
      
            if (b[w] > _GAIN_P98_HIGH) {
                *(pbReg [w]) -= 1;
            }
    }
}

/**
 */
static void dacP98FillGainInitialRestRegister( pScanData ps )
{
      ps->OpenScanPath( ps );

      IODataToRegister( ps, ps->RegThresholdGapControl, ps->AsicReg.RD_ThresholdGapCtrl );
      IODataToRegister( ps, ps->RegModelControl, ps->AsicReg.RD_ModelControl );

      ps->CloseScanPath( ps );
}

/**
 */
static void dacP98SetInitialGainRegister( pScanData ps )
{
      DacP98FillGainOutDirectPort( ps );        /* R/G/B GainOut to scanner         */
    dacP98FillGainInitialRestRegister( ps );/* Model Control2, LED, Correct.*/
}

/** Find the the most ideal intensity for each color (RGB)
 */
static void dacP98SetRGBGainRegister( pScanData ps )
{
    IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeIdle );

      ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
    IOSelectLampSource( ps );

    IOCmdRegisterToScanner( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
    dacP98SetInitialGainRegister( ps );

    ps->AsicReg.RD_ModeControl   = _ModeScan;
    ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
    ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorDirForward + _MotorHEightStep;
    ps->AsicReg.RD_XStepTime   = ps->bSpeed4;

    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
            ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi300;
            ps->AsicReg.RD_Origin = 32 +  60 + 4;
    } else {
            ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi600;
            ps->AsicReg.RD_Origin = 64 + 120 + 4;
    }
    ps->AsicReg.RD_Dpi    = 300;
    ps->AsicReg.RD_Pixels = 2560;

      IOPutOnAllRegisters( ps );
}

/**
 */
static void dacP98FillRGBMap( pUChar pBuffer )
{
    ULong  dw, dw1;
      pULong pdw = (pULong)(pBuffer);

    for( dw = 256, dw1 = 0; dw; dw--, dw1 += 0x01010101 ) {
            *pdw++ = dw1;
            *pdw++ = dw1;
            *pdw++ = dw1;
            *pdw++ = dw1;
    }
}

/** here we download the current mapping table
 */
static void dacP98DownloadMapTable( pScanData ps, pUChar pBuffer )
{
    Byte  bAddr;
    ULong i;

    IODataToRegister( ps, ps->RegScanControl,
                        (Byte)((ps->AsicReg.RD_ScanControl & 0xfc) | _SCAN_BYTEMODE));

    for( i = 3, bAddr = _MAP_ADDR_RED; i--; bAddr += _MAP_ADDR_SIZE ) {

        IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
        IODataToRegister( ps, ps->RegMemoryLow, 0);
        IODataToRegister( ps, ps->RegMemoryHigh, bAddr );

      IOMoveDataToScanner( ps, pBuffer, 4096 );
      pBuffer += 4096;
    }

    IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
}

/**
 */
static void dacP98DownloadShadingTable( pScanData ps,
                                        pUChar pBuffer, ULong size )
{
    IODataToRegister( ps, ps->RegModeControl, _ModeShadingMem );
      IODataToRegister( ps, ps->RegMemoryLow,  0 );
    IODataToRegister( ps, ps->RegMemoryHigh, 0 );

    /* set 12 bits output color */
    IODataToRegister( ps, ps->RegScanControl,
                                (Byte)(ps->AsicReg.RD_ScanControl | _SCAN_12BITMODE));

      /* MoveDataToShadingRam() */
    IOMoveDataToScanner( ps ,pBuffer, size );

    if( _ASIC_IS_98003 == ps->sCaps.AsicID )
        IODataToRegister( ps, ps->RegModeControl, _ModeScan );
    else
        IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );

    DacP98FillShadingDarkToShadingRegister( ps );
}

/** Build a linear map for asic (this model is 12-bit scanner, there are 4096
 *  map entries but just generate 256 level output, so the content must be 0 to
 *  255), then fill the shading buffer (the first 3k), and map table (the last
 *  1k) to asic for R & G & B channels.
 *
 *  I need pScanBuffer2 size = 5400 * 2 * 3
 *  pScanBuffer1 size = 256 * 16 * 2
 */
static void dacP98SetInitialGainRAM( pScanData ps )
{
    memset( ps->pScanBuffer2, 0xff, (5400 * 2 * 3));

      dacP98DownloadShadingTable( ps, ps->pScanBuffer2, (5400 * 2 * 3));

    dacP98FillRGBMap( ps->pScanBuffer1 );             /* Fill 12 Bits R Map */
    dacP98FillRGBMap( ps->pScanBuffer1 + 4096 );    /* Fill 12 Bits G Map */
    dacP98FillRGBMap( ps->pScanBuffer1 + 8192 );    /* Fill 12 Bits B Map */

      dacP98DownloadMapTable( ps, ps->pScanBuffer1 );
}

/** Find the the most ideal intensity for each color (RGB)
 */
static void dacP98AdjustRGBGain( pScanData ps )
{
      int bCorrectTimes;

      DBG( DBG_LOW, "dacP98AdjustRGBGain()\n" );

      ps->OpenScanPath( ps );
      dacP98SetInitialGainRAM( ps );      /* set shading ram and read out data to */
    ps->CloseScanPath( ps );

    ps->bRedGainIndex   = 0x02;
      ps->bGreenGainIndex = 0x02;
      ps->bBlueGainIndex  = 0x02;

    for (bCorrectTimes = 10; bCorrectTimes; bCorrectTimes-- ) {

            dacP98SetRGBGainRegister( ps );            /* shading the most brightness &*/
            ps->PauseColorMotorRunStates( ps );  /* stop scan states                 */
            IOReadOneShadingLine( ps, ps->pScanBuffer1, 2560UL );
            dacP98AdjustGain( ps );
    }

    dacP98SetRGBGainRegister( ps );       /* shading the most brightness &    */
      ps->PauseColorMotorRunStates( ps ); /* stop scan states                */

    IOReadOneShadingLine( ps, ps->pScanBuffer1, 2560UL );

    dacP98CheckLastGain( ps );
      DacP98FillGainOutDirectPort( ps );
}

/**
 */
static void dacP98SetAdjustShadingRegister( pScanData ps )
{
      DBG( DBG_LOW, "dacP98SetAdjustShadingRegister()\n" );

      IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeIdle );

      ps->AsicReg.RD_ScanControl = _SCAN_12BITMODE + _SCAN_1ST_AVERAGE;
      IOSelectLampSource( ps );

    IOCmdRegisterToScanner( ps, ps->RegScanControl,
                                          ps->AsicReg.RD_ScanControl );

      ps->AsicReg.RD_ModeControl     = _ModeScan;
      ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorHEightStep + _MotorDirForward;
      ps->AsicReg.RD_XStepTime       = ps->bSpeed1;
      ps->AsicReg.RD_ModelControl  = _LED_ACTIVITY + _LED_CONTROL;

    if (ps->bSetScanModeFlag & _ScanMode_AverageOut) {
            ps->AsicReg.RD_Dpi        = 300;
            ps->AsicReg.RD_Pixels = 2700;
            ps->AsicReg.RD_ModelControl += _ModelDpi300;
    } else {
            ps->AsicReg.RD_Dpi        = 600;
            ps->AsicReg.RD_Pixels = 5400;
            ps->AsicReg.RD_ModelControl += _ModelDpi600;
    }
      ps->AsicReg.RD_Origin = 4;

      IOPutOnAllRegisters( ps );
}

/**
 */
static void dacP98ReadShadingScanLine( pScanData ps )
{
      TimerDef timer;

      MiscStartTimer( &timer, _SECOND );

    ps->Scan.bFifoSelect = ps->RegGFifoOffset;

    while((IOReadFifoLength( ps ) < dwReadyLen) &&
               !MiscCheckTimer(&timer)) {
            _DO_UDELAY( 1 );
      }

    IOReadColorData( ps, ps->pScanBuffer2, ps->dwShadingLen );
}

/**
 */
static void dacP98GainResize( pUShort pValue, UShort wResize)
{
      DataType Data;
    Byte     bTemp;

    Data.dwValue = ((ULong) *pValue) * (ULong) wResize / 100;

    if (0x1000 <= Data.dwValue)
            Data.wValue = 0xfff;

    Data.wValue *= 16;

    bTemp = Data.wOverlap.b1st;
    Data.wOverlap.b1st = Data.wOverlap.b2nd;
    Data.wOverlap.b2nd = bTemp;

    *pValue = Data.wValue;
}

/**
 */
static void dacP98SortHilightShadow( pScanData ps, pUShort pwData,
                                                     ULong dwHilightOff, ULong dwShadowOff )
{
      ULong   dwLines, dwPixels;
    UShort  wVCmp, wTmp;
    pUShort pw;

    for (dwPixels = 0; dwPixels < (ps->dwShadingPixels - 4); dwPixels++) {

            pw    = (pUShort)ps->Shade.pHilight + dwHilightOff + dwPixels;
            wVCmp = pwData[dwPixels] & 0xfffU;

            for (dwLines = _DEF_BRIGHTEST_SKIP; dwLines--; pw += 5400UL) {
                if (wVCmp > *pw) {
                        wTmp  = wVCmp;
                        wVCmp = *pw;
                        *pw   = wTmp;
                }
            }
    }
    for (dwPixels = 0; dwPixels < (ps->dwShadingPixels - 4); dwPixels++) {

            pw    = ps->pwShadow + dwShadowOff + dwPixels;
            wVCmp = pwData [dwPixels] & 0xfffU;

            for (dwLines = _DEF_DARKEST_SKIP; dwLines--; pw += 5400UL) {

                if (wVCmp < *pw) {
                        wTmp  = wVCmp;
                        wVCmp = *pw;
                        *pw   = wTmp;
            }
            }
    }
}

/**
 */
static void dacP98WriteBackToShadingRAM( pScanData ps )
{
      ULong   dw;

      pUShort     pBuffer = (pUShort)ps->pScanBuffer2;

      DBG( DBG_LOW, "dacP98WriteBackToShadingRAM()\n" );

    if (ps->DataInf.wPhyDataType >= COLOR_TRUE24) {

            for (dw = 0; dw < 5400; dw++) {

                *pBuffer = ((pUShort)ps->pScanBuffer1)[dw] -
                                            ps->Shade.DarkOffset.Colors.Red;
                  dacP98GainResize( pBuffer,
                              ps->Shade.pCcdDac->GainResize.Colors.Red );
                pBuffer ++;

                *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400] -
                                            ps->Shade.DarkOffset.Colors.Green;
                  dacP98GainResize( pBuffer,
                              ps->Shade.pCcdDac->GainResize.Colors.Green );
                pBuffer ++;

                *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400 * 2] -
                                             ps->Shade.DarkOffset.Colors.Blue;
                  dacP98GainResize( pBuffer,
                              ps->Shade.pCcdDac->GainResize.Colors.Blue );
                pBuffer ++;
            }

    } else {
            for (dw = 0; dw < 5400; dw++) {

                  DataType Data;
                  Byte   bTemp;

                *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400] -
                                            ps->Shade.DarkOffset.Colors.Green;

                Data.wValue = (*pBuffer) * 16;
                bTemp = Data.wOverlap.b1st;
            Data.wOverlap.b1st = Data.wOverlap.b2nd;
                Data.wOverlap.b2nd = bTemp;
                *pBuffer = Data.wValue;
                pBuffer++;
            }
            
    }
      dacP98DownloadShadingTable( ps, ps->pScanBuffer2, (5400 * 2 * 3));
}

/**
 */
static void dacP98ShadingRunLoop( pScanData ps )
{
      int             i;
      DataPointer p;

    p.pb = ps->a_nbNewAdrPointer;

    switch( ps->IO.portMode ) {
      case _PORT_SPP:
      case _PORT_BIDI:
          *p.pw++ = 0;
          for (i = 0; i < 7; i++)
                  *p.pdw++ = 0x00800700;
          *p.pw = 0;
          break;

      default:
          *p.pb++ = 0;
          for (i = 0; i < 15; i++)
                  *p.pw++ = 0xf888;
          *p.pb = 0;
    }

      IOSetToMotorRegister( ps );
}

/**
 */
static void dacP98Adjust12BitShading( pScanData ps )
{
      DataPointer pd, pt;
    ULong         dw, dw1, dwLoop;

      DBG( DBG_LOW, "dacP98Adjust12BitShading()\n" );

    memset( ps->pScanBuffer1, 0, (5400 * 4 * 3));

    if( ps->Shade.pHilight && (_Shading_32Times == ps->bShadingTimeFlag)) {

            memset( ps->Shade.pHilight, 0, (ps->dwHilight * 2UL));

            for (dw = 0; dw < ps->dwShadow; dw++)
                ps->pwShadow[dw] = 0xfff;
    }

      /*
       * in the original code this function does not exist !
       * (of course the code behind the function does ;-)
       */
      dacP98SetAdjustShadingRegister( ps );

    dacP98ShadingRunLoop( ps );
    _DODELAY( 24 );

    if ((ps->DataInf.dwScanFlag & SCANDEF_TPA ) ||
            (_Shading_32Times == ps->bShadingTimeFlag)) {
            dwLoop = 32;
      } else {
            if (_Shading_16Times == ps->bShadingTimeFlag) {
               dwLoop = 16;
            } else {
               dwLoop = 4;
            }
    }

    for (dw1 = 0; dw1 < dwLoop; dw1++) {

        ps->Scan.bFifoSelect = ps->RegGFifoOffset;

            dacP98ReadShadingScanLine( ps );

            if((_Shading_32Times == ps->bShadingTimeFlag) && ps->Shade.pHilight ) {

                dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2, 0, 0 );
            dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2 +
                                                                          ps->dwShadingPixels,
                                                     ps->dwHilightCh, ps->dwShadowCh );

                dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2 +
                                                                          ps->dwShadingPixels * 2,
                                                        ps->dwHilightCh * 2, ps->dwShadowCh * 2);
            }

          /* SumAdd12BitShadingR */
            pd.pw  = (pUShort)ps->pScanBuffer2;
            pt.pdw = (pULong)(ps->pScanBuffer1 + dwADCPipeLine);

            for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
                *pt.pdw += (ULong)(*pd.pw & 0x0fff);

          /* SumAdd10BitShadingG */
            if( ps->bSetScanModeFlag & _ScanMode_AverageOut )
                pd.pw = (pUShort)(ps->pScanBuffer2 + 2700 * 2);
            else
                pd.pw = (pUShort)(ps->pScanBuffer2 + 5400 * 2);

            pt.pdw = (pULong)(ps->pScanBuffer1 + 5400 * 4 + dwADCPipeLine);

            for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
            *pt.pdw += (ULong)(*pd.pw & 0x0fff);

          /* SumAdd12BitShadingB */
            if( ps->bSetScanModeFlag & _ScanMode_AverageOut )
                pd.pw = (pUShort)(ps->pScanBuffer2 + 2700 * 4);
            else
            pd.pw = (pUShort)(ps->pScanBuffer2 + 5400 * 4);

            pt.pdw = (pULong)(ps->pScanBuffer1 + 5400 * 8 + dwADCPipeLine);

            for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
                *pt.pdw += (ULong)(*pd.pw * 94 / 100 & 0x0fff);

            /* one line */
            if (IOReadFifoLength( ps ) <= 2500) 
            IORegisterDirectToScanner( ps, ps->RegRefreshScanState );
    }

    TPAP98001AverageShadingData( ps );

      ps->OpenScanPath( ps );
      dacP98WriteBackToShadingRAM( ps );
      ps->CloseScanPath( ps );
}

/**
 */
static Bool dacP98WaitForShading( pScanData ps )
{
    Byte oldLineControl;

      DBG( DBG_LOW, "dacP98WaitForShading()\n" );

      /*    
       * before getting the shading data, (re)init the ASIC
       */
    ps->InitialSetCurrentSpeed( ps );
      ps->ReInitAsic( ps, _TRUE );

      IOCmdRegisterToScanner( ps, ps->RegLineControl,
                                          ps->AsicReg.RD_LineControl );

    ps->Shade.DarkOffset.Colors.Red   = 0;
      ps->Shade.DarkOffset.Colors.Green = 0;
      ps->Shade.DarkOffset.Colors.Blue  = 0;

      /*
       * according to the scan mode, switch on the lamp
       */
    IOSelectLampSource( ps );
    IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);

    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
            ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi300;
      } else {
            ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi600;
      }
    IOCmdRegisterToScanner( ps, ps->RegModelControl,
                                          ps->AsicReg.RD_ModelControl );

    IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeScan);

    oldLineControl = ps->AsicReg.RD_LineControl;
      IOSetXStepLineScanTime( ps, _DEFAULT_LINESCANTIME );

      /* set line control */
      IOCmdRegisterToScanner( ps, ps->RegLineControl,
                                          ps->AsicReg.RD_LineControl );

      /* Wait for Sensor to position */
      if( !ps->GotoShadingPosition( ps ))
            return _FALSE;

    ps->AsicReg.RD_LineControl = oldLineControl;
    IOCmdRegisterToScanner( ps, ps->RegLineControl,
                                          ps->AsicReg.RD_LineControl );

    dwADCPipeLine = 4 * 4;

    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
            dwReadyLen              = 2500;
            ps->dwShadingLen  = 2700 * 2;
            ps->dwShadingPixels     = 2700;
    } else {
            dwReadyLen              = 5000;
            ps->dwShadingLen  = 5400 * 2;
            ps->dwShadingPixels     = 5400;
    }

      dacP98AdjustRGBGain           ( ps );
      DacP98AdjustDark        ( ps );
      dacP98Adjust12BitShading( ps );

    ps->OpenScanPath( ps );
      DacP98FillShadingDarkToShadingRegister( ps );

      if ( COLOR_BW != ps->DataInf.wPhyDataType )
            dacP98DownloadMapTable( ps, ps->a_bMapTable );

    ps->CloseScanPath( ps );

    return _TRUE;
}

/** Set RAM bank and size, then write the data to it
 */
static void dacP96FillWhole4kRAM( pScanData ps, pUChar pBuf )
{
    ps->OpenScanPath( ps );

      IODataToRegister( ps, ps->RegMemAccessControl,
                                ps->Asic96Reg.RD_MemAccessControl );

    ps->AsicReg.RD_ModeControl = _ModeProgram;
    IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );

    IOMoveDataToScanner( ps, pBuf, ps->ShadingBankSize );

    ps->AsicReg.RD_ModeControl = _ModeScan;
    IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );

    ps->CloseScanPath( ps );
}

/**
 */
static void dacP96FillChannelDarkOffset( pScanData ps )
{
    ps->OpenScanPath( ps );

      IODataToRegister( ps, ps->RegRedChDarkOffset,
                                ps->Asic96Reg.RD_RedChDarkOff );
    IODataToRegister( ps, ps->RegGreenChDarkOffset,
                                ps->Asic96Reg.RD_GreenChDarkOff );
    IODataToRegister( ps, ps->RegBlueChDarkOffset,
                                ps->Asic96Reg.RD_BlueChDarkOff );

    ps->CloseScanPath( ps );
}

/**
 */
static void dacP96FillEvenOddControl( pScanData ps )
{
    ps->OpenScanPath( ps );

      IODataToRegister( ps, ps->RegRedChEvenOffset,
                                ps->Asic96Reg.RD_RedChEvenOff );
      IODataToRegister( ps, ps->RegGreenChEvenOffset,
                                ps->Asic96Reg.RD_GreenChEvenOff );
      IODataToRegister( ps, ps->RegBlueChEvenOffset,
                                ps->Asic96Reg.RD_BlueChEvenOff );
      IODataToRegister( ps, ps->RegRedChOddOffset,
                                ps->Asic96Reg.RD_RedChOddOff );
      IODataToRegister( ps, ps->RegGreenChOddOffset,
                                ps->Asic96Reg.RD_GreenChOddOff );
      IODataToRegister( ps, ps->RegBlueChOddOffset,
                                ps->Asic96Reg.RD_BlueChOddOff );

    ps->CloseScanPath( ps );
}

/** Used for capture data to pScanData->pPrescan16.
 *  Used to replace:
 *    1) ReadFBKScanLine (3 * 1024, 5)
 *    2) ReadOneScanLine (3 * 2560, 11)
 *    4) ReadShadingScanLine (3 * 1280, 6)
 */
static void dacP96ReadDataWithinOneSecond( pScanData ps,
                                                               ULong dwLen, Byte bBlks )
{
      TimerDef timer;

    MiscStartTimer( &timer, _SECOND );

    while((IODataRegisterFromScanner( ps, ps->RegFifoOffset) < bBlks) &&
                  !MiscCheckTimer(&timer));

    IOReadScannerImageData( ps, ps->pPrescan16, dwLen );
}

/**
 */
static void dacP96GetEvenOddOffset( pUChar pb, pWordVal pwv )
{
      ULong dw;
    UShort  we, wo;

    for (dw = 8, we = wo = 0; dw; dw-- ) {
            we += *pb++;
            wo += *pb++;
    }

    pwv->b1st = (Byte)(we >> 3);
    pwv->b2nd = (Byte)(wo >> 3);
}

/**
 */
static void dacP96SumAverageShading( pScanData ps, pUChar pDest, pUChar pSrce )
{
      ULong  dw;
      UShort wLeft[6];
      UShort wSumL, wSumR;

    pSrce += ps->Offset70 + ps->Device.DataOriginX;
    pDest += ps->Offset70 + ps->Device.DataOriginX;

    wLeft[0] = wLeft[1] = wLeft[2] =
      wLeft[3] = wLeft[4] = wLeft[5] = (UShort)*pSrce;

    wSumL = wLeft[0] * 6;
    wSumR = (UShort)pSrce[1] + pSrce[2] + pSrce[3] + pSrce[4] +
                        pSrce[5] + pSrce[6];

/*  for (dw = 2772; dw; dw--, pSrce++, pDest++) */
    for (dw = ps->BufferSizePerModel - 6; dw; dw--, pSrce++, pDest++) {

            *pDest = (Byte)(((UShort)*pSrce * 4 + wSumL + wSumR) / 16);
            wSumL  = wSumL - wLeft [0] + (UShort)*pSrce;

            wLeft[0] = wLeft[1];
            wLeft[1] = wLeft[2];
            wLeft[2] = wLeft[3];
            wLeft[3] = wLeft[4];
            wLeft[4] = wLeft[5];
            wLeft[5] = (UShort)*pSrce;
            wSumR = wSumR - (UShort) *(pSrce + 1) + (UShort) *(pSrce + 7);
    }
}

/**
 */
static void dacP96WriteLinearGamma( pScanData ps,
                                                    pUChar pBuf, ULong dwEntries, Byte bBank )
{
      ULong   dw;
    pULong  pdw = (pULong)(pBuf + ps->ShadingBufferSize);

    for (dw = 0; dwEntries; pdw++, dwEntries--, dw += 0x01010101)
            *pdw = dw;

    ps->Asic96Reg.RD_MemAccessControl = bBank;

    dacP96FillWhole4kRAM( ps, pBuf );
}

/**
 */
static void dacP96FillChannelShadingOffset( pScanData ps )
{
    ps->OpenScanPath( ps );

      IODataToRegister( ps, ps->RegRedChShadingOffset,
                                ps->Asic96Reg.u28.RD_RedChShadingOff);
      IODataToRegister( ps, ps->RegGreenChShadingOffset,
                                ps->Asic96Reg.u29.RD_GreenChShadingOff);
      IODataToRegister( ps, ps->RegBlueChShadingOffset,
                                ps->Asic96Reg.RD_BlueChShadingOff);

    ps->CloseScanPath( ps );
}

/**
 */
static void dacP96GetHilightShadow( pScanData ps,
                                                      pUChar pBuf, pUChar pChOff, pUChar pHigh )
{
      ULong dw;

      /* GetShadingImageExtent (ps) */
      if (ps->DataInf.wAppDataType < COLOR_256GRAY)
            dw = (ULong)(ps->DataInf.crImage.cx & 0xfff8);
      else
            dw = (ULong)ps->DataInf.crImage.cx;

    for( pBuf += ps->DataInf.crImage.x, *pChOff = 0xff, *pHigh = 0;
             dw; dw--, pBuf++ ) {

            if (*pChOff < *pBuf) {
                if (*pHigh < *pBuf)
                        *pHigh = *pBuf; /* brightest */
            } else
                *pChOff = *pBuf;    /* darkest */
    }
}

/**
 */
static void dacP96ReadColorShadingLine( pScanData ps )
{
    Byte     b2ndDiscard, b3rdDiscard, b1stReadLines, b2ndReadLines;
    Byte     b3rdReadLines;
      ULong  dw;
    DataType Data;

    /* ClearScanBuffer1 (ps) */
      /* buffer to keep sum of data */
    memset( ps->pScanBuffer1, 0, ps->BufferForDataRead1 );

    b2ndDiscard   = ps->b2ndLinesOffset;
    b3rdDiscard   = ps->b1stLinesOffset;
    b1stReadLines = b2ndReadLines = b3rdReadLines = 8;

    while( _TRUE ) {

            /* ReadShadingScanLine(ps) */
            dacP96ReadDataWithinOneSecond( ps, ps->ShadingScanLineLen,
                                                         ps->ShadingScanLineBlks );

            if (b1stReadLines) {

                b1stReadLines--;

            /* SumAdd10BitShadingR */
                for (dw = 0; dw < ps->BufferSizeBase; dw++)
                  ((pUShort)ps->pScanBuffer1)[dw] += (UShort)ps->pPrescan16 [dw];
            }

            if (!b2ndDiscard) {
                if (b2ndReadLines) {
                        b2ndReadLines--;
                        /* SumAdd10BitShadingG */
                        for (dw = ps->BufferSizeBase;dw < (ULong)ps->BufferSizeBase * 2;dw++) {
                            ((pUShort)ps->pScanBuffer1)[dw] +=
                                                                              (UShort)ps->pPrescan16[dw];
                        }
                }
            } else
                b2ndDiscard--;
      
            if (!b3rdDiscard) {
                if (b3rdReadLines) {
                        b3rdReadLines--;
                        /* SumAdd10BitShadingB */
                        for (dw = ps->BufferSizeBase * 2;
                                    dw < (ULong)ps->BufferSizeBase * 3; dw++) {
                            ((pUShort)ps->pScanBuffer1)[dw] +=
                                                                              (UShort)ps->pPrescan16[dw];
                        }
                } else
                        break;
            } else
                b3rdDiscard--;

            IORegisterDirectToScanner( ps, ps->RegRefreshScanState );
    }

    for (dw = 0; dw < (ULong)ps->BufferSizeBase * 3; dw++) {

            Data.wOverlap.b1st =
            Data.wOverlap.b2nd = (Byte)(((pUShort)ps->pScanBuffer1)[dw] / 8);
            ((pUShort)ps->pPrescan16)[dw] = Data.wValue;
    }
}

/**
 */
static void dacP96SetShadingGainProc( pScanData ps, Byte bHigh, ULong dwCh )
{
      Byte  bDark, bGain, bGainX2, bGainX4, bMask;
      pUChar      pbChDark, pbSrce, pbDest;
      ULong dw;

    pbChDark = NULL, pbSrce = NULL, pbDest = NULL;
    bDark = 0, bGain = 0, bGainX2 = 0, bGainX4 = 0, bMask = 0;

    switch( dwCh ) {

      case 0:     /* red */
          pbChDark = &ps->Asic96Reg.u28.RD_RedChShadingOff;
          pbSrce   = ps->pPrescan16;
          pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->Device.DataOriginX;
          bGainX2  = 1;
          bGainX4  = 3;
          bMask    = 0x3c;
          break;

      case 1:     /* green */
          pbChDark = &ps->Asic96Reg.u29.RD_GreenChShadingOff;
          pbSrce   = ps->pPrescan16 + ps->BufferSizePerModel;
          pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->ShadingBankSize +
                           ps->Device.DataOriginX;
          bGainX2  = 4;
          bGainX4  = 0x0c;
          bMask    = 0x33;
          break;

      case 2:
          pbChDark = &ps->Asic96Reg.RD_BlueChShadingOff;
          pbSrce   = ps->pPrescan16 + ps->BufferSizePerModel * 2;
          pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->ShadingBankSize * 2 +
                           ps->Device.DataOriginX;
          bGainX2  = 0x10;
          bGainX4  = 0x30;
          bMask    = 0x0f;
    }

    bDark = *pbChDark;
    if ((bHigh -= bDark) > 60U) {
            /* Hilight - Shadow > 60, Quality not so good */
            bGain = bGainX2;        /* Gain x 2 */
            if (bHigh > 120U)
                bGain = bGainX4;    /* Poor quality, Gain x 4 */
    } else
            bGain = 0;

    ps->Asic96Reg.RD_ShadingCorrectCtrl &= bMask;
    ps->Asic96Reg.RD_ShadingCorrectCtrl |= bGain;

    if (!bGain) { 
            /* GammaGain1 (ps) */
            for (dw = ps->BufferSizePerModel; dw; dw--, pbSrce++, pbDest++)
                if (*pbSrce > bDark)
                        *pbDest = (*pbSrce - bDark) * 4;
            else
                        *pbDest = 0;
    } else
            if (bGain == bGainX2) {
                  /* GammaGain2 */
                for (dw = ps->BufferSizePerModel; dw; dw--, pbSrce++, pbDest++)
                        if (*pbSrce > bDark)
                            *pbDest = (*pbSrce - bDark) * 2;
                        else
                            *pbDest = 0;
            } else {
                  /* GammaGain4 (ps) */
                  memcpy( pbDest, pbSrce, ps->BufferSizePerModel );
                *pbChDark = 0;
            }
}

/**
 */
static void dacP96FillShadingAndGammaTable( pScanData ps )
{
    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankRed;       /* R */
      dacP96FillWhole4kRAM( ps, ps->pPrescan16 );

    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankGreen;     /* G */
      dacP96FillWhole4kRAM( ps, ps->pPrescan16 );

    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankBlue;      /* B */
      dacP96FillWhole4kRAM( ps, ps->pPrescan16 );
}

/**
 */
static void dacP96SetInitialGainRAM( pScanData ps )
{
    ULong  dw, dw1;
      pULong pdw = (pULong)(ps->pPrescan16 + ps->ShadingBufferSize);

      memset( ps->pPrescan16, 0xff, ps->ShadingBufferSize );

    for (dw = 256, dw1 = 0; dw; dw--, dw1 += 0x01010101, pdw++)
            *pdw = dw1;

      dacP96FillShadingAndGammaTable( ps );
}

/**
 */
static void dacP96Adjust10BitShading( pScanData ps )
{
      pULong      pdw;
      ULong dw;
      Byte  bRedHigh, bGreenHigh, bBlueHigh;

    /* ShadingMotorRunLoop(ps)
       * set scan states as:
     *       40h, 00, 00, 00, 40h, 01, 03, 02, ... (repeat)
     * so, read a R/G/B line every 2 steps
       */
    pdw = (pULong)ps->a_nbNewAdrPointer;
    for (dw = 0; dw < 4; dw++) {
            *pdw++ = 0x40;
            *pdw++ = 0x02030140;
      }

    dacP96SetInitialGainRAM( ps);   /* initiates the shading buffers and maps */

    /* SetAdjustShadingRegister(ps) */
    /* Prepare Physical/2 dpi, 8.5" scanning condition for reading the shading area */
    ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
    ps->Asic96Reg.RD_MotorControl = ps->IgnorePF | ps->MotorOn |
                                                      _MotorDirForward;
    ps->AsicReg.RD_ModelControl   = ps->Device.ModelCtrl | _ModelWhiteIs0;
    ps->AsicReg.RD_Dpi                = ps->PhysicalDpi / 2;
    ps->AsicReg.RD_Origin             = (UShort)(ps->Offset70 +
                                             ps->Device.DataOriginX);
    ps->AsicReg.RD_Pixels             = ps->BufferSizeBase;
    IOPutOnAllRegisters( ps );

    ps->Asic96Reg.RD_ShadingCorrectCtrl = _ShadingRCorrectX4|_ShadingGCorrectX4|
                                                            _ShadingBCorrectX4;
      IOCmdRegisterToScanner( ps, ps->RegShadingCorrectCtrl,
                                                          ps->Asic96Reg.RD_ShadingCorrectCtrl );

    /* Read shaded data and do average */
      dacP96ReadColorShadingLine( ps );

    /* ExpandAndAverage (ps) ------------------------------------------------*/
/*
       for (dw = 0; dw < 1280 * 3; dw++)
   {
      Data.wOverlap.b1st =
      Data.wOverlap.b2nd = (Byte)(((pUShort) ps->pScanBuffer1)[dw] / 8);
      ((pULong) ps->pPrescan16)[dw] = Data.wValue;
  }
*/
      /* CalculateShadingOffset (ps); */
    dacP96GetHilightShadow( ps, ps->pPrescan16,
                                    &ps->Asic96Reg.u28.RD_RedChShadingOff, &bRedHigh );

    dacP96GetHilightShadow( ps, ps->pPrescan16 + ps->BufferSizePerModel,
                        &ps->Asic96Reg.u29.RD_GreenChShadingOff, &bGreenHigh );

    dacP96GetHilightShadow( ps, ps->pPrescan16 + ps->BufferSizePerModel * 2,
                              &ps->Asic96Reg.RD_BlueChShadingOff, &bBlueHigh );

      /* SubTheImageDataBase (ps) */
      dacP96SetShadingGainProc( ps, bRedHigh,   0 );  /* red       */
      dacP96SetShadingGainProc( ps, bGreenHigh, 1 );  /* green */
      dacP96SetShadingGainProc( ps, bBlueHigh,  2 );  /* blue      */
      dacP96FillChannelShadingOffset( ps );

      IOCmdRegisterToScanner( ps, ps->RegShadingCorrectCtrl,
                                        ps->Asic96Reg.RD_ShadingCorrectCtrl );

      dacP96SumAverageShading( ps, ps->pPrescan16, ps->pScanBuffer1 );
      dacP96SumAverageShading( ps, ps->pPrescan16 + ps->ShadingBankSize,
                                         ps->pScanBuffer1 + ps->ShadingBankSize );
      dacP96SumAverageShading( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
                                       ps->pScanBuffer1 + ps->ShadingBankSize * 2 );

    /* --------------------------------------------------------------------- */

    /* PrewriteBackToGammaShadingRAM( ps) */
    dacP96WriteLinearGamma( ps, ps->pPrescan16, 256, ps->ShadingBankRed );
      dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize, 256,
                                          ps->ShadingBankGreen );
      dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
                                  256, ps->ShadingBankBlue );
}

/**
 */
static Bool dacP96003WaitForShading( pScanData ps )
{
      int         bCorrectTimes;
      DataPointer p;
    ULong         dw;
    UShort        w;
    WordVal       wv;
      pUChar            pbReg[3];
    Byte          b[3];

      DBG( DBG_LOW, "dacP96003WaitForShading()\n" );

    /* TurnOnLamp () */
      ps->AsicReg.RD_ScanControl |= ps->bLampOn;
      IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);

      ps->Asic96Reg.RD_LedControl = _LedActControl | _LedMotorActEnable;
      IOCmdRegisterToScanner(ps, ps->RegLedControl, ps->Asic96Reg.RD_LedControl);

    if ( ps->GotoShadingPosition( ps )) {

      /* AdjustRGBGain () =================================================*/
            ps->Asic96Reg.RD_RedGainOut  = ps->Asic96Reg.RD_GreenGainOut =
            ps->Asic96Reg.RD_BlueGainOut = 8;
            ps->Asic96Reg.u26.RD_ModelControl2 = _Model2DirectOutPort;

            IOCmdRegisterToScanner(ps, ps->RegModelControl2, _Model2DirectOutPort);

            for ( bCorrectTimes = 4; bCorrectTimes >= 1; bCorrectTimes-- ) {

                  ps->PauseColorMotorRunStates( ps );

                  /* SetRGBGainRegister () ----------------------------------------*/
                ps->AsicReg.RD_ScanControl = ps->bLampOn | _SCAN_BYTEMODE;
                dacP96SetInitialGainRAM( ps );

                /* SetInitialGainRegister () ++++++++++++++++++++++++++++++++++++*/
                ps->Asic96Reg.u28.RD_RedChShadingOff  =           
                  ps->Asic96Reg.u29.RD_GreenChShadingOff    =
                ps->Asic96Reg.RD_BlueChShadingOff           =
                ps->Asic96Reg.RD_RedChDarkOff               =
                ps->Asic96Reg.RD_GreenChDarkOff             =
                ps->Asic96Reg.RD_BlueChDarkOff              =
                ps->Asic96Reg.RD_RedChEvenOff               =
                ps->Asic96Reg.RD_GreenChEvenOff             =
                ps->Asic96Reg.RD_BlueChEvenOff              =
                ps->Asic96Reg.RD_RedChOddOff                =
                ps->Asic96Reg.RD_GreenChOddOff              =
                ps->Asic96Reg.RD_BlueChOddOff               = 0;
                ps->Asic96Reg.RD_ShadingCorrectCtrl = _ShadingRCorrectX4 |
                                                                    _ShadingGCorrectX4 |
                                                                        _ShadingBCorrectX4;

                  dacP96FillChannelShadingOffset( ps );
                dacP96FillChannelDarkOffset( ps );
                  dacP96FillEvenOddControl( ps );

                /* FillGainOutDirectPort (); */
                  ps->OpenScanPath( ps );
                  IODataToRegister( ps, ps->RegRedGainOutDirect,
                                            ps->Asic96Reg.RD_RedGainOut );
                  IODataToRegister( ps, ps->RegGreenGainOutDirect,
                                            ps->Asic96Reg.RD_GreenGainOut );
                  IODataToRegister( ps, ps->RegBlueGainOutDirect,
                                            ps->Asic96Reg.RD_BlueGainOut );

                /* FillGainInitialRestRegister (); */
                IODataToRegister( ps, ps->RegModelControl2,
                                            ps->Asic96Reg.u26.RD_ModelControl2 );
                  IODataToRegister( ps, ps->RegThresholdGapControl,
                                          ps->AsicReg.RD_ThresholdGapCtrl );
                  IODataToRegister( ps, ps->RegLedControl,
                                            ps->Asic96Reg.RD_LedControl );

                IODataToRegister( ps, ps->RegShadingCorrectCtrl,
                                          ps->Asic96Reg.RD_ShadingCorrectCtrl );

                  ps->CloseScanPath( ps );

                ps->Asic96Reg.RD_MotorControl = 0;
                  IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );

                  ps->AsicReg.RD_ModeControl    = _ModeScan;
                  ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
                  ps->Asic96Reg.RD_MotorControl = (ps->IgnorePF |
                                                                 ps->MotorOn | _MotorDirForward);

                  ps->AsicReg.RD_Origin       = 142;
                  ps->AsicReg.RD_ModelControl = ps->Device.ModelCtrl | _ModelWhiteIs0;
            ps->AsicReg.RD_Dpi          = ps->PhysicalDpi;
                  ps->AsicReg.RD_Pixels       = ps->BufferSizePerModel;

                  IOPutOnAllRegisters( ps );

                  /*---------------------------------------------------------------*/

                /* ReadOneScanLine (); */
                dacP96ReadDataWithinOneSecond( ps, ps->OneScanLineLen, 11 );

                  /* AdjustGain () */
                  /*    FindTheMaxGain (), AdjustGainOutData (); */

                pbReg[0] = &ps->Asic96Reg.RD_RedGainOut;
                pbReg[1] = &ps->Asic96Reg.RD_GreenGainOut;
            pbReg[2] = &ps->Asic96Reg.RD_BlueGainOut;

                for (w = 0, p.pb = ps->pPrescan16; w < 3; w++) {
/* CHANGE: org was:     for (dw = 2560, b[w] = 0; dw; dw--, p.pb++) { */
                        for (dw = (ps->OneScanLineLen/3), b[w] = 0; dw; dw--, p.pb++) {

                            if (b[w] < *p.pb)
                                    b[w] = *p.pb;
                        }

                        if (b[w] < _GAIN_LOW)
                            *(pbReg[w]) += a_bCorrectTimesTable[bCorrectTimes - 1];
                        else
                            if (b[w] > _GAIN_P96_HIGH)
                                    *(pbReg[w]) -= a_bCorrectTimesTable[bCorrectTimes - 1];
                }
            }

      /*===================================================================*/

          /* SonyFBK ()/ToshibaFBK ()====================================*/
            /*FillRGBDarkLevel0Table (); */
            memset( ps->pPrescan16, 0xff, ps->ShadingBankSize );

            for( dw = 0, p.pb = ps->pPrescan16 + ps->ShadingBufferSize;
                                                    dw <=255; dw++, p.pb++ ) {
                *p.pb = (Byte) dw;
            }

            dacP96FillShadingAndGammaTable( ps );

            ps->PauseColorMotorRunStates( ps );

            /* SetReadFBKRegister () */
            ps->Asic96Reg.RD_MotorControl = 0;
            IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );

            ps->AsicReg.RD_ModeControl    = _ModeScan;
            ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
            ps->Asic96Reg.RD_MotorControl = ps->IgnorePF | ps->MotorOn |
                                                        _MotorDirForward;

            ps->AsicReg.RD_Origin       = 22;
            ps->AsicReg.RD_ModelControl = ps->Device.ModelCtrl | _ModelWhiteIs0;
        ps->AsicReg.RD_Dpi          = ps->PhysicalDpi;
            ps->AsicReg.RD_Pixels       = ps->FBKScanLineLenBase;

            IOPutOnAllRegisters( ps );

            /* ReadFBKScanLine () */
            dacP96ReadDataWithinOneSecond( ps, ps->FBKScanLineLen,
                                                                                 ps->FBKScanLineBlks );

          /*===================================================================*/
            if ( ps->fSonyCCD ) {

                /* FillChannelDarkLevelControl (); */
                for ( p.pb = ps->pPrescan16 + 32, w = 0, dw = 16;
                          dw; dw--, p.pb++) {
                          w += (UShort) *p.pb;
                  }

                ps->Asic96Reg.RD_RedChDarkOff = (Byte)(w / 16);

                for ( p.pb = ps->pPrescan16 + 32 + ps->FBKScanLineLenBase, w = 0, dw = 16;
                          dw; dw--, p.pb++ ) {
                        w += (UShort)*p.pb;
                  }

                  ps->Asic96Reg.RD_GreenChDarkOff = (Byte)(w / 16);

            for ( p.pb = ps->pPrescan16 + 32 + ps->FBKScanLineLenBase * 2, w = 0, dw = 16;
                          dw; dw--, p.pb++) {
                        w += (UShort)*p.pb;
                  }

                ps->Asic96Reg.RD_BlueChDarkOff = (Byte)(w / 16);

                dacP96FillChannelDarkOffset( ps );

            } else {

                /* FillToshibaDarkLevelControl (); */
                  dacP96GetEvenOddOffset( ps->pPrescan16 + 32, &wv );
                ps->Asic96Reg.RD_RedChEvenOff = wv.b1st;
                ps->Asic96Reg.RD_RedChOddOff  = wv.b2nd;

                  dacP96GetEvenOddOffset( ps->pPrescan16 + 32 + ps->FBKScanLineLenBase, &wv );
                ps->Asic96Reg.RD_GreenChEvenOff = wv.b1st;
                ps->Asic96Reg.RD_GreenChOddOff = wv.b2nd;

                  dacP96GetEvenOddOffset( ps->pPrescan16 + 32 + ps->FBKScanLineLenBase * 2, &wv );
                  ps->Asic96Reg.RD_BlueChEvenOff = wv.b1st;
                  ps->Asic96Reg.RD_BlueChOddOff  = wv.b2nd;

                  dacP96FillEvenOddControl( ps );
            }

            /*    SetInitialGainRAM (); */
            dacP96Adjust10BitShading( ps );

            return _TRUE;
    }

    return _FALSE;
}

/**
 */
static void dacP96001ToSetShadingAddress( pScanData ps, pUChar pData )
{
    ps->OpenScanPath( ps );

    IODataToRegister( ps, ps->RegMemAccessControl,
                                                                  ps->Asic96Reg.RD_MemAccessControl);

    ps->AsicReg.RD_ModeControl = _ModeProgram;
    IODataToRegister( ps, ps->RegModeControl, _ModeProgram );

    ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
    IODataToRegister( ps, ps->RegMotorControl, ps->Asic96Reg.RD_MotorControl);

    memset( ps->pScanBuffer1, 0, (64 + 8 + ps->Offset70));
      memcpy( ps->pScanBuffer1 + 64 + 8 + ps->Offset70, pData,
                                                                        _BUF_SIZE_BASE_CONST * 2 );

    IOMoveDataToScanner( ps, ps->pScanBuffer1,
                                          _BUF_SIZE_BASE_CONST * 2 + 64 + 8 + ps->Offset70 );

    ps->AsicReg.RD_ModeControl = _ModeScan;
    IODataToRegister( ps, ps->RegModeControl, _ModeScan );

    ps->CloseScanPath( ps );
}

/**
 */
static void dacP96001WriteBackToColorShadingRam( pScanData ps )
{
    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3a);
    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 );

    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3e);
    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 + _BUF_SIZE_BASE_CONST*2);

    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3c);
    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 + _BUF_SIZE_BASE_CONST*4);
}

/**
 */
static void dacP96001ModifyShadingColor( pByte pData, Byte bMul )
{
    UShort w;
      ULong  dw;

    for ( dw = 0; dw < _BUF_SIZE_BASE_CONST * 2; dw++ ) {

            w = (UShort)(Byte)(~pData[dw]) * bMul / 100U;

            if (w >= 255U)
            pData[dw] = 0;
            else
                pData[dw] = (Byte)~w;
    }
}

/**
 */
static Byte dacP96001FBKReading( pScanData ps, Byte bValue,
                                                 Byte bReg, pByte pbSave, Bool bFBKModify )
{
    TimerDef timer;
    UShort   w, wSum;
    Byte     addrSeq[8] = { 0x40, 0x20, 0x10, 0x08, 4, 2, 1, 0 };
    Byte     bTemp, bFBKTemp, bFBKIndex;

    if( bFBKModify ) {
            bFBKIndex = 3;
            bFBKTemp = *pbSave;
    } else {
            bFBKTemp = 0x80;
            bFBKIndex = 0;
    }

    while( _TRUE ) {

            *pbSave = bFBKTemp;
            IOCmdRegisterToScanner( ps, bReg, bFBKTemp );

            /* SetColorRunTable (BYTE) */
            memset( ps->a_nbNewAdrPointer, bValue, _SCANSTATE_BYTES );
            MotorSetConstantMove( ps, 0 );

            /* SetReadFBK (pScanData) */
            ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                                            ps->Asic96Reg.RD_MotorControl );

            ps->AsicReg.RD_ModeControl  = _ModeScan;
            ps->AsicReg.RD_ScanControl  = _SCAN_BYTEMODE | ps->bLampOn;
            ps->AsicReg.RD_ModelControl =
                              (_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0 );

            ps->AsicReg.RD_Dpi    = 300;
            ps->AsicReg.RD_Origin = 22;
            ps->AsicReg.RD_Pixels = 1024;
            IOPutOnAllRegisters( ps );

            ps->Asic96Reg.RD_MotorControl =
                                             (ps->FullStep | ps->MotorOn | _MotorDirForward);
            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                                                     ps->Asic96Reg.RD_MotorControl );

            MiscStartTimer( &timer, _SECOND );
            while((IODataRegisterFromScanner( ps, ps->RegFifoOffset) < 1) &&
                                                                              !MiscCheckTimer( &timer ));

            IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );
            IOReadScannerImageData( ps, ps->pScanBuffer1, 64 );

            for( w = 26, wSum = 0; w < 42; w++)
                wSum += ps->pScanBuffer1[w];

            wSum >>= 4;
            bTemp = addrSeq[bFBKIndex++];

            if( bTemp ) {
                if( wSum < 0xfe )
                        bFBKTemp += bTemp;
                else
                        bFBKTemp -= bTemp;
            } else {
                return bFBKTemp;
            }
    }
}

/**
 */
static Bool dacP96001WaitForShading( pScanData ps )
{
      Bool   bFBKModify;
    Byte   bRSave;
    Byte   bGSave;
    Byte   bBSave;
    ULong  dw;
    pULong pdw;

      DBG( DBG_LOW, "dacP96001WaitForShading()\n" );

    ps->AsicReg.RD_ScanControl |= ps->bLampOn;
    IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);

    if ( ps->GotoShadingPosition( ps )) {

            _DODELAY( 250 );

          /* AdjustMostWideOffset70 (pScanData) -------------------------------*/
            /* FillABitGray (pScanData)*/
            memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
            ps->a_nbNewAdrPointer[8]  =
            ps->a_nbNewAdrPointer[24] = 0x30;

            MotorSetConstantMove( ps, 32 );

            /* SetMaxWideRegister (pScanData) */
            ps->AsicReg.RD_ModeControl = _ModeScan;
            ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE | ps->bLampOn;

            ps->Asic96Reg.RD_MotorControl =
                                            (ps->MotorOn | ps->IgnorePF | _MotorDirForward);
            ps->AsicReg.RD_ModelControl =
                                (_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0);

            ps->AsicReg.RD_Dpi    = 300;
            ps->AsicReg.RD_Origin = 64 + 8;
            ps->AsicReg.RD_Pixels = 2700;
            IOPutOnAllRegisters( ps );

            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                ps->Asic96Reg.RD_MotorControl );

            /* ReadMaxWideLine */
            dacP96ReadDataWithinOneSecond( ps, 2700, 5 );

          /* AdjustOffset70Proc (pScanData)------------------------------------*/
            {
                ULong dwSum, dw, dwLeft, dwCenter;

                /* AverageWideBank (pScanData) */
                for( dwSum = 0, dw = 0; dw < 2700; dw++ )
                        dwSum += (ULong)ps->pPrescan16[dw];
      
                  dwSum /= 2700UL;

                if( dwSum <= 0x80 ) {

                        memcpy( ps->pScanBuffer1, ps->pPrescan16, 140 );
                        memcpy( ps->pScanBuffer1 + 140,
                                          ps->pPrescan16 + _BUF_SIZE_BASE_CONST * 2, 140);

                        /* BlackOffsetCheck (pScanData) */
                        for( dw = dwLeft = 0; dw < 140; dw++ ) {
                            if( ps->pScanBuffer1[dw] >= 0xe0 )
                                    dwLeft++;
                            else
                                    break;
                        }

                        /* WhiteOffsetCheck (pScanData) */
                        for( dw = 140, dwCenter = 0; dw < 280; dw++ ) {
                            if( ps->pScanBuffer1[dw] < 0xe0 )
                                    dwCenter++;
                            else
                                    break;
                        }

                        if (dwLeft) {
                            ps->Offset70 = (dwLeft + dwCenter) / 2 + 14;
                        } else {
                            if (dwCenter == 140)
                                    ps->Offset70 = 70;
                        else
                                    ps->Offset70 = dwCenter / 2 + 2;
                        }
            }
            }

            memset( ps->pPrescan16, 0, ps->BufferSizePerModel * 3 );
            dacP96001WriteBackToColorShadingRam( ps );

            /* SetFBK */
            if((IODataRegisterFromScanner(ps, ps->RegReadIOBufBus) & 0x0f) == 0x0f)
            bFBKModify = 0;
            else
                bFBKModify = 1;

            dacP96001FBKReading(ps, 0x10, ps->RegRedDCAdjust,  &bRSave,bFBKModify);
            dacP96001FBKReading(ps, 0x30, ps->RegGreenDCAdjust,&bGSave,bFBKModify);
            dacP96001FBKReading(ps, 0x20, ps->RegBlueDCAdjust, &bBSave,bFBKModify);

            ps->OpenScanPath( ps );
            IODataToRegister( ps, ps->RegRedDCAdjust,   (Byte)(bRSave + 2));
            IODataToRegister( ps, ps->RegGreenDCAdjust, (Byte)(bGSave + 2));
            IODataToRegister( ps, ps->RegBlueDCAdjust,  bBSave);
            ps->CloseScanPath( ps );

            /* Turn off and then turn on motor */
            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                 (Byte)(ps->Asic96Reg.RD_MotorControl & ~ps->MotorOn));
            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                                                     ps->Asic96Reg.RD_MotorControl );

            /* FillABitColor (pScanData) */
            pdw = (pULong)ps->a_nbNewAdrPointer;
            for( dw = 0; dw < 4; dw++) {
                *pdw++ = 0x40;
                *pdw++ = 0x2030140;
            }

            IOSetToMotorRegister( ps );

            /* SetShadingRegister (pScanData) */
            ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                                                        ps->Asic96Reg.RD_MotorControl );
            ps->AsicReg.RD_ModeControl    = _ModeScan;
            ps->AsicReg.RD_LineControl    = ps->TimePerLine;
            ps->AsicReg.RD_ScanControl    = _SCAN_BYTEMODE | ps->bLampOn;
            ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;

            ps->AsicReg.RD_ModelControl =
                                    (_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0);
            ps->AsicReg.RD_Dpi    = 150;
            ps->AsicReg.RD_Origin = (UShort)(64 + 8 + ps->Offset70);
            ps->AsicReg.RD_Pixels = ps->BufferSizeBase;
            IOPutOnAllRegisters( ps );

            IOCmdRegisterToScanner( ps, ps->RegMotorControl,
                                  (Byte)(ps->MotorOn | ps->IgnorePF | _MotorDirForward));

            dacP96ReadColorShadingLine( ps );

            /* ModifyShadingColor (pScanData) */
            dacP96001ModifyShadingColor( ps->pPrescan16, 103 );
            dacP96001ModifyShadingColor( ps->pPrescan16 +
                                                                  _BUF_SIZE_BASE_CONST * 2 * 2, 97);
            dacP96001WriteBackToColorShadingRam( ps );
            return _TRUE;
    }
    return _FALSE;
}

/**
 */
static void dacP98003GainOffsetToDAC( pScanData ps, Byte ch, Byte reg, Byte d )
{
    if( ps->Device.bDACType == _DA_SAMSUNG8531 ) {

      IODataToRegister( ps, ps->RegADCAddress, 0 );
      IODataToRegister( ps, ps->RegADCData, ch );
      IODataToRegister( ps, ps->RegADCSerialOutStr, ch);
    }

    IODataToRegister( ps, ps->RegADCAddress, reg );
    IODataToRegister( ps, ps->RegADCData, d );
    IODataToRegister( ps, ps->RegADCSerialOutStr, d );
}

/**
 */
static void dacP98003AdjustRGBGain( pScanData ps )
{
    ULong i;
    Byte  bHi[3];

    DBG( DBG_LOW, "dacP98003AdjustRGBGain()\n" );

    ps->Shade.Gain.Colors.Red   =
    ps->Shade.Gain.Colors.Green =
    ps->Shade.Gain.Colors.Blue  =  ps->Shade.bUniGain;

    ps->Shade.Hilight.Colors.Red   =
    ps->Shade.Hilight.Colors.Green =
    ps->Shade.Hilight.Colors.Blue  = 0;

    ps->Shade.bGainHigh = _GAIN_P98003_HIGH;
    ps->Shade.bGainLow  = _GAIN_P98003_LOW;

    ps->Shade.fStop = _FALSE;

    for( i = 10; i-- && !ps->Shade.fStop; ) {

        ps->Shade.fStop = _TRUE;

        /* SetRGBGainRegister () */
        IODataToRegister( ps, ps->RegModeControl, _ModeIdle );

        ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
        IOSelectLampSource( ps );
      IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );

        DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );

        ps->AsicReg.RD_ModeControl   = _ModeScan;
        ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
        ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;

      if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
              ps->AsicReg.RD_Origin = (UShort)ps->Device.DataOriginX >> 1;
      else
              ps->AsicReg.RD_Origin = (UShort)ps->Device.DataOriginX;

        ps->AsicReg.RD_Dpi    = 300;
        ps->AsicReg.RD_Pixels = 2560;

      /* PauseColorMotorRunStates () */
      memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
          ps->a_nbNewAdrPointer[1] = 0x77;      

          IOPutOnAllRegisters( ps );

      _DODELAY( 70 );

        /* read one shading line and work on it */
          if( IOReadOneShadingLine( ps, (pUChar)ps->Bufs.b1.pShadingRam, 2560)) {

            if ( ps->DataInf.wPhyDataType <= COLOR_256GRAY ) {

                  bHi[1] = DacP98003SumGains(
                                 (pUChar)ps->Bufs.b1.pShadingRam + 2560, 2560);
                    if( bHi[1] )
                      DacP98003AdjustGain( ps, _CHANNEL_GREEN, bHi[1] );
                    else {
                      ps->Shade.fStop = _FALSE;
                    }
          } else {
                  bHi[0] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam, 2560);
                    bHi[1] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam + 2560, 2560);
                  bHi[2] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam + 5120, 2560);

                    if (!bHi[0] || !bHi[1] || !bHi[2] ) {
                      ps->Shade.fStop = _FALSE;
                    } else {
                      DacP98003AdjustGain( ps, _CHANNEL_RED,   bHi[0] );
                      DacP98003AdjustGain( ps, _CHANNEL_GREEN, bHi[1] );
                      DacP98003AdjustGain( ps, _CHANNEL_BLUE,  bHi[2] );
                    }
          }
          } else
          ps->Shade.fStop = _FALSE;
    }

#ifdef DEBUG
    if( !ps->Shade.fStop )
        DBG( DBG_LOW, "dacP98003AdjustRGBGain() - all loops done!!!\n" );
#endif

    DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );
}

/**
 */
static UShort dacP98003SumDarks( pScanData ps, pUShort data )
{
    UShort i, loop;

    if( ps->Device.bCCDID == _CCD_3799 ) {
      if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
          data += 0x18;
          else
              data += 0x30;
    } else {
      if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
              data += 0x18;
      else
              data += 0x20;
    }

    for( i = 0, loop = 16; loop--; data++ )
      i += *data;
    i >>= 4;

    return i;
}

/**
 */
static void dacP98003AdjustShadingWaveform( pScanData ps )
{
    Byte           b;
    UShort         count, wR, wG, wB, tmp;
    DataType       var;
    DataPointer    pvar, psum;
    RBGPtrDef      cp;
    pRGBUShortDef  pRGB, pwsum;

    DBG( DBG_LOW, "dacP98003AdjustShadingWaveForm()\n" );

    memset( ps->Bufs.b2.pSumBuf, 0, (5400 * 3 * 2));

    /* SetAdjustShadingRegister () */
    IODataToRegister( ps, ps->RegModeControl, _ModeIdle );

    ps->AsicReg.RD_LineControl    = _LOBYTE(ps->Shade.wExposure);
    ps->AsicReg.RD_ExtLineControl = _HIBYTE(ps->Shade.wExposure);
    IODataToRegister( ps, ps->RegExtendedLineControl,
                      ps->AsicReg.RD_ExtLineControl );
    IODataToRegister( ps, ps->RegLineControl, ps->AsicReg.RD_LineControl );

    ps->AsicReg.RD_XStepTime    = _LOBYTE(ps->Shade.wExposure);
    ps->AsicReg.RD_ExtXStepTime = _HIBYTE(ps->Shade.wExposure);
    IODataToRegister( ps, ps->RegExtendedXStep, ps->AsicReg.RD_ExtXStepTime );
    IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime );

    ps->AsicReg.RD_ModeControl   = _ModeScan;
    ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
    ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;

      if( ps->Shade.bIntermediate & _ScanMode_AverageOut ) {

      ps->AsicReg.RD_Dpi     = 300;
      ps->AsicReg.RD_Pixels  = 2700;
      ps->Shade.shadingBytes = 2700 * 2;
    } else {
      ps->AsicReg.RD_Dpi     = 600;
      ps->AsicReg.RD_Pixels  = 5400;
      ps->Shade.shadingBytes = 5400 * 2;
    }
    ps->AsicReg.RD_Origin = _SHADING_BEGINX;

    for( pvar.pdw = (pULong)ps->a_nbNewAdrPointer,
         var.dwValue = _SCANSTATE_BYTES >> 2; var.dwValue--; pvar.pdw++) {
      *pvar.pdw = 0x00f00080;
    }

    ps->Scan.fRefreshState = _FALSE;
    IOPutOnAllRegisters( ps );
    _DODELAY( 55 );

    /* SetupHilightShadow () */
    if( ps->Shade.pHilight ) {

        memset( ps->Shade.pHilight, 0,
              ps->Shade.shadingBytes * ps->Shade.skipHilight * 3 );

        memset((pUChar)ps->Shade.pHilight +
                ps->Shade.shadingBytes * ps->Shade.skipHilight * 3, 0xff,
                      ps->Shade.shadingBytes * ps->Shade.skipShadow * 3 );
    }


    for( count = 32; count--;) {

        IOReadOneShadingLine( ps,
                             ((pUChar)ps->Bufs.b1.pShadingRam)+_SHADING_BEGINX,
                                                           ps->Shade.shadingBytes );

          /* SaveHilightShadow() */
      if( ps->Shade.pHilight ) {

            if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

                  cp.red.usp   = ps->Bufs.b1.pShadingRam + _SHADING_BEGINX;
                    cp.green.usp = cp.red.usp   + ps->AsicReg.RD_Pixels;
                  cp.blue.usp  = cp.green.usp + ps->AsicReg.RD_Pixels;
                    pvar.pusrgb = (pRGBUShortDef)ps->Shade.pHilight +
                                                         _SHADING_BEGINX;

                  for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                      pRGB = pvar.pusrgb++;
                        wR = *cp.red.usp;
                      wG = *cp.green.usp;
                        wB = *cp.blue.usp;

                      for( b = ps->Shade.skipHilight; b--;
                                               pRGB += ps->AsicReg.RD_Pixels) {

                              if( wR > pRGB->Red ) {
                                  tmp = wR;
                                  wR  = pRGB->Red;
                                  pRGB->Red = tmp;
                              }
                              if( wG > pRGB->Green ) {
                                  tmp = wG;
                                  wG  = pRGB->Green;
                                  pRGB->Green = tmp;
                              }
                              if( wB > pRGB->Blue ) {
                                  tmp = wB;
                                  wB  = pRGB->Blue;
                                  pRGB->Blue = tmp;
                              }
                      }

                      wR = *cp.red.usp++;
                        wG = *cp.green.usp++;
                      wB = *cp.blue.usp++;
                        for(b = ps->Shade.skipShadow; b--;
                                               pRGB += ps->AsicReg.RD_Pixels) {

                              if (wR < pRGB->Red) {
                                  tmp = wR;
                                  wR  = pRGB->Red;
                                  pRGB->Red = tmp;
                              }
                              if (wG < pRGB->Green) {
                                  tmp = wG;
                                  wG  = pRGB->Green;
                                  pRGB->Green = tmp;
                              }
                              if (wB < pRGB->Blue) {
                                  tmp = wB;
                                  wB  = pRGB->Blue;
                                  pRGB->Blue = tmp;
                              }
                      }
              }

          } else {

                  cp.green.usp = ps->Bufs.b1.pShadingRam +
                               ps->AsicReg.RD_Pixels + _SHADING_BEGINX;
                  cp.blue.usp  = (pUShort) ps->Shade.pHilight + _SHADING_BEGINX;

                  for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                      cp.red.usp = cp.blue.usp++;
                        wG = *cp.green.usp;
                      for( b = ps->Shade.skipHilight; b--;
                                          cp.red.usp += ps->AsicReg.RD_Pixels) {
                              if( wG > *cp.red.usp ) {
                                  tmp = wG;
                                  wG  = *cp.red.usp;
                                  *cp.red.usp = tmp;
                              }
                      }
                        wG = *cp.green.usp++;
                      for (b = ps->Shade.skipShadow; b--;
                                              cp.red.usp += ps->AsicReg.RD_Pixels) {
                              if( wG < *cp.red.usp ) {
                                  tmp = wG;
                                  wG  = *cp.red.usp;
                                  *cp.red.usp = tmp;
                              }
                      }
                    }
          }
          }

      /* AddToSumBuffer() */
            if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

          cp.red.usp   = ps->Bufs.b1.pShadingRam + _SHADING_BEGINX;
              cp.green.usp = cp.red.usp   + ps->AsicReg.RD_Pixels;
              cp.blue.usp  = cp.green.usp + ps->AsicReg.RD_Pixels;

          pvar.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;

              for( var.dwValue = (ULong)ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
               var.dwValue--;
                 pvar.pulrgb++, cp.red.usp++, cp.green.usp++, cp.blue.usp++) {
                  pvar.pulrgb->Red   += (ULong)*cp.red.usp;
                    pvar.pulrgb->Green += (ULong)*cp.green.usp;
                  pvar.pulrgb->Blue  += (ULong)*cp.blue.usp;
              }

      } else {

          cp.green.usp = ps->Bufs.b1.pShadingRam + ps->AsicReg.RD_Pixels +
                                                               _SHADING_BEGINX;
              pvar.pdw  = (pULong)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
              for(var.dwValue = (ULong)ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                  var.dwValue--; pvar.pdw++, cp.green.usp++) {
                    *pvar.pdw += (ULong)*cp.green.usp;
          }
        }

          if( IOReadFifoLength( ps ) < ps->AsicReg.RD_Pixels )
           IORegisterToScanner( ps, ps->RegRefreshScanState );
    }

    /* AverageAfterSubHilightShadow() */
    if( ps->Shade.pHilight ) {

        if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

                psum.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
              pwsum       = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
              pvar.pusrgb = (pRGBUShortDef)ps->Shade.pHilight + _SHADING_BEGINX;

                for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                  pRGB = pvar.pusrgb++;

                  for( b = ps->Shade.skipHilight + ps->Shade.skipShadow;
                                        b--; pRGB += ps->AsicReg.RD_Pixels ) {

                      psum.pulrgb->Red   -= (ULong)pRGB->Red;
                  psum.pulrgb->Green -= (ULong)pRGB->Green;
                      psum.pulrgb->Blue  -= (ULong)pRGB->Blue;
                  }

                  pwsum->Red   = (UShort)(psum.pulrgb->Red   / ps->Shade.dwDiv);
              pwsum->Green = (UShort)(psum.pulrgb->Green / ps->Shade.dwDiv);
                  pwsum->Blue  = (UShort)(psum.pulrgb->Blue  / ps->Shade.dwDiv);
                  psum.pulrgb++;
                  pwsum++;
              }
        } else {
                cp.green.ulp = (pULong)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
            cp.blue.usp  = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
              pvar.pw      = (pUShort)ps->Shade.pHilight  + _SHADING_BEGINX;

                for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                  cp.red.usp = pvar.pw++;

              for( b = ps->Shade.skipHilight + ps->Shade.skipShadow;
                                     b--; cp.red.usp += ps->AsicReg.RD_Pixels )
                        *cp.green.ulp -= *cp.red.usp;

                  *cp.blue.usp = (UShort)(*cp.green.ulp / ps->Shade.dwDiv);
                  cp.blue.usp++;
                  cp.green.ulp++;
                }
        }
    } else {
            if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

              psum.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf  + _SHADING_BEGINX;
            pwsum       = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;

              for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                  pwsum->Red   = (UShort)(psum.pulrgb->Red   >> 5);
              pwsum->Green = (UShort)(psum.pulrgb->Green >> 5);
                  pwsum->Blue  = (UShort)(psum.pulrgb->Blue  >> 5);
                  psum.pulrgb++;
                      pwsum++;
                }
        } else {
              cp.green.ulp = (pULong)ps->Bufs.b2.pSumBuf  + _SHADING_BEGINX;
            cp.blue.usp  = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;

              for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                              var.dwValue--;) {
                  *cp.blue.usp = (UShort)(*cp.green.ulp >> 5);
                  cp.blue.usp++;
                  cp.green.ulp++;
                }
        }
    }

    /* Process negative & transparency here */
    if( ps->DataInf.dwScanFlag & SCANDEF_TPA )
          TPAP98003FindCenterPointer( ps );

    if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
            TPAP98003Reshading( ps );

    pRGB = (pRGBUShortDef)&ps->Shade.pCcdDac->GainResize;

      if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

            pwsum = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;

                for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                            var.dwValue--;) {

              if ((short)(pwsum->Red -= ps->Shade.DarkOffset.Colors.Red) > 0) {
                  pwsum->Red = pwsum->Red * pRGB->Red / 100U;
                  if( pwsum->Red > 0xfff )
                          pwsum->Red = 0xfff;
                } else
                  pwsum->Red = 0;

            if((short)(pwsum->Green -= ps->Shade.DarkOffset.Colors.Green) > 0) {
                  pwsum->Green = pwsum->Green * pRGB->Green / 100U;
                if( pwsum->Green > 0xfff )
                      pwsum->Green = 0xfff;
            } else
                  pwsum->Green = 0;

                if ((short)(pwsum->Blue -= ps->Shade.DarkOffset.Colors.Blue) > 0) {
                pwsum->Blue = pwsum->Blue * pRGB->Blue / 100U;
                  if( pwsum->Blue > 0xfff )
                  pwsum->Blue = 0xfff;
            } else
                  pwsum->Blue = 0;

            wR = (UShort)(pwsum->Red >> 4);
            pwsum->Red <<= 12;
              pwsum->Red |= wR;
            wR = (UShort)(pwsum->Green >> 4);
                pwsum->Green <<= 12;
              pwsum->Green |= wR;
                wR = (UShort)(pwsum->Blue>> 4);
                pwsum->Blue <<= 12;
              pwsum->Blue |= wR;
                pwsum++;
            }
   } else {

            cp.green.usp = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;

          for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
                                                            var.dwValue--;) {

              if((short)(*cp.green.usp -= ps->Shade.DarkOffset.Colors.Green) > 0) {

                  *cp.green.usp = *cp.green.usp * pRGB->Green / 100U;
                  if( *cp.green.usp > 0xfff )
                      *cp.green.usp = 0xfff;
            } else
                  *cp.green.usp = 0;

                wR = (UShort)(*cp.green.usp >> 4);
              *cp.green.usp <<= 12;
                *cp.green.usp |= wR;

                cp.green.usp++;
        }
    }

    /* DownloadShadingAndSetDark() */
    dacP98DownloadShadingTable( ps, ps->Bufs.b2.pSumBuf, (5400 * 3 * 2));
}

/**
 */
static void dacP98003AdjustDark( pScanData ps )
{
    ULong  i;
    UShort wDarks[3];

    DBG( DBG_LOW, "dacP98003AdjustDark()\n" );

    ps->Shade.DarkDAC.Colors = ps->Shade.pCcdDac->DarkDAC.Colors;
    ps->Shade.fStop = _FALSE;

    for( i = 16; i-- && !ps->Shade.fStop;) {

      ps->Shade.fStop = _TRUE;

      /* FillDarkToDAC() */
        DacP98003FillToDAC( ps, &ps->Device.RegDACOffset, &ps->Shade.DarkDAC );

        IODataToRegister( ps, ps->RegModeControl, _ModeIdle );

        ps->AsicReg.RD_ScanControl = (_SCAN_12BITMODE + _SCAN_1ST_AVERAGE);
        IOSelectLampSource( ps );
      IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );

        ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
        ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;

        ps->AsicReg.RD_Origin = _SHADING_BEGINX;
        ps->AsicReg.RD_Pixels = 512;

      if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
              ps->AsicReg.RD_Dpi = 300;
      else
              ps->AsicReg.RD_Dpi = 600;


      /* PauseColorMotorRunStates () */
      memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
          ps->a_nbNewAdrPointer[1] = 0x77;      

          IOPutOnAllRegisters( ps );
      _DODELAY( 70 );

        /* read one shading line and work on it */
          if( IOReadOneShadingLine(ps, (pUChar)ps->Bufs.b1.pShadingRam, 512*2)) {

            if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

                  wDarks[0] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam );
                wDarks[1] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
                                               ps->AsicReg.RD_Pixels );
                    wDarks[2] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
                                               ps->AsicReg.RD_Pixels * 2UL);

                if( !wDarks[0] || !wDarks[1] || !wDarks[2] ) {
                        ps->Shade.fStop = _FALSE;
                    } else {
                        ps->Shade.DarkOffset.wColors[0] = wDarks[0];
                        ps->Shade.DarkOffset.wColors[1] = wDarks[1];
                        ps->Shade.DarkOffset.wColors[2] = wDarks[2];
                        (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
                                               _CHANNEL_RED, wDarks[0] );
                        (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
                                               _CHANNEL_GREEN, wDarks[1] );
                      (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
                                               _CHANNEL_BLUE, wDarks[2] );
                  }
              } else {
                  wDarks[1] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
                                               ps->AsicReg.RD_Pixels );
                  if (!wDarks[1] )
                      ps->Shade.fStop = _FALSE;
                  else {
                      ps->Shade.DarkOffset.wColors[1] = wDarks[1];
                        (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
                                               _CHANNEL_GREEN, wDarks[1] );
                  }
              }
      } else
            ps->Shade.fStop = _FALSE;
    }

    /* CalculateDarkDependOnCCD() */
      if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
      (*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_RED   );
      (*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_GREEN );
      (*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_BLUE  );
    } else
      (*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_GREEN );
}

/**
 */
static Bool dacP98003WaitForShading( pScanData ps )
{
    ULong i, tmp;
    Byte  bScanControl;

      DBG( DBG_LOW, "dacP98003WaitForShading()\n" );

      /*    
       * before getting the shading data, (re)init the ASIC
       */
      ps->ReInitAsic( ps, _TRUE );

    ps->Shade.DarkOffset.Colors.Red   = 0;
    ps->Shade.DarkOffset.Colors.Green = 0;
    ps->Shade.DarkOffset.Colors.Blue  = 0;

    IORegisterToScanner( ps, ps->RegResetMTSC );

    IODataToRegister( ps, ps->RegModelControl, ps->AsicReg.RD_ModelControl);
    IODataToRegister( ps, ps->RegMotorDriverType,
                                            ps->AsicReg.RD_MotorDriverType );
    IODataToRegister( ps, ps->RegScanControl1,
                                        (_SCANSTOPONBUFFULL| _MFRC_BY_XSTEP));
    ps->GotoShadingPosition( ps );

    bScanControl = ps->AsicReg.RD_ScanControl;

    /* SetShadingMapForGainDark */
    memset( ps->Bufs.b2.pSumBuf, 0xff, (5400 * 3 * 2));

    /* DownloadShadingAndSetDark() */
    dacP98DownloadShadingTable( ps, ps->Bufs.b2.pSumBuf, (5400 * 3 * 2));

    for( i = 0, tmp = 0; i < 1024; tmp += 0x01010101, i += 4 ) {
      ps->Bufs.b1.Buf.pdw[i]   =
      ps->Bufs.b1.Buf.pdw[i+1] =
      ps->Bufs.b1.Buf.pdw[i+2] =
      ps->Bufs.b1.Buf.pdw[i+3] = tmp;
    }

    memcpy( ps->Bufs.b1.pShadingMap + 4096, ps->Bufs.b1.pShadingMap, 4096 );
    memcpy( ps->Bufs.b1.pShadingMap + 8192, ps->Bufs.b1.pShadingMap, 4096 );
    dacP98DownloadMapTable( ps, ps->Bufs.b1.pShadingMap );

    DBG( DBG_LOW, "wExposure = %u\n", ps->Shade.wExposure);
    DBG( DBG_LOW, "wXStep    = %u\n", ps->Shade.wXStep);

    ps->AsicReg.RD_LineControl    = (_LOBYTE(ps->Shade.wExposure));
    ps->AsicReg.RD_ExtLineControl = (_HIBYTE(ps->Shade.wExposure));
    IODataToRegister(ps, ps->RegExtendedLineControl,
                                            ps->AsicReg.RD_ExtLineControl );
    IODataToRegister(ps, ps->RegLineControl, ps->AsicReg.RD_LineControl );

    dacP98003AdjustRGBGain( ps );
    dacP98003AdjustDark( ps );
    dacP98003AdjustShadingWaveform( ps );

    ps->AsicReg.RD_ScanControl = bScanControl;

      /* here we have to download the table in any case...*/
      dacP98DownloadMapTable( ps, ps->a_bMapTable );

    MotorP98003BackToHomeSensor( ps );

    return _TRUE;
}

/************************ exported functions *********************************/

/**
 */
_LOC int DacInitialize( pScanData ps )
{
      DBG( DBG_HIGH, "DacInitialize()\n" );

      if( NULL == ps )
            return _E_NULLPTR;

      /*
       * depending on the asic, we set some functions
       */
      if( _ASIC_IS_98003 == ps->sCaps.AsicID ) {

            ps->WaitForShading = dacP98003WaitForShading;

    } else if( _ASIC_IS_98001 == ps->sCaps.AsicID ) {

            ps->WaitForShading = dacP98WaitForShading;

      } else if( _ASIC_IS_96003 == ps->sCaps.AsicID ) {

            ps->WaitForShading = dacP96003WaitForShading;

      } else if( _ASIC_IS_96001 == ps->sCaps.AsicID ) {

            ps->WaitForShading = dacP96001WaitForShading;

      } else {

            DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" );
            return _E_NOSUPP;
      }
      return _OK;
}

/** Fill out the R/G/B GainOut value
 */
02476 _LOC void DacP98FillGainOutDirectPort( pScanData ps )
{
      ps->OpenScanPath( ps );

    IODataRegisterToDAC( ps, 0x28, ps->bRedGainIndex   );
    IODataRegisterToDAC( ps, 0x29, ps->bGreenGainIndex );
    IODataRegisterToDAC( ps, 0x2a, ps->bBlueGainIndex  );

      ps->CloseScanPath( ps );
}

/**
 */
_LOC void DacP98FillShadingDarkToShadingRegister( pScanData ps )
{
      pUChar pValue;
      Byte   bReg;

      DBG( DBG_LOW, "DacP98FillShadingDarkToShadingRegister()\n" );

      ps->AsicReg.RD_RedDarkOff   = ps->Shade.DarkOffset.Colors.Red;
    ps->AsicReg.RD_GreenDarkOff = ps->Shade.DarkOffset.Colors.Green;
    ps->AsicReg.RD_BlueDarkOff  = ps->Shade.DarkOffset.Colors.Blue;

    pValue = (pUChar)&ps->AsicReg.RD_RedDarkOff;
    for (bReg = ps->RegRedChDarkOffsetLow; bReg <= ps->RegBlueChDarkOffsetHigh;
             bReg++, pValue++) {
            
            IODataToRegister( ps, bReg, *pValue );
      }
}

/**
 */
_LOC void DacP98AdjustDark( pScanData ps )
{
      Byte bCorrectTimes;           /* used to be a global var !*/

      DBG( DBG_LOW, "DacP98AdjustDark()\n" );

    ps->Shade.pCcdDac->DarkDAC.Colors.Red   = ps->bsPreRedDAC;
    ps->Shade.pCcdDac->DarkDAC.Colors.Green = ps->bsPreGreenDAC;
    ps->Shade.pCcdDac->DarkDAC.Colors.Blue  = ps->bsPreBlueDAC;

    if( ps->DataInf.dwScanFlag & SCANDEF_Negative ) {
            bCorrectTimes = 6;
      } else {
            bCorrectTimes = 5;
      }

/* CHANGE
** original code seems to be buggy : for (bCorrectTimes ; bCorrectTimes--;) {
*/
      for (;bCorrectTimes ; bCorrectTimes-- ) {

      ps->OpenScanPath( ps );
            dacP98FillDarkDAC( ps );
            dacP98SetReadFBKRegister( ps );
            ps->CloseScanPath( ps );

      IOPutOnAllRegisters( ps );

            ps->PauseColorMotorRunStates( ps );       /* stop scan states */

            IOReadOneShadingLine( ps, ps->pScanBuffer1, 512*2 );

            dacP98FillChannelDarkLevelControl( ps );

            if(dacP98CheckChannelDarkLevel( ps ))
            break;
    }

      ps->Shade.DarkOffset.Colors.Red=
                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Red,
                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Red,
                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Red );

    ps->Shade.DarkOffset.Colors.Green =
                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Green,
                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Green,
                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Green );

    ps->Shade.DarkOffset.Colors.Blue  =
                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Blue,
                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue,
                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Blue );
}

/**
 */
_LOC void DacP96WriteBackToGammaShadingRAM( pScanData ps )
{
      /* ModifyGammaShadingOffset(ps) */
    ps->OpenScanPath( ps);

    IODataToRegister( ps, ps->RegRedChShadingOffset,
                                ps->Asic96Reg.u28.RD_RedChShadingOff );
      IODataToRegister( ps, ps->RegGreenChShadingOffset,
           (Byte)((ULong)ps->Asic96Reg.u29.RD_GreenChShadingOff * 96UL/100UL));

      IODataToRegister( ps, ps->RegBlueChShadingOffset,
                      (Byte)((ULong)ps->Asic96Reg.RD_BlueChShadingOff * 91UL/100UL));

    ps->CloseScanPath( ps );

      dacP96WriteLinearGamma( ps, ps->pPrescan16, 256, ps->ShadingBankRed);
      dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize,
                                                                      256, ps->ShadingBankGreen);
      dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
                                                                        256, ps->ShadingBankBlue);
}

/**
 */
_LOC void DacP98003FillToDAC( pScanData ps, pRGBByteDef regs, pColorByte data )
{
      if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {

        dacP98003GainOffsetToDAC( ps, _DAC_RED, regs->Red, data->Colors.Red );
        dacP98003GainOffsetToDAC( ps, _DAC_GREENCOLOR,
                                            regs->Green, data->Colors.Green );
        dacP98003GainOffsetToDAC( ps, _DAC_BLUE,
                                            regs->Blue, data->Colors.Blue );
    } else {
        dacP98003GainOffsetToDAC( ps, _DAC_GREENMONO, regs->Green,
                                                                  data->Colors.Green );
    }
}

/**
 */
_LOC void DacP98003AdjustGain( pScanData ps, ULong color, Byte hilight )
{
    if( hilight < ps->Shade.bGainLow ) {

        if( ps->Shade.Hilight.bColors[color] < ps->Shade.bGainHigh ) {

          ps->Shade.fStop = _FALSE;
          ps->Shade.Hilight.bColors[color] = hilight;

          if( hilight <= (Byte)(ps->Shade.bGainLow - hilight))
                  ps->Shade.Gain.bColors[color] += ps->Shade.bGainDouble;
              else
                ps->Shade.Gain.bColors[color]++;
          }
    } else {
      if( hilight > ps->Shade.bGainHigh ) {
          ps->Shade.fStop = _FALSE;
              ps->Shade.Hilight.bColors[color] = hilight;
          ps->Shade.Gain.bColors[color]--;
      } else
          ps->Shade.Hilight.bColors[color] = hilight;
      }

    if( ps->Shade.Gain.bColors[color] > ps->Shade.bMaxGain ) {
        ps->Shade.Gain.bColors[color] = ps->Shade.bMaxGain;
    }
}

/**
 */
_LOC Byte DacP98003SumGains( pUChar pb, ULong pixelsLine )
{
    Byte   bHilight, tmp;
    ULong  dwPixels, dwAve;
    UShort sum;

    for( bHilight = 0, dwPixels = pixelsLine >> 4; dwPixels--; ) {

      for( sum = 0, dwAve = 16; dwAve--; pb++)
              sum += (UShort)*pb;

      sum >>= 4;
        tmp = (Byte)sum;

          if( tmp > bHilight )
              bHilight = tmp;
    }
    return bHilight;
}

/* END PLUSTEK-PP_DAC.C .....................................................*/

Generated by  Doxygen 1.6.0   Back to index