/*............................................................................. * Project : SANE library for Plustek parallelport flatbed scanners. *............................................................................. */ /* @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 * 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 * . *
* 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" /************************** 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 */ _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 .....................................................*/