• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* @file plustek-pp_tpa.c
2  * @brief Here we find some adjustments according to the scan source.
3  *        This file is ASIC P9800x specific
4  *
5  * based on sources acquired from Plustek Inc.
6  * Copyright (C) 1998 Plustek Inc.
7  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
8  * also based on the work done by Rick Bronson
9  *
10  * History:
11  * - 0.30 - initial version
12  * - 0.31 - Added some comments
13  * - 0.32 - no changes
14  * - 0.33 - new header
15  * - 0.34 - no changes
16  * - 0.35 - no changes
17  * - 0.36 - no changes
18  * - 0.37 - cosmetic changes
19  * - 0.38 - Replaced AllPointer by DataPointer
20  *        - renamed this file from transform.c tpa.c
21  * - 0.39 - no changes
22  * - 0.40 - no changes
23  * - 0.41 - no changes
24  * - 0.42 - changed include names
25  * - 0.43 - no changes
26  * - 0.44 - fix format string issues, as Long types default to int32_t
27  *          now
28  * .
29  * <hr>
30  * This file is part of the SANE package.
31  *
32  * This program is free software; you can redistribute it and/or
33  * modify it under the terms of the GNU General Public License as
34  * published by the Free Software Foundation; either version 2 of the
35  * License, or (at your option) any later version.
36  *
37  * This program is distributed in the hope that it will be useful, but
38  * WITHOUT ANY WARRANTY; without even the implied warranty of
39  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
40  * General Public License for more details.
41  *
42  * You should have received a copy of the GNU General Public License
43  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
44  *
45  * As a special exception, the authors of SANE give permission for
46  * additional uses of the libraries contained in this release of SANE.
47  *
48  * The exception is that, if you link a SANE library with other files
49  * to produce an executable, this does not by itself cause the
50  * resulting executable to be covered by the GNU General Public
51  * License.  Your use of that executable is in no way restricted on
52  * account of linking the SANE library code into it.
53  *
54  * This exception does not, however, invalidate any other reasons why
55  * the executable file might be covered by the GNU General Public
56  * License.
57  *
58  * If you submit changes to SANE to the maintainers to be included in
59  * a subsequent release, you agree by submitting the changes that
60  * those changes may be distributed with this exception intact.
61  *
62  * If you write modifications of your own for SANE, it is your choice
63  * whether to permit this exception to apply to your modifications.
64  * If you do not wish that, delete this exception notice.
65  * <hr>
66  */
67 #include "plustek-pp_scan.h"
68 
69 /***************************** local vars ************************************/
70 
71 static UShort a_wGainString [] = {
72 	 50,  75, 100, 125, 150, 175, 200, 225,
73 	250, 275, 300, 325, 350, 375, 400, 425,
74 	450, 475, 500, 525, 550, 575, 600, 625,
75 	650, 675, 700, 725, 750, 775, 800, 825
76 };
77 
78 /*************************** local functions *********************************/
79 
80 /*.............................................................................
81  *
82  */
tpaP98SubNoise(pScanData ps,pULong pdwSum,pUShort pwShading,ULong dwHilightOff,ULong dwShadowOff)83 static void tpaP98SubNoise( pScanData ps, pULong pdwSum, pUShort pwShading,
84 					        ULong dwHilightOff, ULong dwShadowOff )
85 {
86 	ULong   dwPixels, dwLines, dwSum;
87     pUShort pw;
88 
89     for (dwPixels = 4; dwPixels--; pdwSum++, pwShading++)
90 		*pwShading = (UShort)(*pdwSum >> 5);
91 
92     for (dwPixels = 0; dwPixels < (ps->dwShadingPixels - 4); dwPixels++,
93 						 pdwSum++, pwShading++) {
94 
95 		pw = (pUShort)ps->Shade.pHilight + dwHilightOff + dwPixels;
96 		dwSum = 0;
97 
98 		for (dwLines = _DEF_BRIGHTEST_SKIP; dwLines--; pw += 5400UL)
99 		    dwSum += (ULong) *pw;
100 
101 		pw = ps->pwShadow + dwShadowOff + dwPixels;
102 
103 		for (dwLines = _DEF_DARKEST_SKIP; dwLines--; pw += 5400UL)
104 		    dwSum += (ULong) *pw;
105 
106 		*pwShading = (UShort)((*pdwSum - dwSum) / ps->Shade.dwDiv);
107     }
108     if (ps->dwShadingPixels != 5400UL) {
109 		for (dwPixels = 2700UL; dwPixels--; pdwSum++, pwShading++)
110 		    *pwShading = (UShort)(*pdwSum >> 5);
111 	}
112 }
113 
114 /*.............................................................................
115  *
116  */
tpaP98ShadingWaveformSum(pScanData ps)117 static void tpaP98ShadingWaveformSum( pScanData ps )
118 {
119 	DataPointer	pd, pt;
120     ULong		dw;
121 
122     pd.pdw = (pULong)ps->pScanBuffer1;
123     pt.pw  = (pUShort)ps->pScanBuffer1;
124 
125     if ((ps->DataInf.dwScanFlag & SCANDEF_TPA ) ||
126 		(0 == ps->bShadingTimeFlag)) {
127 
128 		if( ps->Shade.pHilight ) {
129 
130 		    tpaP98SubNoise( ps, (pULong)ps->pScanBuffer1,
131 						      (pUShort)ps->pScanBuffer1, 0, 0);
132 
133 		    tpaP98SubNoise( ps ,(pULong)ps->pScanBuffer1 + 5400UL,
134 						      (pUShort)ps->pScanBuffer1 + 5400UL,
135 						      ps->dwHilightCh, ps->dwShadowCh);
136 
137 		    tpaP98SubNoise( ps, (pULong)ps->pScanBuffer1 + 5400UL * 2UL,
138 						      (pUShort)ps->pScanBuffer1 + 5400UL * 2UL,
139 				      	      ps->dwHilightCh * 2, ps->dwShadowCh * 2);
140 		} else {
141 
142 		    for (dw = 5400 * 3; dw; dw--, pt.pw++, pd.pdw++)
143 				*pt.pw = (UShort)(*pd.pdw / 32);	/* shift 5 bits */
144 		}
145 
146     } else {
147 
148 		if (02 == ps->bShadingTimeFlag ) {
149 		    for (dw = 5400 * 3; dw; dw--, pt.pw++, pd.pdw++)
150 				*pt.pw = (UShort)(*pd.pdw / 16);	/* shift 4 bits */
151 		} else {
152 		    for (dw = 5400 * 3; dw; dw--, pt.pw++, pd.pdw++)
153 				*pt.pw = (UShort)(*pd.pdw / 4);	    /* shift 2 bits */
154 		}
155 	}
156 }
157 
158 /*.............................................................................
159  * get wReduceRedFactor, wReduceGreenFactor, wReduceBlueFactor
160  */
tpaP98GetNegativeTempRamData(pScanData ps)161 static void tpaP98GetNegativeTempRamData( pScanData ps )
162 {
163 	UShort		wRedTemp, wGreenTemp, wBlueTemp;
164 	UShort		wRedShadingTemp, wGreenShadingTemp, wBlueShadingTemp;
165     ULong		dw, dw1;
166 	DataPointer	p;
167 	pULong		pdwNegativeSumTemp;
168     pUShort		pNegativeTempRam, pNegativeTempRam2;
169 
170 	ps->bFastMoveFlag = _FastMove_Low_C75_G150;
171 
172 	MotorP98GoFullStep( ps ,80 );
173 
174     pNegativeTempRam   = (pUShort)(ps->pScanBuffer1 + 5400 * 6);
175     pdwNegativeSumTemp = (pULong)(pNegativeTempRam + 960 * 3 * 2);
176     pNegativeTempRam2  = (pUShort)(pdwNegativeSumTemp + 960 * 3 * 4);
177 
178 	/* ClearNegativeSumBuffer() */
179 	memset( pdwNegativeSumTemp, 0, (960 * 3 * 4));
180 
181     /* SetReadNegativeTempRegister() */
182 	ps->AsicReg.RD_Motor0Control = 0;
183 
184 	IOCmdRegisterToScanner( ps, ps->RegMotor0Control,
185 							ps->AsicReg.RD_Motor0Control );
186 
187 	ps->AsicReg.RD_ModeControl   = _ModeScan;
188 	ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorHEightStep + _MotorDirForward;
189 	ps->AsicReg.RD_ModelControl  = _ModelDpi600 + _LED_CONTROL + _LED_ACTIVITY;
190 	ps->AsicReg.RD_Dpi 			 = ps->PhysicalDpi;
191 
192     if (!ps->wNegAdjustX) {
193 		ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 + ps->Device.DataOriginX +
194 							             _Negative96OriginOffsetX * 2);
195 	} else {
196 		ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 + ps->Device.DataOriginX +
197 										 ps->wNegAdjustX);
198 	}
199 
200 	ps->AsicReg.RD_Pixels    = 960;
201 	ps->AsicReg.RD_XStepTime = 32;
202 
203 	IOPutOnAllRegisters( ps );
204 
205     /* NegativeMotorRunLoop() */
206     p.pb = ps->a_nbNewAdrPointer;
207     for (dw = _NUMBER_OF_SCANSTEPS / 8; dw; dw--, p.pdw++)
208 		*p.pdw = 0x87808780;
209 
210 	IOSetToMotorRegister( ps );
211 
212     for (dw1 = 16; dw1; dw1--) {
213 
214 		TimerDef timer;
215 
216 		MiscStartTimer( &timer, _SECOND );
217 
218 		while((IOReadFifoLength( ps ) < 960) && !MiscCheckTimer( &timer )) {
219 
220 	    	_DO_UDELAY(1);
221 		}
222 
223 	    /* ReadColorDataIn() - Read 1 RGB line */
224 		ps->AsicReg.RD_ModeControl = _ModeFifoRSel;
225 		IOReadScannerImageData( ps, (pUChar)pNegativeTempRam, 960 );
226 
227 		ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
228 		IOReadScannerImageData( ps, (pUChar)(pNegativeTempRam + 960), 960 );
229 
230 		ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
231 		IOReadScannerImageData( ps, (pUChar)(pNegativeTempRam + 960 * 2), 960 );
232 
233 		/* fillNegativeSum() */
234 		for (dw = 0; dw < 960 * 3; dw++)
235 		    pdwNegativeSumTemp[dw] += ((pUShort) pNegativeTempRam)[dw];
236 
237 		/* one line */
238 		if (IOReadFifoLength( ps ) <= (960 * 2))
239 		    IORegisterDirectToScanner( ps, ps->RegRefreshScanState );
240     }
241 
242     /* AverageAndShift() */
243     for( dw = 0, dw1 = 0; dw < 240 * 3; dw++, dw1+=4 ) {
244 
245 		pNegativeTempRam[dw] = (UShort)((pdwNegativeSumTemp[dw1] +
246 										 pdwNegativeSumTemp[dw1+1] +
247 										 pdwNegativeSumTemp[dw1+2] +
248 										 pdwNegativeSumTemp[dw1+3]) / 128);
249 				/* shift 6 bits */
250 	}
251 
252 	/* NegativeAdd1() */
253     if (!ps->wNegAdjustX) {
254 		dw1 = (ps->dwOffsetNegative + _Negative96OriginOffsetX * 2 * 2) / 2;
255     } else {
256 		dw1 = (ps->dwOffsetNegative + ps->wNegAdjustX * 2) / 2;
257 	}
258 
259 	/* do R shading average */
260     for (dw = 0; dw < 240; dw++, dw1 += 4) {
261 		pNegativeTempRam2[dw] = (UShort)(
262 								 (((pUShort)ps->pScanBuffer1)[dw1] +
263 								  ((pUShort)ps->pScanBuffer1)[dw1+1] +
264 								  ((pUShort)ps->pScanBuffer1)[dw1+2] +
265 					 			  ((pUShort)ps->pScanBuffer1)[dw1+3]) / 4);
266 	}
267 
268 	/* NegativeAdd1() */
269     if (!ps->wNegAdjustX)
270 		dw1 = (ps->dwOffsetNegative + 5400 * 2 + _Negative96OriginOffsetX * 2 * 2) / 2;
271     else
272 		dw1 = (ps->dwOffsetNegative + 5400 * 2 + ps->wNegAdjustX * 2) / 2;
273 
274 	/* do G shading average */
275     for (; dw < 240 * 2; dw++, dw1 += 4) {
276 		pNegativeTempRam2[dw] = (UShort)(
277 									(((pUShort)ps->pScanBuffer1)[dw1] +
278 									 ((pUShort)ps->pScanBuffer1)[dw1+1] +
279 									 ((pUShort)ps->pScanBuffer1)[dw1+2] +
280 									 ((pUShort)ps->pScanBuffer1)[dw1+3]) / 4);
281 	}
282 
283 	/* NegativeAdd1() */
284     if (!ps->wNegAdjustX)
285 		dw1 = (ps->dwOffsetNegative + 5400 * 4 + _Negative96OriginOffsetX * 2 * 2) / 2;
286     else
287 		dw1 = (ps->dwOffsetNegative + 5400 * 4 + ps->wNegAdjustX * 2) / 2;
288 
289 	/* do B shading average */
290     for (; dw < 240 * 3; dw++, dw1 += 4) {
291 		pNegativeTempRam2 [dw] = (UShort)(
292 									(((pUShort)ps->pScanBuffer1)[dw1] +
293 									 ((pUShort)ps->pScanBuffer1)[dw1+1] +
294 									 ((pUShort)ps->pScanBuffer1)[dw1+2] +
295 									 ((pUShort)ps->pScanBuffer1)[dw1+3]) / 4);
296 	}
297 
298     wRedTemp = wGreenTemp = wBlueTemp = 0;
299     wRedShadingTemp = wGreenShadingTemp = wBlueShadingTemp = 0;
300 
301     /* FindMaxNegValue -- find R */
302     for (dw = 0; dw < 240; dw++) {
303 		if (pNegativeTempRam[dw] >= wRedTemp &&
304 		    pNegativeTempRam[dw + 240] >= wGreenTemp  &&
305 	    	pNegativeTempRam[dw + 480] > wBlueTemp)	{
306 
307 		    wRedTemp   = pNegativeTempRam[dw];
308 		    wGreenTemp = pNegativeTempRam[dw + 240];
309 	    	wBlueTemp  = pNegativeTempRam[dw + 480];
310 
311 		    wRedShadingTemp   = pNegativeTempRam2[dw];
312 		    wGreenShadingTemp = pNegativeTempRam2[dw + 240];
313 	    	wBlueShadingTemp  = pNegativeTempRam2[dw + 480];
314 		}
315 	}
316 
317     /* GainAddX = (1/4)*DoubleX + 1/ 2 */
318     if ((ps->bRedGainIndex += (Byte)((wRedShadingTemp / wRedTemp) * 100 - 50) / 25) > 32)
319 		ps->bRedGainIndex = 31;
320 
321     if ((ps->bGreenGainIndex += (Byte)((wGreenShadingTemp / wGreenTemp) * 100 - 50) / 25) > 32)
322 		ps->bGreenGainIndex = 31;
323 
324     if ((ps->bBlueGainIndex += (Byte)((wBlueShadingTemp / wBlueTemp) * 100 - 50) / 25) > 32)
325 		ps->bBlueGainIndex = 31;
326 
327 }
328 
329 /*.............................................................................
330  *
331  */
tpaP98RecalculateNegativeShadingGain(pScanData ps)332 static void tpaP98RecalculateNegativeShadingGain( pScanData ps )
333 {
334     Byte		b[3];
335 	UShort		wSum, counter;
336 	UShort		w, w1, w2;
337 	ULong		dw, dw1;
338 	pUChar		pDest, pSrce, pNegativeTempRam;
339     pUChar		pbReg[3];
340 	TimerDef	timer;
341     DataPointer	p;
342 
343     pNegativeTempRam = (pUChar)(ps->pScanBuffer1 + 5400 * 6);
344 
345     /* AdjustDarkCondition () */
346     ps->Shade.pCcdDac->DarkDAC.Colors.Red   = ps->bsPreRedDAC;
347     ps->Shade.pCcdDac->DarkDAC.Colors.Green = ps->bsPreGreenDAC;
348     ps->Shade.pCcdDac->DarkDAC.Colors.Blue  = ps->bsPreBlueDAC;
349 
350     ps->Shade.pCcdDac->DarkCmpHi.Colors.Red   = ps->wsDACCompareHighRed;
351     ps->Shade.pCcdDac->DarkCmpLo.Colors.Red   = ps->wsDACCompareLowRed;
352     ps->Shade.pCcdDac->DarkCmpHi.Colors.Green = ps->wsDACCompareHighGreen;
353     ps->Shade.pCcdDac->DarkCmpLo.Colors.Green = ps->wsDACCompareLowGreen;
354     ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue  = ps->wsDACCompareHighBlue;
355     ps->Shade.pCcdDac->DarkCmpLo.Colors.Blue  = ps->wsDACCompareLowBlue;
356 
357     DacP98FillGainOutDirectPort( ps );
358 
359     /* ClearNegativeTempBuffer () */
360 	memset( pNegativeTempRam, 0, (960 * 3 * 4));
361 
362     /* GetNegGainValue () */
363 	ps->PauseColorMotorRunStates( ps );
364 
365     /* SetScanMode () set scan mode to Byte mode */
366 	ps->AsicReg.RD_ScanControl |= _SCAN_BYTEMODE;
367 	ps->AsicReg.RD_ScanControl &= 0xfd;
368 	IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
369     DacP98FillGainOutDirectPort( ps );
370 
371     /* SetReadNegativeTempRegister() */
372 	ps->AsicReg.RD_Motor0Control = 0;
373     IOCmdRegisterToScanner( ps, ps->RegMotor0Control,
374 							ps->AsicReg.RD_Motor0Control );
375 
376 	ps->AsicReg.RD_ModeControl   = _ModeScan;
377 	ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorHEightStep + _MotorDirForward;
378 	ps->AsicReg.RD_ModelControl  = _ModelDpi600 + _LED_CONTROL + _LED_ACTIVITY;
379 	ps->AsicReg.RD_Dpi 			 = ps->PhysicalDpi;
380 
381     if (!ps->wNegAdjustX) {
382 		ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 +
383                                          ps->Device.DataOriginX +
384 					 				     _Negative96OriginOffsetX * 2);
385 	} else {
386 		ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 + ps->Device.DataOriginX +
387 										 ps->wNegAdjustX);
388 	}
389 	ps->AsicReg.RD_Pixels = 960;
390 	ps->AsicReg.RD_XStepTime = 32;
391     IOPutOnAllRegisters( ps );
392 
393     /* ReReadNegativeTemp */
394 	MiscStartTimer( &timer, _SECOND );
395 
396     while((IOReadFifoLength( ps) < 960) && !MiscCheckTimer( &timer )) {
397 
398 		_DO_UDELAY(1);	/* 1 us delay */
399 	}
400 
401     /* ReadColorDataIn() - Read 1 RGB line */
402 	ps->AsicReg.RD_ModeControl = _ModeFifoRSel;
403 	IOReadScannerImageData( ps, pNegativeTempRam, 960);
404 
405 	ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
406     IOReadScannerImageData( ps, pNegativeTempRam + 960, 960);
407 
408 	ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
409 	IOReadScannerImageData( ps, pNegativeTempRam + 960 * 2, 960);
410 
411     /* FindRGBGainValue(); */
412     pDest = pSrce = pNegativeTempRam;
413 
414     /* ReAdjustGainAverage() */
415     for (dw1 = 0; dw1 < (960 * 3) / 16; dw1++, pDest++) {
416 		for (dw = 0, wSum = 0; dw < 16; dw++, pSrce++)
417 		    wSum += *pSrce;
418 
419 		*pDest = wSum / 16;
420     }
421 
422     /* FindTheMaxGainValue */
423     for (w = 0, p.pb = pNegativeTempRam; w < 3; w++) {
424 		for (dw = 960 / 16, b[w] = 0; dw; dw--, p.pb++) {
425 		    if (b[w] < *p.pb)
426 				b[w] = *p.pb;
427 		}
428     }
429 	ps->bRedHigh   = b[0];
430 	ps->bGreenHigh = b[1];
431     ps->bBlueHigh  = b[2];
432 
433     /* ModifyExposureTime () */
434     if ((ps->bRedHigh < _GAIN_LOW) ||
435 		(ps->bGreenHigh < _GAIN_LOW) || (ps->bBlueHigh <  _GAIN_LOW)) {
436 		ps->AsicReg.RD_LineControl = 192;
437 	}
438 
439 	IOCmdRegisterToScanner( ps, ps->RegLineControl,
440 							ps->AsicReg.RD_LineControl );
441     counter = 0;
442 
443     /* ReAdjustRGBGain () */
444     for (w1 = 0; w1 < 16; w1++) {
445 
446 		ps->PauseColorMotorRunStates( ps );
447 		DacP98FillGainOutDirectPort( ps );
448 
449 		/* SetReadNegativeTempRegister () */
450 		ps->AsicReg.RD_Motor0Control = 0;
451 		IOCmdRegisterToScanner( ps, ps->RegMotor0Control,
452 								ps->AsicReg.RD_Motor0Control );
453 
454 		ps->AsicReg.RD_ModeControl   = _ModeScan;
455 		ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorHEightStep + _MotorDirForward;
456 		ps->AsicReg.RD_ModelControl  = _ModelDpi600 + _LED_CONTROL + _LED_ACTIVITY;
457 		ps->AsicReg.RD_Dpi 			 = ps->PhysicalDpi;
458 
459 		if (!ps->wNegAdjustX) {
460 		    ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 +
461                                              ps->Device.DataOriginX +
462 										     _Negative96OriginOffsetX * 2);
463 		} else {
464 			ps->AsicReg.RD_Origin = (UShort)(ps->dwOffset70 +
465                                              ps->Device.DataOriginX +
466 											 ps->wNegAdjustX);
467 		}
468 
469 		ps->AsicReg.RD_Pixels    = 960;
470 		ps->AsicReg.RD_XStepTime = 32;
471 		IOPutOnAllRegisters( ps );
472 
473 		/* ReReadNegativeTemp () */
474 		MiscStartTimer( &timer, _SECOND );
475 		while((IOReadFifoLength( ps ) < 960) && !MiscCheckTimer( &timer)) {
476 
477 			_DO_UDELAY(1);
478 		}
479 
480 		/* ReadColorDataIn() - Read 1 RGB line */
481 		ps->AsicReg.RD_ModeControl = _ModeFifoRSel;
482 		IOReadScannerImageData( ps, pNegativeTempRam, 960 );
483 
484 		ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
485 		IOReadScannerImageData( ps, pNegativeTempRam + 960, 960);
486 
487 		ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
488 		IOReadScannerImageData( ps ,pNegativeTempRam + 960 * 2, 960);
489 
490 
491 		/* ReAdjustGainAverage() */
492 		pDest = pSrce = pNegativeTempRam;
493 		for( dw1 = 0; dw1 < (960 * 3) / 16; dw1++, pDest++ ) {
494 		    for( dw = 0, wSum = 0; dw < 16; dw++, pSrce++ )
495 				wSum += *pSrce;
496 		    *pDest = wSum / 16;
497 		}
498 
499 		/* FindTheMaxGainValue */
500 		pbReg[0] = &ps->bRedGainIndex;
501 		pbReg[1] = &ps->bGreenGainIndex;
502 		pbReg[2] = &ps->bBlueGainIndex;
503 		for (w = 0, p.pb = pNegativeTempRam; w < 3; w++) {
504 
505 		    for (dw = 960 / 16, b [w] = 0; dw; dw--, p.pb++) {
506 				if (b[w] < *p.pb)
507 				    b[w] = *p.pb;
508 		    }
509 		    if (b [w] < _GAIN_LOW) {
510 				if (( _GAIN_P98_HIGH - b [w]) < b [w])
511 				    *(pbReg [w]) += 1;
512 				else
513 			    	*(pbReg [w]) += 4;
514 	    	} else {
515 
516 				if (b [w] > _GAIN_P98_HIGH)
517 			    	*(pbReg [w]) -= 1;
518 		    }
519 		}
520 
521 		for (w2 = 0; w2 < 3; w2++) {
522 		    if (*(pbReg[w2]) > 31)
523 			(*(pbReg[w2])) = 31;
524 		}
525 		if ((b[0] == 0) || (b[1] == 0) || (b[2] == 0)) {
526 	    	counter++;
527 
528 		    if (counter < 16) {
529 				w1--;
530 				ps->bRedGainIndex   -= 4;
531 				ps->bGreenGainIndex -= 4;
532 				ps->bBlueGainIndex  -= 4;
533 		    }
534 		}
535     }
536 
537 	DacP98FillGainOutDirectPort( ps );
538 
539     ps->Shade.DarkOffset.Colors.Red   = 0;
540 	ps->Shade.DarkOffset.Colors.Green = 0;
541 	ps->Shade.DarkOffset.Colors.Blue  = 0;
542 
543     ps->OpenScanPath( ps );
544 	DacP98FillShadingDarkToShadingRegister( ps );
545     ps->CloseScanPath( ps );
546 
547 	DacP98AdjustDark( ps );
548 }
549 
550 /*.............................................................................
551  *
552  */
tpaP98RecalculateShadingGainandData(pScanData ps)553 static void tpaP98RecalculateShadingGainandData( pScanData ps )
554 {
555 	DataPointer	p;
556 	ULong		dw;
557     UShort      filmAdjustX;
558 	UShort		wOldRedGain, wOldGreenGain, wOldBlueGain;
559 	UShort		wNewRedGain, wNewGreenGain, wNewBlueGain;
560 
561     /* AdjustDarkCondition () */
562     ps->Shade.pCcdDac->DarkDAC.Colors.Red   = ps->bsPreRedDAC;
563     ps->Shade.pCcdDac->DarkDAC.Colors.Green = ps->bsPreGreenDAC;
564     ps->Shade.pCcdDac->DarkDAC.Colors.Blue  = ps->bsPreBlueDAC;
565 
566     ps->Shade.pCcdDac->DarkCmpHi.Colors.Red   = ps->wsDACCompareHighRed;
567     ps->Shade.pCcdDac->DarkCmpLo.Colors.Red   = ps->wsDACCompareLowRed;
568     ps->Shade.pCcdDac->DarkCmpHi.Colors.Green = ps->wsDACCompareHighGreen;
569     ps->Shade.pCcdDac->DarkCmpLo.Colors.Green = ps->wsDACCompareLowGreen;
570     ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue  = ps->wsDACCompareHighBlue;
571     ps->Shade.pCcdDac->DarkCmpLo.Colors.Blue  = ps->wsDACCompareLowBlue;
572 
573     wOldRedGain = a_wGainString[ps->bRedGainIndex] * 100/ps->wReduceRedFactor;
574 
575 	/* SearchNewGain() */
576     for (ps->bRedGainIndex = 0; ps->bRedGainIndex < 32; ps->bRedGainIndex++) {
577 		if (wOldRedGain < a_wGainString[ps->bRedGainIndex])
578 		    break;
579 	}
580 
581     if (0 == ps->bRedGainIndex)
582 		ps->bRedGainIndex ++;
583 
584     wNewRedGain = a_wGainString[--ps->bRedGainIndex];
585 
586     wOldGreenGain = a_wGainString[ps->bGreenGainIndex]*100/
587 														ps->wReduceGreenFactor;
588 
589 	/* SearchNewGain() */
590     for (ps->bGreenGainIndex = 0;
591 		 ps->bGreenGainIndex < 32; ps->bGreenGainIndex++) {
592 
593 		if (wOldGreenGain < a_wGainString[ps->bGreenGainIndex])
594 		    break;
595 	}
596 
597     if (0 == ps->bGreenGainIndex)
598 		ps->bGreenGainIndex ++;
599 
600     wNewGreenGain = a_wGainString[--ps->bGreenGainIndex];
601 
602     wOldBlueGain = a_wGainString[ps->bBlueGainIndex]*100/ps->wReduceBlueFactor;
603 
604 	/* SearchNewGain() */
605     for (ps->bBlueGainIndex = 0;ps->bBlueGainIndex < 32;ps->bBlueGainIndex++) {
606 		if (wOldBlueGain < a_wGainString[ps->bBlueGainIndex])
607 		    break;
608 	}
609     if (0 == ps->bBlueGainIndex)
610 		ps->bBlueGainIndex ++;
611 
612     wNewBlueGain = a_wGainString[--ps->bBlueGainIndex];
613 
614 	DacP98FillGainOutDirectPort( ps );
615 
616 	ps->Shade.DarkOffset.Colors.Red   = 0;
617     ps->Shade.DarkOffset.Colors.Green = 0;
618     ps->Shade.DarkOffset.Colors.Blue  = 0;
619 
620     ps->OpenScanPath( ps );
621 	DacP98FillShadingDarkToShadingRegister( ps );
622     ps->CloseScanPath( ps );
623 
624 	DacP98AdjustDark( ps );
625 
626     /* RecalculateTransparencyImage() */
627     if (ps->DataInf.dwScanFlag & SCANDEF_Transparency) {
628 		filmAdjustX = ps->wPosAdjustX;
629     } else {
630 		filmAdjustX = ps->wNegAdjustX;
631 	}
632 
633     if (!filmAdjustX) {
634 		p.pw = (pUShort)(ps->pScanBuffer1 + ps->dwOffsetNegative +
635 			  		       _Negative96OriginOffsetX * 2);
636 	} else {
637 		p.pw = (pUShort)(ps->pScanBuffer1 +
638 							  ps->dwOffsetNegative + filmAdjustX);
639 	}
640 
641 	/* RecalculateData() */
642     for (dw= 0; dw < _NegativePageWidth * 2 + 132; dw++, p.pw++)
643 		*p.pw = *p.pw * wNewRedGain / wOldRedGain;
644 
645     if (!ps->wNegAdjustX) {
646 		p.pw = (pUShort)(ps->pScanBuffer1 + 5400 * 2 +
647 							ps->dwOffsetNegative + _Negative96OriginOffsetX * 2);
648 	} else {
649 		p.pw = (pUShort)(ps->pScanBuffer1 + 5400 * 2 +
650 									ps->dwOffsetNegative + ps->wNegAdjustX);
651 	}
652 
653 	/* RecalculateData() */
654     for (dw= 0; dw < _NegativePageWidth * 2 + 132; dw++, p.pw++)
655 		*p.pw = *p.pw * wNewGreenGain / wOldGreenGain;
656 
657     if (!ps->wNegAdjustX) {
658 		p.pw = (pUShort)(ps->pScanBuffer1 + 5400 * 4 +
659 							ps->dwOffsetNegative + _Negative96OriginOffsetX * 2);
660     } else {
661 		p.pw = (pUShort)(ps->pScanBuffer1 + 5400 * 4 +
662 									ps->dwOffsetNegative + ps->wNegAdjustX);
663 	}
664 
665 	/* RecalculateData() - 64 + dwoffset70 */
666     for (dw= 0; dw < _NegativePageWidth * 2 + 132; dw++, p.pw++)
667 		*p.pw = *p.pw * wNewBlueGain / wOldBlueGain;
668 }
669 
670 /************************ exported functions *********************************/
671 
672 /*.............................................................................
673  * perform some adjustments according to the source (normal, transparency etc)
674  */
TPAP98001AverageShadingData(pScanData ps)675 _LOC void TPAP98001AverageShadingData( pScanData ps )
676 {
677 	DBG( DBG_LOW, "TPAP98001AverageShadingData()\n" );
678 
679 	ps->wNegAdjustX 	 = 0;
680 	ps->wPosAdjustX 	 = 0;
681 	ps->dwOffsetNegative = 0;
682 
683 	tpaP98ShadingWaveformSum( ps );
684 
685 	/*
686 	 * CHANGE: to support Grayscale images in transparency and negative mode
687 	 * original code: if ((ps->DataInf.wPhyDataType >= COLOR_TRUE24) &&
688 	 */
689 	if((ps->DataInf.wPhyDataType >= COLOR_256GRAY) &&
690        (ps->DataInf.dwScanFlag & SCANDEF_TPA)) {
691 
692 		if (((ps->DataInf.dwScanFlag & SCANDEF_Negative) && !ps->wNegAdjustX) ||
693 		    ((ps->DataInf.dwScanFlag & SCANDEF_Transparency) && !ps->wPosAdjustX)) {
694 
695 		    Long	dwLeft, dwRight;
696 		    pUShort	pw = (pUShort)ps->pScanBuffer1;
697 
698 		    for (dwLeft = 0; dwLeft < 5400; dwLeft++)
699 				if (pw[dwLeft] >= 600)
700 		    		break;
701 
702 		    for (dwRight = 4600; dwRight; dwRight--)
703 				if (pw[dwRight] >= 600)
704 		    		break;
705 
706 			DBG( DBG_LOW, "_TPAPageWidth = %u, _NegativePageWidth = %u\n"
707 						  "right = %d, left = %d --> right = %d\n",
708 						  _TPAPageWidth, _NegativePageWidth,
709 						  dwRight, dwLeft, (((Long)dwRight-(Long)dwLeft)/2));
710 
711 		    dwRight = (dwRight - dwLeft) / 2;
712 
713 		    if (ps->DataInf.dwScanFlag & SCANDEF_Negative) {
714 
715 				if (dwRight >= (Long)_NegativePageWidth) {
716 
717 				    ps->wNegAdjustX = (UShort)(dwRight - _NegativePageWidth +
718 										 	   dwLeft - ps->dwOffset70 -
719                                                ps->Device.DataOriginX + 4U);
720 					if( ps->wNegAdjustX > (_Negative96OriginOffsetX * 2U))
721 						ps->wNegAdjustX = (_Negative96OriginOffsetX * 2U);
722 
723 				    ps->DataInf.crImage.x += ps->wNegAdjustX;
724 				} else {
725 				    ps->DataInf.crImage.x += (_Negative96OriginOffsetX * 2U);
726 				}
727 		    }  else {
728 				if (dwRight >= (Long)_TPAPageWidth) {
729 
730 				    ps->wPosAdjustX = (UShort)(dwRight - _TPAPageWidth +
731 									 		   dwLeft - ps->dwOffset70 -
732 											   ps->Device.DataOriginX + 4U);
733 
734 					if( ps->wPosAdjustX > (_Transparency96OriginOffsetX * 2U))
735 						ps->wPosAdjustX = (_Transparency96OriginOffsetX * 2U);
736 
737 		    		ps->DataInf.crImage.x += ps->wPosAdjustX;
738 
739 				} else {
740 				    ps->DataInf.crImage.x += (_Transparency96OriginOffsetX * 2U);
741 				}
742 	    	}
743 		}
744 #if 0
745 		else {
746 			/* CHANGE: as we always reset the values, we can ignore this code..*/
747 
748 		    if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
749 				ps->DataInf.crImage.x += ps->wNegAdjustX;
750 		    else
751 				ps->DataInf.crImage.x += ps->wPosAdjustX;
752 		}
753 #endif
754 
755 		if( ps->DataInf.dwScanFlag & SCANDEF_Negative ) {
756 
757 	    	ps->dwOffsetNegative = (ps->dwOffset70 + 64+4) * 2;
758 
759 			tpaP98GetNegativeTempRamData( ps );
760 		    tpaP98RecalculateNegativeShadingGain( ps );
761 
762 		} else {
763 		    ps->wReduceRedFactor   = 0x3e;
764 		    ps->wReduceGreenFactor = 0x39;
765 	    	ps->wReduceBlueFactor  = 0x42;
766 
767 		    if( ps->Device.bCCDID == _CCD_518 ) {
768 				ps->wReduceRedFactor   = 55;
769 				ps->wReduceGreenFactor = 55;
770 				ps->wReduceBlueFactor  = 55;
771 		    }
772 		    if( ps->Device.bCCDID == _CCD_3797 ) {
773 				ps->wReduceRedFactor   = 42;
774 				ps->wReduceGreenFactor = 50;
775 				ps->wReduceBlueFactor  = 50;
776 		    }
777 
778 			tpaP98RecalculateShadingGainandData( ps );
779 		}
780     }
781 }
782 
783 /*.............................................................................
784  * perform some adjustments according to the source (normal, transparency etc)
785  */
TPAP98003FindCenterPointer(pScanData ps)786 _LOC void TPAP98003FindCenterPointer( pScanData ps )
787 {
788     ULong         i;
789     ULong         width;
790     ULong         left;
791     ULong         right;
792     pRGBUShortDef pwSum = ps->Bufs.b2.pSumRGB;
793 
794     if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
795         width = _NEG_PAGEWIDTH600;
796     else
797 	    width = _NEG_PAGEWIDTH600 - 94;
798 
799     /* 2.54 cm tolerance */
800     left  = ps->Device.DataOriginX + _NEG_ORG_OFFSETX * 2 - 600;
801     right = ps->Device.DataOriginX + _NEG_ORG_OFFSETX * 2 +
802                                           _NEG_PAGEWIDTH600 + 600;
803 
804     for( i = 5400UL - left, pwSum = ps->Bufs.b2.pSumRGB; i--; left++)
805     	if( pwSum[left].Red   > _NEG_EDGE_VALUE &&
806 	        pwSum[left].Green > _NEG_EDGE_VALUE &&
807 	        pwSum[left].Blue  > _NEG_EDGE_VALUE)
808     	    break;
809 
810     for( i = 5400UL - left, pwSum = ps->Bufs.b2.pSumRGB; i--; right--)
811     	if( pwSum[right].Red   > _NEG_EDGE_VALUE &&
812 	        pwSum[right].Green > _NEG_EDGE_VALUE &&
813 	        pwSum[right].Blue  > _NEG_EDGE_VALUE)
814 	        break;
815 
816     if((right <= left) || ((right - left) < width)) {
817         if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
818 	        ps->Scan.negBegin = ps->Device.DataOriginX + _NEG_ORG_OFFSETX * 2;
819     	else
820 	        ps->Scan.posBegin = ps->Device.DataOriginX + _POS_ORG_OFFSETX * 2;
821     } else {
822         if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
823 	        ps->Scan.negBegin = (right + left) / 2UL - _NEG_PAGEWIDTH;
824     	else
825             ps->Scan.posBegin = (right + left) / 2UL - _POS_PAGEWIDTH;
826     }
827 }
828 
829 /*.............................................................................
830  * this function does some reshading, when scanning negatives on an ASIC 98003
831  * based scanner
832  */
TPAP98003Reshading(pScanData ps)833 _LOC void TPAP98003Reshading( pScanData ps )
834 {
835     Byte        bHi[3], bHiLeft[3], bHiRight[3];
836     ULong       i, dwR, dwG, dwB, dwSum;
837     ULong       dwIndex, dwIndexRight, dwIndexLeft;
838     DataPointer RedPtr, GreenPtr, BluePtr;
839     TimerDef    timer;
840 
841 	bHi[0] = bHi[1] = bHi[2] = 0;
842 
843 /* CHECK: Why this ??? */
844 #if 1
845     ps->Scan.negScan[1].exposureTime = 144;
846     ps->Scan.negScan[1].xStepTime    = 18;
847     ps->Scan.negScan[2].exposureTime = 144;
848     ps->Scan.negScan[2].xStepTime    = 36;
849     ps->Scan.negScan[3].exposureTime = 144;
850     ps->Scan.negScan[3].xStepTime    = 72;
851     ps->Scan.negScan[4].exposureTime = 144;
852     ps->Scan.negScan[4].xStepTime    = 144;
853 #endif
854 
855     ps->Shade.wExposure = ps->Scan.negScan[ps->Scan.dpiIdx].exposureTime;
856     ps->Shade.wXStep    = ps->Scan.negScan[ps->Scan.dpiIdx].xStepTime;
857 
858     MiscStartTimer( &timer, _SECOND );
859 
860     while(!(IOGetScanState(ps, _TRUE) & _SCANSTATE_STOP) &&
861                                               (_OK == MiscCheckTimer(&timer)));
862 
863     IODataToRegister( ps, ps->RegXStepTime,
864                                     (Byte)(ps->AsicReg.RD_LineControl >> 4));
865      _DODELAY( 12 );
866     MotorP98003PositionYProc( ps, _NEG_SHADING_OFFS );
867 
868     IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime );
869 
870     ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
871     IOSelectLampSource( ps );
872 
873     IODataToRegister( ps, ps->RegLineControl, _LOBYTE(ps->Shade.wExposure));
874     IODataToRegister( ps, ps->RegXStepTime,   _LOBYTE(ps->Shade.wXStep));
875 
876     ps->AsicReg.RD_LineControl    = _LOBYTE(ps->Shade.wExposure);
877     ps->AsicReg.RD_ExtLineControl = _HIBYTE(ps->Shade.wExposure);
878     ps->AsicReg.RD_XStepTime      = (Byte)(ps->Shade.wExposure);
879     ps->AsicReg.RD_ModeControl    = _ModeScan;
880     ps->AsicReg.RD_Motor0Control  = _FORWARD_MOTOR;
881 
882     ps->AsicReg.RD_Origin = (UShort)ps->Scan.negBegin;
883     ps->AsicReg.RD_Pixels = _NEG_PAGEWIDTH600;
884 
885     memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
886 
887     /* put 9 scan states to make sure there are 8 lines available at least */
888     for( i = 0; i <= 12; i++)
889     	ps->a_nbNewAdrPointer[i] = 0x8f;
890 
891     IOPutOnAllRegisters( ps );
892     _DODELAY( 70 );
893 
894 	/* prepare the buffers... */
895     memset( ps->Bufs.TpaBuf.pb, 0, _SizeTpaDataBuf );
896 
897     RedPtr.pb   = ps->Bufs.b1.pShadingMap;
898     GreenPtr.pb = RedPtr.pb   + _NEG_PAGEWIDTH600;
899     BluePtr.pb  = GreenPtr.pb + _NEG_PAGEWIDTH600;
900 
901     for( dwSum = 8; dwSum--; ) {
902 
903         IOReadOneShadingLine( ps, ps->Bufs.b1.pShadingMap, _NEG_PAGEWIDTH600 );
904 
905 	    for( i = 0; i < _NEG_PAGEWIDTH600; i++) {
906 
907 	        ps->Bufs.TpaBuf.pusrgb[i].Red   += RedPtr.pb[i];
908     	    ps->Bufs.TpaBuf.pusrgb[i].Green += GreenPtr.pb[i];
909 	        ps->Bufs.TpaBuf.pusrgb[i].Blue  += BluePtr.pb[i];
910     	}
911     }
912 
913     for( i = 0; i < (_NEG_PAGEWIDTH600 * 3UL); i++ )
914     	ps->Bufs.TpaBuf.pb[i] = ps->Bufs.TpaBuf.pw[i] >> 3;
915 
916     RedPtr.pb = ps->Bufs.TpaBuf.pb;
917 
918 	/* Convert RGB to gray scale (Brightness), and average 16 pixels */
919     for( bHiRight[1] = 0, i = dwIndexRight = 0;
920                                          i < _NEG_PAGEWIDTH600 / 2; i += 16 ) {
921     	bHiRight [0] =
922 	       (Byte)(((((ULong) RedPtr.pbrgb [i].Red +
923 		     (ULong) RedPtr.pbrgb[i + 1].Red +
924 		     (ULong) RedPtr.pbrgb[i + 2].Red +
925 		     (ULong) RedPtr.pbrgb[i + 3].Red +
926 		     (ULong) RedPtr.pbrgb[i + 4].Red +
927 		     (ULong) RedPtr.pbrgb[i + 5].Red +
928 		     (ULong) RedPtr.pbrgb[i + 6].Red +
929 		     (ULong) RedPtr.pbrgb[i + 7].Red +
930 		     (ULong) RedPtr.pbrgb[i + 8].Red +
931 		     (ULong) RedPtr.pbrgb[i + 9].Red +
932 		     (ULong) RedPtr.pbrgb[i + 10].Red +
933 		     (ULong) RedPtr.pbrgb[i + 11].Red +
934 		     (ULong) RedPtr.pbrgb[i + 12].Red +
935 		     (ULong) RedPtr.pbrgb[i + 13].Red +
936 		     (ULong) RedPtr.pbrgb[i + 14].Red +
937 		     (ULong) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL +
938 		   (((ULong) RedPtr.pbrgb[i].Green +
939 		     (ULong) RedPtr.pbrgb[i + 1].Green +
940 		     (ULong) RedPtr.pbrgb[i + 2].Green +
941 		     (ULong) RedPtr.pbrgb[i + 3].Green +
942 		     (ULong) RedPtr.pbrgb[i + 4].Green +
943 		     (ULong) RedPtr.pbrgb[i + 5].Green +
944 		     (ULong) RedPtr.pbrgb[i + 6].Green +
945 		     (ULong) RedPtr.pbrgb[i + 7].Green +
946 		     (ULong) RedPtr.pbrgb[i + 8].Green +
947 		     (ULong) RedPtr.pbrgb[i + 9].Green +
948 		     (ULong) RedPtr.pbrgb[i + 10].Green +
949 		     (ULong) RedPtr.pbrgb[i + 11].Green +
950 		     (ULong) RedPtr.pbrgb[i + 12].Green +
951 		     (ULong) RedPtr.pbrgb[i + 13].Green +
952 		     (ULong) RedPtr.pbrgb[i + 14].Green +
953 		     (ULong) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL +
954 		   (((ULong) RedPtr.pbrgb[i].Blue +
955 		     (ULong) RedPtr.pbrgb[i + 1].Blue +
956 		     (ULong) RedPtr.pbrgb[i + 2].Blue +
957 		     (ULong) RedPtr.pbrgb[i + 3].Blue +
958 		     (ULong) RedPtr.pbrgb[i + 4].Blue +
959 		     (ULong) RedPtr.pbrgb[i + 5].Blue +
960 		     (ULong) RedPtr.pbrgb[i + 6].Blue +
961 		     (ULong) RedPtr.pbrgb[i + 7].Blue +
962 		     (ULong) RedPtr.pbrgb[i + 8].Blue +
963 		     (ULong) RedPtr.pbrgb[i + 9].Blue +
964 		     (ULong) RedPtr.pbrgb[i + 10].Blue +
965 		     (ULong) RedPtr.pbrgb[i + 11].Blue +
966 		     (ULong) RedPtr.pbrgb[i + 12].Blue +
967 		     (ULong) RedPtr.pbrgb[i + 13].Blue +
968 		     (ULong) RedPtr.pbrgb[i + 14].Blue +
969 		     (ULong) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL);
970 
971     	if( bHiRight[1] < bHiRight[0] ) {
972     	    bHiRight[1] = bHiRight[0];
973 	        dwIndexRight = i;
974     	}
975     }
976 
977 	/* Convert RGB to gray scale (Brightness), and average 16 pixels */
978     for( bHiLeft[1] = 0, i = dwIndexLeft = _NEG_PAGEWIDTH / 2;
979                                         	 i < _NEG_PAGEWIDTH600; i += 16 ) {
980     	bHiLeft [0] =
981 	       (Byte)(((((ULong) RedPtr.pbrgb[i].Red +
982 		     (ULong) RedPtr.pbrgb[i + 1].Red +
983 		     (ULong) RedPtr.pbrgb[i + 2].Red +
984 		     (ULong) RedPtr.pbrgb[i + 3].Red +
985 		     (ULong) RedPtr.pbrgb[i + 4].Red +
986 		     (ULong) RedPtr.pbrgb[i + 5].Red +
987 		     (ULong) RedPtr.pbrgb[i + 6].Red +
988 		     (ULong) RedPtr.pbrgb[i + 7].Red +
989 		     (ULong) RedPtr.pbrgb[i + 8].Red +
990 		     (ULong) RedPtr.pbrgb[i + 9].Red +
991 		     (ULong) RedPtr.pbrgb[i + 10].Red +
992 		     (ULong) RedPtr.pbrgb[i + 11].Red +
993 		     (ULong) RedPtr.pbrgb[i + 12].Red +
994 		     (ULong) RedPtr.pbrgb[i + 13].Red +
995 		     (ULong) RedPtr.pbrgb[i + 14].Red +
996 		     (ULong) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL +
997 		   (((ULong) RedPtr.pbrgb[i].Green +
998 		     (ULong) RedPtr.pbrgb[i + 1].Green +
999 		     (ULong) RedPtr.pbrgb[i + 2].Green +
1000 		     (ULong) RedPtr.pbrgb[i + 3].Green +
1001 		     (ULong) RedPtr.pbrgb[i + 4].Green +
1002 		     (ULong) RedPtr.pbrgb[i + 5].Green +
1003 		     (ULong) RedPtr.pbrgb[i + 6].Green +
1004 		     (ULong) RedPtr.pbrgb[i + 7].Green +
1005 		     (ULong) RedPtr.pbrgb[i + 8].Green +
1006 		     (ULong) RedPtr.pbrgb[i + 9].Green +
1007 		     (ULong) RedPtr.pbrgb[i + 10].Green +
1008 		     (ULong) RedPtr.pbrgb[i + 11].Green +
1009 		     (ULong) RedPtr.pbrgb[i + 12].Green +
1010 		     (ULong) RedPtr.pbrgb[i + 13].Green +
1011 		     (ULong) RedPtr.pbrgb[i + 14].Green +
1012 		     (ULong) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL +
1013 		   (((ULong) RedPtr.pbrgb[i].Blue +
1014 		     (ULong) RedPtr.pbrgb[i + 1].Blue +
1015 		     (ULong) RedPtr.pbrgb[i + 2].Blue +
1016 		     (ULong) RedPtr.pbrgb[i + 3].Blue +
1017 		     (ULong) RedPtr.pbrgb[i + 4].Blue +
1018 		     (ULong) RedPtr.pbrgb[i + 5].Blue +
1019 		     (ULong) RedPtr.pbrgb[i + 6].Blue +
1020 		     (ULong) RedPtr.pbrgb[i + 7].Blue +
1021 		     (ULong) RedPtr.pbrgb[i + 8].Blue +
1022 		     (ULong) RedPtr.pbrgb[i + 9].Blue +
1023 		     (ULong) RedPtr.pbrgb[i + 10].Blue +
1024 		     (ULong) RedPtr.pbrgb[i + 11].Blue +
1025 		     (ULong) RedPtr.pbrgb[i + 12].Blue +
1026 		     (ULong) RedPtr.pbrgb[i + 13].Blue +
1027 		     (ULong) RedPtr.pbrgb[i + 14].Blue +
1028 		     (ULong) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL);
1029 
1030         if( bHiLeft[1] < bHiLeft[0] ) {
1031             bHiLeft[1] = bHiLeft[0];
1032 	        dwIndexLeft = i;
1033     	}
1034     }
1035 
1036     if((bHiLeft[1] < 200) && (bHiRight[1] < 200)) {
1037 
1038     	if( bHiLeft[1] < bHiRight[1] )
1039     	    dwIndex = dwIndexRight;
1040 	    else
1041 	        dwIndex = dwIndexLeft;
1042     } else {
1043     	if( bHiLeft[1] > 200 )
1044     	    dwIndex = dwIndexRight;
1045 	    else
1046 	        dwIndex = dwIndexLeft;
1047     }
1048 
1049     /* Get the hilight */
1050     RedPtr.pusrgb = ps->Bufs.b2.pSumRGB + dwIndex +
1051                     ps->AsicReg.RD_Origin + _SHADING_BEGINX;
1052 
1053     for( dwR = dwG = dwB = 0, i = 16; i--; RedPtr.pusrgb++ ) {
1054     	dwR += RedPtr.pusrgb->Red;
1055 	    dwG += RedPtr.pusrgb->Green;
1056     	dwB += RedPtr.pusrgb->Blue;
1057     }
1058 
1059     dwR >>= 8;
1060     dwG >>= 8;
1061     dwB >>= 8;
1062 
1063     if( dwR > dwG && dwR > dwB )
1064     	ps->Shade.bGainHigh = (Byte)dwR;     /* >> 4 for average, >> 4 to 8-bit */
1065     else {
1066     	if( dwG > dwR && dwG > dwB )
1067 	        ps->Shade.bGainHigh = (Byte)dwG;
1068     	else
1069 	        ps->Shade.bGainHigh = (Byte)dwB;
1070     }
1071 
1072     ps->Shade.bGainHigh = (Byte)(ps->Shade.bGainHigh - 0x18);
1073     ps->Shade.bGainLow  = (Byte)(ps->Shade.bGainHigh - 0x10);
1074 
1075     /* Reshading to get the new gain */
1076     ps->Shade.Hilight.Colors.Red   = 0;
1077     ps->Shade.Hilight.Colors.Green = 0;
1078     ps->Shade.Hilight.Colors.Blue  = 0;
1079     ps->Shade.Gain.Colors.Red++;
1080     ps->Shade.Gain.Colors.Green++;
1081     ps->Shade.Gain.Colors.Blue++;
1082     ps->Shade.fStop = _FALSE;
1083 
1084     RedPtr.pb   = ps->Bufs.b1.pShadingMap + dwIndex;
1085     GreenPtr.pb = RedPtr.pb   + _NEG_PAGEWIDTH600;
1086     BluePtr.pb  = GreenPtr.pb + _NEG_PAGEWIDTH600;
1087 
1088     for( i = 16; i-- && !ps->Shade.fStop;) {
1089 
1090     	ps->Shade.fStop = _TRUE;
1091 
1092         DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );
1093 
1094     	IODataToRegister( ps, ps->RegModeControl, _ModeIdle );
1095 
1096         ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
1097         IOSelectLampSource( ps );
1098 
1099     	ps->AsicReg.RD_ModeControl   = _ModeScan;
1100 	    ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
1101     	ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;
1102 
1103         memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
1104         ps->a_nbNewAdrPointer[1] = 0x77;
1105 
1106     	IOPutOnAllRegisters( ps );
1107 	    _DODELAY( 50 );
1108 
1109     	if(IOReadOneShadingLine(ps,ps->Bufs.b1.pShadingMap,_NEG_PAGEWIDTH600)) {
1110 
1111 	        bHi[0] = DacP98003SumGains( RedPtr.pb,   32 );
1112     	    bHi[1] = DacP98003SumGains( GreenPtr.pb, 32 );
1113 	        bHi[2] = DacP98003SumGains( BluePtr.pb,  32 );
1114 
1115 	        if( !bHi[0] || !bHi[1] || !bHi[2]) {
1116     	    	ps->Shade.fStop = _FALSE;
1117     	    } else {
1118 
1119         		DacP98003AdjustGain( ps, _CHANNEL_RED,   bHi[0] );
1120 	        	DacP98003AdjustGain( ps, _CHANNEL_GREEN, bHi[1] );
1121 		        DacP98003AdjustGain( ps, _CHANNEL_BLUE,  bHi[2] );
1122     	    }
1123 	    } else
1124 	        ps->Shade.fStop = _FALSE;
1125     }
1126 
1127     DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );
1128 
1129     /* Set RGB Gain */
1130     if( dwR && dwG && dwB ) {
1131 
1132     	if(ps->Device.bCCDID == _CCD_3797 || ps->Device.bDACType == _DA_ESIC) {
1133     	    ps->Shade.pCcdDac->GainResize.Colors.Red =
1134                                          (UShort)((ULong)bHi[0] * 100UL / dwR);
1135 	        ps->Shade.pCcdDac->GainResize.Colors.Green =
1136                                          (UShort)((ULong)bHi[1] * 100UL / dwG);
1137 	        ps->Shade.pCcdDac->GainResize.Colors.Blue =
1138                                          (UShort)((ULong)bHi[2] * 100UL / dwB);
1139     	} else {
1140     	    ps->Shade.pCcdDac->GainResize.Colors.Red =
1141                                          (UShort)((ULong)bHi[0] * 90UL / dwR);
1142 	        ps->Shade.pCcdDac->GainResize.Colors.Green =
1143                                          (UShort)((ULong)bHi[1] * 77UL / dwG);
1144 	        ps->Shade.pCcdDac->GainResize.Colors.Blue =
1145                                          (UShort)((ULong)bHi[2] * 73UL / dwB);
1146 		}
1147     	ps->Shade.DarkOffset.Colors.Red +=
1148                                    (UShort)((dwR > bHi[0]) ? dwR - bHi[0] : 0);
1149     	ps->Shade.DarkOffset.Colors.Green +=
1150                                    (UShort)((dwG > bHi[1]) ? dwG - bHi[1] : 0);
1151 	    ps->Shade.DarkOffset.Colors.Blue +=
1152                                    (UShort)((dwB > bHi[2]) ? dwB - bHi[2] : 0);
1153 
1154 	    if( ps->Device.bDACType != _DA_ESIC && ps->Device.bCCDID != _CCD_3799 ) {
1155             ps->Shade.DarkOffset.Colors.Red =
1156                 		(UShort)(ps->Shade.DarkOffset.Colors.Red *
1157                     		 ps->Shade.pCcdDac->GainResize.Colors.Red / 100UL);
1158     	    ps->Shade.DarkOffset.Colors.Green =
1159                 		(UShort)(ps->Shade.DarkOffset.Colors.Green *
1160                       	   ps->Shade.pCcdDac->GainResize.Colors.Green / 100UL);
1161 	        ps->Shade.DarkOffset.Colors.Blue =
1162                 		(UShort)(ps->Shade.DarkOffset.Colors.Blue *
1163                  	        ps->Shade.pCcdDac->GainResize.Colors.Blue / 100UL);
1164     	}
1165     }
1166 
1167     /* AdjustDark () */
1168     ps->AsicReg.RD_Origin = _SHADING_BEGINX;
1169     ps->AsicReg.RD_Pixels = 5400;
1170 }
1171 
1172 /* END PLUSTEK-PP_TPA.C .....................................................*/
1173