summaryrefslogtreecommitdiff
path: root/backend/u12-shading.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-10-06 14:00:40 +0200
commit6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch)
tree2e301d871bbeeb44aa57ff9cc070fcf3be484487 /backend/u12-shading.c
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'backend/u12-shading.c')
-rw-r--r--backend/u12-shading.c877
1 files changed, 877 insertions, 0 deletions
diff --git a/backend/u12-shading.c b/backend/u12-shading.c
new file mode 100644
index 0000000..e31c7ee
--- /dev/null
+++ b/backend/u12-shading.c
@@ -0,0 +1,877 @@
+/* @file u12-shading.c -
+ * @brief all the shading functions
+ *
+ * based on sources acquired from Plustek Inc.
+ * Copyright (C) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de>
+ *
+ * History:
+ * - 0.01 - initial version
+ * - 0.02 -
+ * .
+ * <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>
+ */
+
+#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 = &regs[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 ..........................................................*/