/* @file u12-shading.c - * @brief all the shading functions * * based on sources acquired from Plustek Inc. * Copyright (C) 2003-2004 Gerhard Jaeger * * History: * - 0.01 - initial version * - 0.02 - * . *
* 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, see . * * 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. *
*/ #define _GAIN_HIGH 240 /* Volt. max. value */ #define _GAIN_LOW 220 /* Volt. min. value */ #define _CHANNEL_RED 0 #define _CHANNEL_GREEN 1 #define _CHANNEL_BLUE 2 /* for DAC programming */ #define _VALUE_CONFIG 0x51 #define _DAC_RED (SANE_Byte)(_VALUE_CONFIG | 0x00) #define _DAC_GREENCOLOR (SANE_Byte)(_VALUE_CONFIG | 0x04) #define _DAC_GREENMONO (SANE_Byte)(_VALUE_CONFIG | 0x06) #define _DAC_BLUE (SANE_Byte)(_VALUE_CONFIG | 0x08) /* forward declarations ... */ static void u12tpa_Reshading( U12_Device * ); static void u12tpa_FindCenterPointer( U12_Device * ); /** */ static void u12shading_DownloadShadingTable( U12_Device *dev, SANE_Byte *buf, u_long len ) { SANE_Byte *val, *rb; SANE_Byte reg, regs[20]; int c; DBG( _DBG_INFO, "u12shading_DownloadShadingTable()\n" ); u12io_DataToRegister( dev, REG_MODECONTROL, _ModeShadingMem ); u12io_DataToRegister( dev, REG_MEMORYLO, 0 ); u12io_DataToRegister( dev, REG_MEMORYHI, 0 ); /* set 12 bits output color */ u12io_DataToRegister( dev, REG_SCANCONTROL, (SANE_Byte)(dev->regs.RD_ScanControl | _SCAN_12BITMODE)); u12io_MoveDataToScanner( dev, buf, len ); regs[0] = REG_MODECONTROL; regs[1] = _ModeScan; /* FillShadingDarkToShadingRegister() */ dev->regs.RD_RedDarkOff = dev->shade.DarkOffset.Colors.Red; dev->regs.RD_GreenDarkOff = dev->shade.DarkOffset.Colors.Green; dev->regs.RD_BlueDarkOff = dev->shade.DarkOffset.Colors.Blue; val = (SANE_Byte*)&dev->regs.RD_RedDarkOff; rb = ®s[2]; c = 1; for( reg = REG_REDCHDARKOFFSETLO; reg <= REG_BLUECHDARKOFFSETHI; reg++, val++) { *(rb++) = reg; *(rb++) = *val; c++; } u12io_DataToRegs( dev, regs, c ); } /** */ static SANE_Status u12shadingAdjustShadingWaveform( U12_Device *dev ) { SANE_Byte b; u_short count, wR, wG, wB, tmp; DataType var; DataPointer pvar, psum; RBGPtrDef cp; RGBUShortDef *pRGB, *pwsum; u_long shadingBytes; DBG( _DBG_INFO, "u12shading_AdjustShadingWaveForm()\n" ); memset( &cp, 0, sizeof(RBGPtrDef)); memset( dev->bufs.b2.pSumBuf, 0, (5400 * 3 * 2)); u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle ); dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure); dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure); u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL, dev->regs.RD_ExtLineControl ); u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl ); dev->regs.RD_XStepTime = _LOBYTE(dev->shade.wExposure); dev->regs.RD_ExtXStepTime = _HIBYTE(dev->shade.wExposure); u12io_DataToRegister( dev, REG_EXTENDEDXSTEP, dev->regs.RD_ExtXStepTime ); u12io_DataToRegister( dev, REG_XSTEPTIME, dev->regs.RD_XStepTime ); dev->regs.RD_ModeControl = _ModeScan; dev->regs.RD_StepControl = _MOTOR0_SCANSTATE; dev->regs.RD_Motor0Control = _FORWARD_MOTOR; if( dev->shade.intermediate & _ScanMode_AverageOut ) { dev->regs.RD_Dpi = 300; dev->regs.RD_Pixels = 2700; shadingBytes = 2700 * 2; } else { dev->regs.RD_Dpi = 600; dev->regs.RD_Pixels = 5400; shadingBytes = 5400 * 2; } dev->regs.RD_Origin = _SHADING_BEGINX; for( pvar.pdw = (u_long*)dev->scanStates, var.dwValue = _SCANSTATE_BYTES >> 2; var.dwValue--; pvar.pdw++) { *pvar.pdw = 0x00f00080; } dev->scan.refreshState = SANE_FALSE; u12io_PutOnAllRegisters( dev ); /* _DODELAY( 100 ); */ if( dev->shade.pHilight ) { memset( dev->shade.pHilight, 0, shadingBytes * dev->shade.skipHilight * 3 ); memset((SANE_Byte*)dev->shade.pHilight + shadingBytes * dev->shade.skipHilight * 3, 0xff, shadingBytes * dev->shade.skipShadow * 3 ); } for( count = 32; count--; ) { if( u12io_IsEscPressed()) { DBG( _DBG_INFO, "* CANCEL detected!\n" ); return SANE_STATUS_CANCELLED; } u12io_ReadOneShadingLine( dev, ((SANE_Byte*)dev->bufs.b1.pShadingRam)+ _SHADING_BEGINX, shadingBytes ); if( dev->shade.pHilight ) { if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { cp.red.usp = dev->bufs.b1.pShadingRam + _SHADING_BEGINX; cp.green.usp = cp.red.usp + dev->regs.RD_Pixels; cp.blue.usp = cp.green.usp + dev->regs.RD_Pixels; pvar.pusrgb = (RGBUShortDef*)dev->shade.pHilight + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { pRGB = pvar.pusrgb++; wR = *cp.red.usp; wG = *cp.green.usp; wB = *cp.blue.usp; for( b = dev->shade.skipHilight; b--; pRGB += dev->regs.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 = dev->shade.skipShadow; b--; pRGB += dev->regs.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 = dev->bufs.b1.pShadingRam + dev->regs.RD_Pixels + _SHADING_BEGINX; cp.blue.usp = (u_short*)dev->shade.pHilight + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { cp.red.usp = cp.blue.usp++; wG = *cp.green.usp; for( b = dev->shade.skipHilight; b--; cp.red.usp += dev->regs.RD_Pixels) { if( wG > *cp.red.usp ) { tmp = wG; wG = *cp.red.usp; *cp.red.usp = tmp; } } wG = *cp.green.usp++; for( b = dev->shade.skipShadow; b--; cp.red.usp += dev->regs.RD_Pixels ) { if( wG < *cp.red.usp ) { tmp = wG; wG = *cp.red.usp; *cp.red.usp = tmp; } } } } } /* AddToSumBuffer() */ if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { cp.red.usp = dev->bufs.b1.pShadingRam + _SHADING_BEGINX; cp.green.usp = cp.red.usp + dev->regs.RD_Pixels; cp.blue.usp = cp.green.usp + dev->regs.RD_Pixels; pvar.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--; pvar.pulrgb++, cp.red.usp++, cp.green.usp++, cp.blue.usp++) { pvar.pulrgb->Red += (u_long)*cp.red.usp; pvar.pulrgb->Green += (u_long)*cp.green.usp; pvar.pulrgb->Blue += (u_long)*cp.blue.usp; } } else { cp.green.usp = dev->bufs.b1.pShadingRam + dev->regs.RD_Pixels + _SHADING_BEGINX; pvar.pdw = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--; pvar.pdw++, cp.green.usp++) { *pvar.pdw += (u_long)*cp.green.usp; } } u12io_ResetFifoLen(); if( u12io_GetFifoLength( dev ) < dev->regs.RD_Pixels ) u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE ); } /* AverageAfterSubHilightShadow() */ if( dev->shade.pHilight ) { if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; pvar.pusrgb = (RGBUShortDef*)dev->shade.pHilight + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { pRGB = pvar.pusrgb++; for( b = dev->shade.skipHilight + dev->shade.skipShadow; b--; pRGB += dev->regs.RD_Pixels ) { psum.pulrgb->Red -= (u_long)pRGB->Red; psum.pulrgb->Green -= (u_long)pRGB->Green; psum.pulrgb->Blue -= (u_long)pRGB->Blue; } pwsum->Red = (u_short)(psum.pulrgb->Red / dev->shade.dwDiv); pwsum->Green = (u_short)(psum.pulrgb->Green / dev->shade.dwDiv); pwsum->Blue = (u_short)(psum.pulrgb->Blue / dev->shade.dwDiv); psum.pulrgb++; pwsum++; } } else { cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; cp.blue.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; pvar.pw = (u_short*)dev->shade.pHilight + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { cp.red.usp = pvar.pw++; for( b = dev->shade.skipHilight + dev->shade.skipShadow; b--; cp.red.usp += dev->regs.RD_Pixels ) *cp.green.ulp -= *cp.red.usp; *cp.blue.usp = (u_short)(*cp.green.ulp / dev->shade.dwDiv); cp.blue.usp++; cp.green.ulp++; } } } else { if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { pwsum->Red = (u_short)(psum.pulrgb->Red >> 5); pwsum->Green = (u_short)(psum.pulrgb->Green >> 5); pwsum->Blue = (u_short)(psum.pulrgb->Blue >> 5); psum.pulrgb++; pwsum++; } } else { cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; cp.blue.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { *cp.blue.usp = (u_short)(*cp.green.ulp >> 5); cp.blue.usp++; cp.green.ulp++; } } } /* Process negative & transparency here */ if( dev->DataInf.dwScanFlag & _SCANDEF_TPA ) u12tpa_FindCenterPointer( dev ); if( dev->DataInf.dwScanFlag & _SCANDEF_Negative ) u12tpa_Reshading( dev ); pRGB = (RGBUShortDef*)&dev->shade.pCcdDac->GainResize; if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { if ((short)(pwsum->Red -= dev->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 -= dev->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 -= dev->shade.DarkOffset.Colors.Blue) > 0) { pwsum->Blue = pwsum->Blue * pRGB->Blue / 100U; if( pwsum->Blue > 0xfff ) pwsum->Blue = 0xfff; } else pwsum->Blue = 0; wR = (u_short)(pwsum->Red >> 4); pwsum->Red <<= 12; pwsum->Red |= wR; wR = (u_short)(pwsum->Green >> 4); pwsum->Green <<= 12; pwsum->Green |= wR; wR = (u_short)(pwsum->Blue>> 4); pwsum->Blue <<= 12; pwsum->Blue |= wR; pwsum++; } } else { cp.green.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX; for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX; var.dwValue--;) { if((short)(*cp.green.usp -= dev->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 = (u_short)(*cp.green.usp >> 4); *cp.green.usp <<= 12; *cp.green.usp |= wR; cp.green.usp++; } } u12shading_DownloadShadingTable(dev, dev->bufs.b2.pSumBuf, (5400 * 3 * 2)); return SANE_STATUS_GOOD; } /** */ static void u12shading_GainOffsetToDAC( U12_Device *dev, SANE_Byte ch, SANE_Byte reg, SANE_Byte d ) { if( dev->DACType == _DA_SAMSUNG8531 ) { u12io_DataRegisterToDAC( dev, 0, ch ); } u12io_DataRegisterToDAC( dev, reg, d ); } /** */ static void u12shading_FillToDAC( U12_Device *dev, RGBByteDef *regs, ColorByte *data ) { if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { u12shading_GainOffsetToDAC(dev, _DAC_RED, regs->Red, data->Colors.Red); u12shading_GainOffsetToDAC(dev, _DAC_GREENCOLOR, regs->Green, data->Colors.Green); u12shading_GainOffsetToDAC(dev, _DAC_BLUE, regs->Blue, data->Colors.Blue); } else { u12shading_GainOffsetToDAC(dev, _DAC_GREENMONO, regs->Green, data->Colors.Green); } } /** */ static SANE_Byte u12shading_SumGains( SANE_Byte *pb, u_long pixelsLine ) { SANE_Byte hilight, tmp; u_long dwPixels, dwAve; u_short sum; hilight = 0; for( dwPixels = pixelsLine >> 4; dwPixels--; ) { for( sum = 0, dwAve = 16; dwAve--; pb++ ) sum += (u_short)*pb; sum >>= 4; tmp = (SANE_Byte)sum; if( tmp > hilight ) hilight = tmp; } return hilight; } /** */ static void u12shading_AdjustGain( U12_Device *dev, u_long color, SANE_Byte hilight ) { if( hilight < dev->shade.bGainLow ) { if( dev->shade.Hilight.bColors[color] < dev->shade.bGainHigh ) { dev->shade.fStop = SANE_FALSE; dev->shade.Hilight.bColors[color] = hilight; if( hilight <= (SANE_Byte)(dev->shade.bGainLow - hilight)) dev->shade.Gain.bColors[color] += dev->shade.bGainDouble; else dev->shade.Gain.bColors[color]++; } } else { if( hilight > dev->shade.bGainHigh ) { dev->shade.fStop = SANE_FALSE; dev->shade.Hilight.bColors[color] = hilight; dev->shade.Gain.bColors[color]--; } else { dev->shade.Hilight.bColors[color] = hilight; } } if( dev->shade.Gain.bColors[color] > dev->shade.bMaxGain ) { dev->shade.Gain.bColors[color] = dev->shade.bMaxGain; } } /** */ static SANE_Status u12shading_AdjustRGBGain( U12_Device *dev ) { int i; SANE_Byte hi[3]; DBG( _DBG_INFO, "u12shading_AdjustRGBGain()\n" ); dev->shade.Gain.Colors.Red = dev->shade.Gain.Colors.Green = dev->shade.Gain.Colors.Blue = dev->shade.bUniGain; dev->shade.Hilight.Colors.Red = dev->shade.Hilight.Colors.Green = dev->shade.Hilight.Colors.Blue = 0; dev->shade.bGainHigh = _GAIN_HIGH; dev->shade.bGainLow = _GAIN_LOW; dev->shade.fStop = SANE_FALSE; for( i = 10; i-- && !dev->shade.fStop; ) { if( u12io_IsEscPressed()) { DBG( _DBG_INFO, "* CANCEL detected!\n" ); return SANE_STATUS_CANCELLED; } dev->shade.fStop = SANE_TRUE; u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle ); dev->regs.RD_ScanControl = _SCAN_BYTEMODE; u12hw_SelectLampSource( dev ); u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl ); u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain ); dev->regs.RD_ModeControl = _ModeScan; dev->regs.RD_StepControl = _MOTOR0_SCANSTATE; dev->regs.RD_Motor0Control = _FORWARD_MOTOR; if( dev->shade.intermediate & _ScanMode_AverageOut ) dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X >> 1; else dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X; dev->regs.RD_Dpi = 300; dev->regs.RD_Pixels = 2560; memset( dev->scanStates, 0, _SCANSTATE_BYTES ); dev->scanStates[1] = 0x77; u12io_PutOnAllRegisters( dev ); /* _DODELAY( 100 ); */ /* read one shading line and work on it */ if( u12io_ReadOneShadingLine( dev, (SANE_Byte*)dev->bufs.b1.pShadingRam, 2560)) { if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) { hi[1] = u12shading_SumGains( (SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560); if( hi[1] ) { u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] ); } else { dev->shade.fStop = SANE_FALSE; } } else { hi[0] = u12shading_SumGains( (SANE_Byte*)dev->bufs.b1.pShadingRam, 2560); hi[1] = u12shading_SumGains( (SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560); hi[2] = u12shading_SumGains( (SANE_Byte*)dev->bufs.b1.pShadingRam + 5120, 2560); if (!hi[0] || !hi[1] || !hi[2] ) { dev->shade.fStop = SANE_FALSE; } else { u12shading_AdjustGain( dev, _CHANNEL_RED, hi[0] ); u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] ); u12shading_AdjustGain( dev, _CHANNEL_BLUE, hi[2] ); } } } else dev->shade.fStop = SANE_FALSE; } if( !dev->shade.fStop ) DBG( _DBG_INFO, "u12shading_AdjustRGBGain() - all loops done!!!\n" ); u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain ); return SANE_STATUS_GOOD; } /** */ static u_short u12shading_SumDarks( U12_Device *dev, u_short *data ) { u_short i, loop; if( dev->CCDID == _CCD_3799 ) { if( dev->shade.intermediate & _ScanMode_AverageOut ) data += 0x18; else data += 0x30; } else { if( dev->shade.intermediate & _ScanMode_AverageOut ) data += 0x18; else data += 0x20; } for( i = 0, loop = 16; loop--; data++ ) i += *data; i >>= 4; return i; } /** */ static SANE_Status u12shadingAdjustDark( U12_Device *dev ) { u_long i; u_short wDarks[3]; DBG( _DBG_INFO, "u12shadingAdjustDark()\n" ); dev->shade.DarkDAC.Colors = dev->shade.pCcdDac->DarkDAC.Colors; dev->shade.fStop = SANE_FALSE; for( i = 16; i-- && !dev->shade.fStop;) { if( u12io_IsEscPressed()) { DBG( _DBG_INFO, "* CANCEL detected!\n" ); return SANE_STATUS_CANCELLED; } dev->shade.fStop = SANE_TRUE; u12shading_FillToDAC( dev, &dev->RegDACOffset, &dev->shade.DarkDAC ); u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle ); dev->regs.RD_ScanControl = (_SCAN_12BITMODE + _SCAN_1ST_AVERAGE); u12hw_SelectLampSource( dev ); u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl ); dev->regs.RD_StepControl = _MOTOR0_SCANSTATE; dev->regs.RD_Motor0Control = _FORWARD_MOTOR; dev->regs.RD_Origin = _SHADING_BEGINX; dev->regs.RD_Pixels = 512; if( dev->shade.intermediate & _ScanMode_AverageOut ) dev->regs.RD_Dpi = 300; else dev->regs.RD_Dpi = 600; memset( dev->scanStates, 0, _SCANSTATE_BYTES ); dev->scanStates[1] = 0x77; u12io_PutOnAllRegisters( dev ); /* _DODELAY( 100 ); */ /* read one shading line and work on it */ if( u12io_ReadOneShadingLine(dev, (SANE_Byte*)dev->bufs.b1.pShadingRam, 512*2)) { if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { wDarks[0] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam); wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam + dev->regs.RD_Pixels ); wDarks[2] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam + dev->regs.RD_Pixels * 2UL); if( !wDarks[0] || !wDarks[1] || !wDarks[2] ) { dev->shade.fStop = SANE_FALSE; } else { dev->shade.DarkOffset.wColors[0] = wDarks[0]; dev->shade.DarkOffset.wColors[1] = wDarks[1]; dev->shade.DarkOffset.wColors[2] = wDarks[2]; (*dev->fnDACDark)( dev,dev->shade.pCcdDac, _CHANNEL_RED, wDarks[0] ); (*dev->fnDACDark)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN, wDarks[1] ); (*dev->fnDACDark)( dev, dev->shade.pCcdDac, _CHANNEL_BLUE, wDarks[2] ); } } else { wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam + dev->regs.RD_Pixels ); if(!wDarks[1] ) { dev->shade.fStop = SANE_FALSE; } else { dev->shade.DarkOffset.wColors[1] = wDarks[1]; (*dev->fnDACDark)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN, wDarks[1] ); } } } else { dev->shade.fStop = SANE_FALSE; } } /* CalculateDarkDependOnCCD() */ if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) { (*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_RED ); (*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN ); (*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_BLUE ); } else { (*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN ); } return SANE_STATUS_GOOD; } /** here we download the current mapping table */ static void u12shading_DownloadMapTable( U12_Device *dev, SANE_Byte *buf ) { SANE_Byte addr, regs[6]; int i; u12io_DataToRegister( dev, REG_SCANCONTROL, (SANE_Byte)((dev->regs.RD_ScanControl & 0xfc) | _SCAN_BYTEMODE)); /* prepare register settings... */ regs[0] = REG_MODECONTROL; regs[1] = _ModeMappingMem; regs[2] = REG_MEMORYLO; regs[3] = 0; regs[4] = REG_MEMORYHI; for( i = 3, addr = _MAP_ADDR_RED; i--; addr += _MAP_ADDR_SIZE ) { regs[5] = addr; u12io_DataToRegs( dev, regs, 3 ); u12io_MoveDataToScanner( dev, buf, 4096 ); buf += 4096; } u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl ); } /** */ static SANE_Status u12shading_DoCalibration( U12_Device *dev ) { SANE_Byte tb[4096*3]; u_long i, tmp; SANE_Byte bScanControl, rb[20]; SANE_Status res; int c; DBG( _DBG_INFO, "u12shading_DoCalibration()\n" ); /** before getting the shading data, (re)init the ASIC */ u12hw_InitAsic( dev, SANE_TRUE ); dev->shade.DarkOffset.Colors.Red = 0; dev->shade.DarkOffset.Colors.Green = 0; dev->shade.DarkOffset.Colors.Blue = 0; c = 0; _SET_REG( rb, c, REG_RESETMTSC, 0 ); _SET_REG( rb, c, REG_MODELCONTROL, dev->regs.RD_ModelControl); _SET_REG( rb, c, REG_MOTORDRVTYPE, dev->regs.RD_MotorDriverType ); _SET_REG( rb, c, REG_SCANCONTROL1, (_SCANSTOPONBUFFULL| _MFRC_BY_XSTEP)); u12io_DataToRegs( dev, rb, c ); res = u12motor_GotoShadingPosition( dev ); if( SANE_STATUS_GOOD != res ) return res; bScanControl = dev->regs.RD_ScanControl; /* SetShadingMapForGainDark */ memset( dev->bufs.b2.pSumBuf, 0xff, (5400 * 3 * 2)); u12shading_DownloadShadingTable( dev, dev->bufs.b2.pSumBuf, (5400*3*2)); for( i = 0, tmp = 0; i < 1024; tmp += 0x01010101, i += 4 ) { dev->bufs.b1.Buf.pdw[i] = dev->bufs.b1.Buf.pdw[i+1] = dev->bufs.b1.Buf.pdw[i+2] = dev->bufs.b1.Buf.pdw[i+3] = tmp; } memcpy( dev->bufs.b1.pShadingMap + 4096, dev->bufs.b1.pShadingMap, 4096 ); memcpy( dev->bufs.b1.pShadingMap + 8192, dev->bufs.b1.pShadingMap, 4096 ); u12shading_DownloadMapTable( dev, dev->bufs.b1.pShadingMap ); DBG( _DBG_INFO, "* wExposure = %u\n", dev->shade.wExposure); DBG( _DBG_INFO, "* wXStep = %u\n", dev->shade.wXStep); dev->regs.RD_LineControl = (_LOBYTE(dev->shade.wExposure)); dev->regs.RD_ExtLineControl = (_HIBYTE(dev->shade.wExposure)); u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL, dev->regs.RD_ExtLineControl ); u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl ); res = u12shading_AdjustRGBGain( dev ); if( SANE_STATUS_GOOD != res ) return res; res = u12shadingAdjustDark( dev ); if( SANE_STATUS_GOOD != res ) return res; res = u12shadingAdjustShadingWaveform( dev ); if( SANE_STATUS_GOOD != res ) return res; dev->regs.RD_ScanControl = bScanControl; /* here we have to prepare and download the table in any case...*/ if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) { u12map_Adjust( dev, _MAP_MASTER, tb ); } else { u12map_Adjust( dev, _MAP_RED, tb ); u12map_Adjust( dev, _MAP_GREEN, tb ); u12map_Adjust( dev, _MAP_BLUE, tb ); } u12shading_DownloadMapTable( dev, tb ); u12motor_BackToHomeSensor( dev ); DBG( _DBG_INFO, "u12shading_DoCalibration() - done.\n" ); return SANE_STATUS_GOOD; } /* END U12-SHADING ..........................................................*/