1/* @file plustek-pp_dac.c
2 * @brief all the shading function formerly found in shading.c.
3 *        don't ask me why I called this file dac.c...
4 *
5 * based on sources acquired from Plustek Inc.
6 * Copyright (C) 1998 Plustek Inc.
7 * Copyright (C) 2000-2004 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 - no changes
13 * - 0.32 - no changes
14 * - 0.33 - added some comments
15 * - 0.34 - slight changes
16 * - 0.35 - removed SetInitialGainRAM from structure pScanData
17 * - 0.36 - added dacP96001WaitForShading and changed dacP96WaitForShading to
18 *          dacP96003WaitForShading
19 *        - changes, due to define renaming
20 * - 0.37 - removed dacP98FillShadingDarkToShadingRegister()
21 *        - removed // comments
22 *        - some code cleanup
23 * - 0.38 - added P12 stuff
24 * - 0.39 - no changes
25 * - 0.40 - disabled the A3I stuff
26 * - 0.41 - no changes
27 * - 0.42 - changed include names
28 * - 0.43 - no changes
29 * .
30 * <hr>
31 * This file is part of the SANE package.
32 *
33 * This program is free software; you can redistribute it and/or
34 * modify it under the terms of the GNU General Public License as
35 * published by the Free Software Foundation; either version 2 of the
36 * License, or (at your option) any later version.
37 *
38 * This program is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 * General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
45 *
46 * As a special exception, the authors of SANE give permission for
47 * additional uses of the libraries contained in this release of SANE.
48 *
49 * The exception is that, if you link a SANE library with other files
50 * to produce an executable, this does not by itself cause the
51 * resulting executable to be covered by the GNU General Public
52 * License.  Your use of that executable is in no way restricted on
53 * account of linking the SANE library code into it.
54 *
55 * This exception does not, however, invalidate any other reasons why
56 * the executable file might be covered by the GNU General Public
57 * License.
58 *
59 * If you submit changes to SANE to the maintainers to be included in
60 * a subsequent release, you agree by submitting the changes that
61 * those changes may be distributed with this exception intact.
62 *
63 * If you write modifications of your own for SANE, it is your choice
64 * whether to permit this exception to apply to your modifications.
65 * If you do not wish that, delete this exception notice.
66 * <hr>
67 */
68#include "plustek-pp_scan.h"
69
70/************************** local definitions ********************************/
71
72/***************************** global vars ***********************************/
73
74static const Byte a_bCorrectTimesTable[4] = {0, 1, 2, 4};
75
76static ULong dwADCPipeLine = 4 * 4;
77static ULong dwReadyLen;
78
79/*************************** local functions *********************************/
80
81/**
82 */
83static void dacP98AdjustGainAverage( pScanData ps )
84{
85	pUChar pDest, pSrce;
86    ULong  dw, dw1;
87    UShort wSum;
88
89    pDest = pSrce = ps->pScanBuffer1;
90
91    for (dw1 = 0; dw1 < (2560 * 3) / 16; dw1++, pDest++) {
92		for (dw = 0, wSum = 0; dw < 16; dw++, pSrce++)
93		    wSum += *pSrce;
94
95		*pDest = wSum / 16;
96    }
97}
98
99/**
100 */
101static void dacP98FillDarkDAC( pScanData ps )
102{
103    IODataRegisterToDAC( ps, 0x20, ps->bRedDAC   );
104    IODataRegisterToDAC( ps, 0x21, ps->bGreenDAC );
105    IODataRegisterToDAC( ps, 0x22, ps->bBlueDAC  );
106}
107
108/**
109 */
110static void dacP98SetReadFBKRegister( pScanData ps )
111{
112    IODataToRegister( ps, ps->RegModeControl, _ModeIdle );
113
114    ps->AsicReg.RD_ScanControl = _SCAN_12BITMODE + _SCAN_1ST_AVERAGE;
115
116    IOSelectLampSource( ps );
117    IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
118
119	ps->AsicReg.RD_Motor0Control = _MotorOn;
120	ps->AsicReg.RD_StepControl 	 = _MOTOR0_SCANSTATE;
121	ps->AsicReg.RD_Origin 		 = 4;
122	ps->AsicReg.RD_Pixels 		 = 512;
123	ps->AsicReg.RD_Motor1Control = 0;
124	ps->AsicReg.RD_Motor0Control = 0;
125
126	ps->AsicReg.RD_ModelControl  = _LED_CONTROL + _LED_ACTIVITY;
127
128    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
129		ps->AsicReg.RD_Dpi = 300;
130		ps->AsicReg.RD_ModelControl += _ModelDpi300;
131
132    } else {
133		ps->AsicReg.RD_Dpi = 600;
134		ps->AsicReg.RD_ModelControl += _ModelDpi600;
135    }
136}
137
138/**
139 */
140static UShort dacP98CalDarkOff( pScanData ps, UShort wChDarkOff,
141							    UShort wDACCompareHigh, UShort wDACOffset )
142{
143    UShort wTemp;
144
145    if ((_CCD_518 == ps->Device.bCCDID) || (_CCD_535 == ps->Device.bCCDID)) {
146		wTemp = wChDarkOff + wDACOffset;
147	} else  {
148
149		if (_CCD_3797 == ps->Device.bCCDID) {
150		    if (wChDarkOff > wDACOffset) {
151				wTemp = wChDarkOff - wDACOffset;
152			} else {
153				wTemp = 0;
154			}
155		} else {
156		    if (wChDarkOff > wDACCompareHigh) {
157				wTemp = wChDarkOff - wDACCompareHigh;
158			} else {
159				wTemp = 0;
160			}
161		}
162    }
163    return wTemp;
164}
165
166/**
167 */
168static Bool dacP98AdjustDAC( UShort DarkOff, UShort wHigh,
169							 UShort wLow, pUChar pbReg, Bool *fDACStopFlag )
170{
171    if (DarkOff > wHigh) {
172		if ((DarkOff - wHigh) > 10) {
173		    if ((DarkOff - wHigh) > 2550)
174				*pbReg += ((DarkOff - wHigh) / 20);
175		    else
176			*pbReg += ((DarkOff - wHigh) / 10);
177		} else
178	    	*pbReg += 1;
179
180		if (!(*pbReg))
181		    *pbReg = 0xff;
182
183		*fDACStopFlag = _FALSE;
184		return _FALSE;
185
186    } else {
187		if (DarkOff < wLow) {
188		    if (DarkOff > 0)
189				*pbReg -= 2;
190		    else
191				*pbReg -= 10;
192
193		    *fDACStopFlag = _FALSE;
194		    return _FALSE;
195		} else
196		    return _TRUE;
197	}
198}
199
200/**
201 */
202static Bool dacP98CheckChannelDarkLevel( pScanData ps )
203{
204	Bool fDACStopFlag = _TRUE;
205
206    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Red,
207                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Red,
208                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Red,
209			         &ps->bRedDAC, &fDACStopFlag );
210    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Green,
211                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Green,
212                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Green,
213			         &ps->bGreenDAC, &fDACStopFlag );
214    dacP98AdjustDAC( ps->Shade.DarkOffset.Colors.Blue,
215                     ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue,
216                     ps->Shade.pCcdDac->DarkCmpLo.Colors.Blue,
217			         &ps->bBlueDAC, &fDACStopFlag );
218
219    return  fDACStopFlag;
220}
221
222/** Average left offset 30, 16 pixels as each color's dark level
223 */
224static void dacP98FillChannelDarkLevelControl( pScanData ps )
225{
226    DataPointer p;
227	ULong	    dwPos, dw, dwSum;
228
229    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
230		dwPos = 0x10 * 3;
231	} else {
232		dwPos = 0x20 * 2;
233	}
234
235    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos), dwSum = 0, dw = 16;
236	     dw; dw--, p.pw++) {
237		dwSum += (ULong)(*p.pw);
238	}
239
240	ps->Shade.DarkOffset.Colors.Red = (UShort)(dwSum / 16);
241
242    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos + 1024), dwSum = 0, dw = 16;
243	    dw; dw--, p.pw++) {
244		dwSum += (ULong)(*p.pw);
245	}
246
247    ps->Shade.DarkOffset.Colors.Green = (UShort)(dwSum / 16);
248
249    for (p.pw = (pUShort)(ps->pScanBuffer1 + dwPos + 1024 * 2), dwSum = 0, dw = 16;
250	    dw; dw--, p.pw++) {
251		dwSum += (ULong)(*p.pw);
252	}
253
254	ps->Shade.DarkOffset.Colors.Blue = (UShort)(dwSum / 16);
255}
256
257/**
258 */
259static void dacP98AdjustGain( pScanData ps )
260{
261	DataPointer	p;
262	ULong		dw;
263	UShort		w;
264    Byte		b[3];
265    pUChar		pbReg[3];
266
267    dacP98AdjustGainAverage( ps );
268
269    pbReg[0] = &ps->bRedGainIndex;
270    pbReg[1] = &ps->bGreenGainIndex;
271    pbReg[2] = &ps->bBlueGainIndex;
272
273    for (w = 0, p.pb = ps->pScanBuffer1; w < 3; w++) {
274
275		for (dw = 2560 / 16, b [w] = 0; dw; dw--, p.pb++) {
276		    if (b [w] < *p.pb)
277				b [w] = *p.pb;
278		}
279		if (b[w] < _GAIN_LOW) {
280		    if ((_GAIN_P98_HIGH - b[w]) < b[w])
281				*(pbReg[w]) += 1;
282		    else
283				*(pbReg[w]) += 4;
284		} else {
285		    if (b[w] > _GAIN_P98_HIGH)
286				*(pbReg[w]) -= 1;
287		}
288    }
289}
290
291/**
292 */
293static void dacP98CheckLastGain( pScanData ps )
294{
295    DataPointer p;
296 	ULong	    dw;
297    UShort	    w;
298    Byte	    b[3];
299    pUChar	    pbReg[3];
300
301    dacP98AdjustGainAverage( ps );
302
303    pbReg[0] = &ps->bRedGainIndex;
304    pbReg[1] = &ps->bGreenGainIndex;
305    pbReg[2] = &ps->bBlueGainIndex;
306
307    for (w = 0, p.pb = ps->pScanBuffer1; w < 3; w++) {
308		for (dw = 2560 / 16, b [w] = 0; dw; dw--, p.pb++) {
309		    if (b[w] < *p.pb)
310				b[w] = *p.pb;
311		}
312
313		if (b[w] > _GAIN_P98_HIGH) {
314		    *(pbReg [w]) -= 1;
315		}
316    }
317}
318
319/**
320 */
321static void dacP98FillGainInitialRestRegister( pScanData ps )
322{
323	ps->OpenScanPath( ps );
324
325	IODataToRegister( ps, ps->RegThresholdGapControl, ps->AsicReg.RD_ThresholdGapCtrl );
326	IODataToRegister( ps, ps->RegModelControl, ps->AsicReg.RD_ModelControl );
327
328	ps->CloseScanPath( ps );
329}
330
331/**
332 */
333static void dacP98SetInitialGainRegister( pScanData ps )
334{
335	DacP98FillGainOutDirectPort( ps );	   	/* R/G/B GainOut to scanner		*/
336    dacP98FillGainInitialRestRegister( ps );/* Model Control2, LED, Correct.*/
337}
338
339/** Find the most ideal intensity for each color (RGB)
340 */
341static void dacP98SetRGBGainRegister( pScanData ps )
342{
343    IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeIdle );
344
345	ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
346    IOSelectLampSource( ps );
347
348    IOCmdRegisterToScanner( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
349    dacP98SetInitialGainRegister( ps );
350
351    ps->AsicReg.RD_ModeControl   = _ModeScan;
352    ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
353    ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorDirForward + _MotorHEightStep;
354    ps->AsicReg.RD_XStepTime 	 = ps->bSpeed4;
355
356    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
357		ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi300;
358		ps->AsicReg.RD_Origin = 32 +  60 + 4;
359    } else {
360		ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi600;
361		ps->AsicReg.RD_Origin = 64 + 120 + 4;
362    }
363    ps->AsicReg.RD_Dpi    = 300;
364    ps->AsicReg.RD_Pixels = 2560;
365
366	IOPutOnAllRegisters( ps );
367}
368
369/**
370 */
371static void dacP98FillRGBMap( pUChar pBuffer )
372{
373    ULong  dw, dw1;
374	pULong pdw = (pULong)(pBuffer);
375
376    for( dw = 256, dw1 = 0; dw; dw--, dw1 += 0x01010101 ) {
377		*pdw++ = dw1;
378		*pdw++ = dw1;
379		*pdw++ = dw1;
380		*pdw++ = dw1;
381    }
382}
383
384/** here we download the current mapping table
385 */
386static void dacP98DownloadMapTable( pScanData ps, pUChar pBuffer )
387{
388    Byte  bAddr;
389    ULong i;
390
391    IODataToRegister( ps, ps->RegScanControl,
392	   			(Byte)((ps->AsicReg.RD_ScanControl & 0xfc) | _SCAN_BYTEMODE));
393
394    for( i = 3, bAddr = _MAP_ADDR_RED; i--; bAddr += _MAP_ADDR_SIZE ) {
395
396        IODataToRegister( ps, ps->RegModeControl, _ModeMappingMem );
397        IODataToRegister( ps, ps->RegMemoryLow, 0);
398        IODataToRegister( ps, ps->RegMemoryHigh, bAddr );
399
400    	IOMoveDataToScanner( ps, pBuffer, 4096 );
401    	pBuffer += 4096;
402    }
403
404    IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
405}
406
407/**
408 */
409static void dacP98DownloadShadingTable( pScanData ps,
410                                        pUChar pBuffer, ULong size )
411{
412    IODataToRegister( ps, ps->RegModeControl, _ModeShadingMem );
413	IODataToRegister( ps, ps->RegMemoryLow,  0 );
414    IODataToRegister( ps, ps->RegMemoryHigh, 0 );
415
416    /* set 12 bits output color */
417    IODataToRegister( ps, ps->RegScanControl,
418					  (Byte)(ps->AsicReg.RD_ScanControl | _SCAN_12BITMODE));
419
420	/* MoveDataToShadingRam() */
421    IOMoveDataToScanner( ps ,pBuffer, size );
422
423    if( _ASIC_IS_98003 == ps->sCaps.AsicID )
424        IODataToRegister( ps, ps->RegModeControl, _ModeScan );
425    else
426        IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
427
428    DacP98FillShadingDarkToShadingRegister( ps );
429}
430
431/** Build a linear map for asic (this model is 12-bit scanner, there are 4096
432 *  map entries but just generate 256 level output, so the content must be 0 to
433 *  255), then fill the shading buffer (the first 3k), and map table (the last
434 *  1k) to asic for R & G & B channels.
435 *
436 *  I need pScanBuffer2 size = 5400 * 2 * 3
437 *  pScanBuffer1 size = 256 * 16 * 2
438 */
439static void dacP98SetInitialGainRAM( pScanData ps )
440{
441    memset( ps->pScanBuffer2, 0xff, (5400 * 2 * 3));
442
443	dacP98DownloadShadingTable( ps, ps->pScanBuffer2, (5400 * 2 * 3));
444
445    dacP98FillRGBMap( ps->pScanBuffer1 );		   	/* Fill 12 Bits R Map */
446    dacP98FillRGBMap( ps->pScanBuffer1 + 4096 );    /* Fill 12 Bits G Map */
447    dacP98FillRGBMap( ps->pScanBuffer1 + 8192 );    /* Fill 12 Bits B Map */
448
449	dacP98DownloadMapTable( ps, ps->pScanBuffer1 );
450}
451
452/** Find the most ideal intensity for each color (RGB)
453 */
454static void dacP98AdjustRGBGain( pScanData ps )
455{
456	int bCorrectTimes;
457
458	DBG( DBG_LOW, "dacP98AdjustRGBGain()\n" );
459
460	ps->OpenScanPath( ps );
461	dacP98SetInitialGainRAM( ps );	/* set shading ram and read out data to */
462    ps->CloseScanPath( ps );
463
464    ps->bRedGainIndex   = 0x02;
465	ps->bGreenGainIndex = 0x02;
466	ps->bBlueGainIndex  = 0x02;
467
468    for (bCorrectTimes = 10; bCorrectTimes; bCorrectTimes-- ) {
469
470		dacP98SetRGBGainRegister( ps );	   	 /* shading the most brightness &*/
471		ps->PauseColorMotorRunStates( ps );	 /* stop scan states			 */
472		IOReadOneShadingLine( ps, ps->pScanBuffer1, 2560UL );
473		dacP98AdjustGain( ps );
474    }
475
476    dacP98SetRGBGainRegister( ps );		/* shading the most brightness &	*/
477	ps->PauseColorMotorRunStates( ps ); /* stop scan states                */
478
479    IOReadOneShadingLine( ps, ps->pScanBuffer1, 2560UL );
480
481    dacP98CheckLastGain( ps );
482	DacP98FillGainOutDirectPort( ps );
483}
484
485/**
486 */
487static void dacP98SetAdjustShadingRegister( pScanData ps )
488{
489	DBG( DBG_LOW, "dacP98SetAdjustShadingRegister()\n" );
490
491	IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeIdle );
492
493	ps->AsicReg.RD_ScanControl = _SCAN_12BITMODE + _SCAN_1ST_AVERAGE;
494	IOSelectLampSource( ps );
495
496    IOCmdRegisterToScanner( ps, ps->RegScanControl,
497							ps->AsicReg.RD_ScanControl );
498
499	ps->AsicReg.RD_ModeControl 	 = _ModeScan;
500	ps->AsicReg.RD_Motor0Control = _MotorOn + _MotorHEightStep + _MotorDirForward;
501	ps->AsicReg.RD_XStepTime 	 = ps->bSpeed1;
502	ps->AsicReg.RD_ModelControl  = _LED_ACTIVITY + _LED_CONTROL;
503
504    if (ps->bSetScanModeFlag & _ScanMode_AverageOut) {
505		ps->AsicReg.RD_Dpi 	  = 300;
506		ps->AsicReg.RD_Pixels = 2700;
507		ps->AsicReg.RD_ModelControl += _ModelDpi300;
508    } else {
509		ps->AsicReg.RD_Dpi 	  = 600;
510		ps->AsicReg.RD_Pixels = 5400;
511		ps->AsicReg.RD_ModelControl += _ModelDpi600;
512    }
513	ps->AsicReg.RD_Origin = 4;
514
515	IOPutOnAllRegisters( ps );
516}
517
518/**
519 */
520static void dacP98ReadShadingScanLine( pScanData ps )
521{
522	TimerDef timer;
523
524	MiscStartTimer( &timer, _SECOND );
525
526    ps->Scan.bFifoSelect = ps->RegGFifoOffset;
527
528    while((IOReadFifoLength( ps ) < dwReadyLen) &&
529		   !MiscCheckTimer(&timer)) {
530		_DO_UDELAY( 1 );
531	}
532
533    IOReadColorData( ps, ps->pScanBuffer2, ps->dwShadingLen );
534}
535
536/**
537 */
538static void dacP98GainResize( pUShort pValue, UShort wResize)
539{
540	DataType Data;
541    Byte	 bTemp;
542
543    Data.dwValue = ((ULong) *pValue) * (ULong) wResize / 100;
544
545    if (0x1000 <= Data.dwValue)
546		Data.wValue = 0xfff;
547
548    Data.wValue *= 16;
549
550    bTemp = Data.wOverlap.b1st;
551    Data.wOverlap.b1st = Data.wOverlap.b2nd;
552    Data.wOverlap.b2nd = bTemp;
553
554    *pValue = Data.wValue;
555}
556
557/**
558 */
559static void dacP98SortHilightShadow( pScanData ps, pUShort pwData,
560					 			     ULong dwHilightOff, ULong dwShadowOff )
561{
562	ULong   dwLines, dwPixels;
563    UShort  wVCmp, wTmp;
564    pUShort pw;
565
566    for (dwPixels = 0; dwPixels < (ps->dwShadingPixels - 4); dwPixels++) {
567
568		pw    = (pUShort)ps->Shade.pHilight + dwHilightOff + dwPixels;
569		wVCmp = pwData[dwPixels] & 0xfffU;
570
571		for (dwLines = _DEF_BRIGHTEST_SKIP; dwLines--; pw += 5400UL) {
572		    if (wVCmp > *pw) {
573				wTmp  = wVCmp;
574				wVCmp = *pw;
575				*pw   = wTmp;
576		    }
577		}
578    }
579    for (dwPixels = 0; dwPixels < (ps->dwShadingPixels - 4); dwPixels++) {
580
581		pw    = ps->pwShadow + dwShadowOff + dwPixels;
582		wVCmp = pwData [dwPixels] & 0xfffU;
583
584		for (dwLines = _DEF_DARKEST_SKIP; dwLines--; pw += 5400UL) {
585
586		    if (wVCmp < *pw) {
587				wTmp  = wVCmp;
588				wVCmp = *pw;
589				*pw   = wTmp;
590	    	}
591		}
592    }
593}
594
595/**
596 */
597static void dacP98WriteBackToShadingRAM( pScanData ps )
598{
599	ULong   dw;
600
601	pUShort	pBuffer = (pUShort)ps->pScanBuffer2;
602
603	DBG( DBG_LOW, "dacP98WriteBackToShadingRAM()\n" );
604
605    if (ps->DataInf.wPhyDataType >= COLOR_TRUE24) {
606
607		for (dw = 0; dw < 5400; dw++) {
608
609		    *pBuffer = ((pUShort)ps->pScanBuffer1)[dw] -
610                                            ps->Shade.DarkOffset.Colors.Red;
611			dacP98GainResize( pBuffer,
612                              ps->Shade.pCcdDac->GainResize.Colors.Red );
613		    pBuffer ++;
614
615		    *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400] -
616                                            ps->Shade.DarkOffset.Colors.Green;
617			dacP98GainResize( pBuffer,
618                              ps->Shade.pCcdDac->GainResize.Colors.Green );
619		    pBuffer ++;
620
621		    *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400 * 2] -
622                                             ps->Shade.DarkOffset.Colors.Blue;
623			dacP98GainResize( pBuffer,
624                              ps->Shade.pCcdDac->GainResize.Colors.Blue );
625		    pBuffer ++;
626		}
627
628    } else {
629		for (dw = 0; dw < 5400; dw++) {
630
631			DataType Data;
632			Byte	 bTemp;
633
634		    *pBuffer = ((pUShort)ps->pScanBuffer1)[dw + 5400] -
635                                            ps->Shade.DarkOffset.Colors.Green;
636
637		    Data.wValue = (*pBuffer) * 16;
638		    bTemp = Data.wOverlap.b1st;
639	    	Data.wOverlap.b1st = Data.wOverlap.b2nd;
640		    Data.wOverlap.b2nd = bTemp;
641		    *pBuffer = Data.wValue;
642		    pBuffer++;
643		}
644
645    }
646	dacP98DownloadShadingTable( ps, ps->pScanBuffer2, (5400 * 2 * 3));
647}
648
649/**
650 */
651static void dacP98ShadingRunLoop( pScanData ps )
652{
653	int		    i;
654	DataPointer p;
655
656    p.pb = ps->a_nbNewAdrPointer;
657
658    switch( ps->IO.portMode ) {
659	case _PORT_SPP:
660	case _PORT_BIDI:
661	    *p.pw++ = 0;
662	    for (i = 0; i < 7; i++)
663			*p.pdw++ = 0x00800700;
664	    *p.pw = 0;
665	    break;
666
667	default:
668	    *p.pb++ = 0;
669	    for (i = 0; i < 15; i++)
670			*p.pw++ = 0xf888;
671	    *p.pb = 0;
672    }
673
674	IOSetToMotorRegister( ps );
675}
676
677/**
678 */
679static void dacP98Adjust12BitShading( pScanData ps )
680{
681	DataPointer pd, pt;
682    ULong		dw, dw1, dwLoop;
683
684	DBG( DBG_LOW, "dacP98Adjust12BitShading()\n" );
685
686    memset( ps->pScanBuffer1, 0, (5400 * 4 * 3));
687
688    if( ps->Shade.pHilight && (_Shading_32Times == ps->bShadingTimeFlag)) {
689
690		memset( ps->Shade.pHilight, 0, (ps->dwHilight * 2UL));
691
692		for (dw = 0; dw < ps->dwShadow; dw++)
693		    ps->pwShadow[dw] = 0xfff;
694    }
695
696	/*
697	 * in the original code this function does not exist !
698	 * (of course the code behind the function does ;-)
699	 */
700	dacP98SetAdjustShadingRegister( ps );
701
702    dacP98ShadingRunLoop( ps );
703    _DODELAY( 24 );
704
705    if ((ps->DataInf.dwScanFlag & SCANDEF_TPA ) ||
706	  	(_Shading_32Times == ps->bShadingTimeFlag)) {
707		dwLoop = 32;
708	} else {
709		if (_Shading_16Times == ps->bShadingTimeFlag) {
710		   dwLoop = 16;
711		} else {
712		   dwLoop = 4;
713		}
714    }
715
716    for (dw1 = 0; dw1 < dwLoop; dw1++) {
717
718        ps->Scan.bFifoSelect = ps->RegGFifoOffset;
719
720		dacP98ReadShadingScanLine( ps );
721
722		if((_Shading_32Times == ps->bShadingTimeFlag) && ps->Shade.pHilight ) {
723
724		    dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2, 0, 0 );
725	    	dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2 +
726												  ps->dwShadingPixels,
727						       	     ps->dwHilightCh, ps->dwShadowCh );
728
729		    dacP98SortHilightShadow( ps, (pUShort)ps->pScanBuffer2 +
730												  ps->dwShadingPixels * 2,
731							       	  ps->dwHilightCh * 2, ps->dwShadowCh * 2);
732		}
733
734	    /* SumAdd12BitShadingR */
735		pd.pw  = (pUShort)ps->pScanBuffer2;
736		pt.pdw = (pULong)(ps->pScanBuffer1 + dwADCPipeLine);
737
738		for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
739		    *pt.pdw += (ULong)(*pd.pw & 0x0fff);
740
741	    /* SumAdd10BitShadingG */
742		if( ps->bSetScanModeFlag & _ScanMode_AverageOut )
743		    pd.pw = (pUShort)(ps->pScanBuffer2 + 2700 * 2);
744		else
745		    pd.pw = (pUShort)(ps->pScanBuffer2 + 5400 * 2);
746
747		pt.pdw = (pULong)(ps->pScanBuffer1 + 5400 * 4 + dwADCPipeLine);
748
749		for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
750	    	*pt.pdw += (ULong)(*pd.pw & 0x0fff);
751
752	    /* SumAdd12BitShadingB */
753		if( ps->bSetScanModeFlag & _ScanMode_AverageOut )
754		    pd.pw = (pUShort)(ps->pScanBuffer2 + 2700 * 4);
755		else
756	    	pd.pw = (pUShort)(ps->pScanBuffer2 + 5400 * 4);
757
758		pt.pdw = (pULong)(ps->pScanBuffer1 + 5400 * 8 + dwADCPipeLine);
759
760		for (dw = 5400 - 4; dw; dw--, pd.pw++, pt.pdw++)
761		    *pt.pdw += (ULong)(*pd.pw * 94 / 100 & 0x0fff);
762
763		/* one line */
764		if (IOReadFifoLength( ps ) <= 2500)
765	    	IORegisterDirectToScanner( ps, ps->RegRefreshScanState );
766    }
767
768    TPAP98001AverageShadingData( ps );
769
770	ps->OpenScanPath( ps );
771	dacP98WriteBackToShadingRAM( ps );
772	ps->CloseScanPath( ps );
773}
774
775/**
776 */
777static Bool dacP98WaitForShading( pScanData ps )
778{
779    Byte oldLineControl;
780
781	DBG( DBG_LOW, "dacP98WaitForShading()\n" );
782
783	/*
784	 * before getting the shading data, (re)init the ASIC
785	 */
786    ps->InitialSetCurrentSpeed( ps );
787	ps->ReInitAsic( ps, _TRUE );
788
789	IOCmdRegisterToScanner( ps, ps->RegLineControl,
790							ps->AsicReg.RD_LineControl );
791
792    ps->Shade.DarkOffset.Colors.Red   = 0;
793	ps->Shade.DarkOffset.Colors.Green = 0;
794	ps->Shade.DarkOffset.Colors.Blue  = 0;
795
796	/*
797	 * according to the scan mode, switch on the lamp
798	 */
799    IOSelectLampSource( ps );
800    IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
801
802    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
803		ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi300;
804	} else {
805		ps->AsicReg.RD_ModelControl = _LED_CONTROL + _ModelDpi600;
806	}
807    IOCmdRegisterToScanner( ps, ps->RegModelControl,
808							ps->AsicReg.RD_ModelControl );
809
810    IOCmdRegisterToScanner( ps, ps->RegModeControl, _ModeScan);
811
812    oldLineControl = ps->AsicReg.RD_LineControl;
813	IOSetXStepLineScanTime( ps, _DEFAULT_LINESCANTIME );
814
815	/* set line control */
816	IOCmdRegisterToScanner( ps, ps->RegLineControl,
817							ps->AsicReg.RD_LineControl );
818
819	/* Wait for Sensor to position */
820	if( !ps->GotoShadingPosition( ps ))
821		return _FALSE;
822
823    ps->AsicReg.RD_LineControl = oldLineControl;
824    IOCmdRegisterToScanner( ps, ps->RegLineControl,
825							ps->AsicReg.RD_LineControl );
826
827    dwADCPipeLine = 4 * 4;
828
829    if( ps->bSetScanModeFlag & _ScanMode_AverageOut ) {
830		dwReadyLen			= 2500;
831		ps->dwShadingLen	= 2700 * 2;
832		ps->dwShadingPixels	= 2700;
833    } else {
834		dwReadyLen			= 5000;
835		ps->dwShadingLen	= 5400 * 2;
836		ps->dwShadingPixels	= 5400;
837    }
838
839	dacP98AdjustRGBGain		( ps );
840	DacP98AdjustDark		( ps );
841	dacP98Adjust12BitShading( ps );
842
843    ps->OpenScanPath( ps );
844	DacP98FillShadingDarkToShadingRegister( ps );
845
846	if ( COLOR_BW != ps->DataInf.wPhyDataType )
847		dacP98DownloadMapTable( ps, ps->a_bMapTable );
848
849    ps->CloseScanPath( ps );
850
851    return _TRUE;
852}
853
854/** Set RAM bank and size, then write the data to it
855 */
856static void dacP96FillWhole4kRAM( pScanData ps, pUChar pBuf )
857{
858    ps->OpenScanPath( ps );
859
860	IODataToRegister( ps, ps->RegMemAccessControl,
861		    			  ps->Asic96Reg.RD_MemAccessControl );
862
863    ps->AsicReg.RD_ModeControl = _ModeProgram;
864    IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );
865
866    IOMoveDataToScanner( ps, pBuf, ps->ShadingBankSize );
867
868    ps->AsicReg.RD_ModeControl = _ModeScan;
869    IODataToRegister( ps, ps->RegModeControl, ps->AsicReg.RD_ModeControl );
870
871    ps->CloseScanPath( ps );
872}
873
874/**
875 */
876static void	dacP96FillChannelDarkOffset( pScanData ps )
877{
878    ps->OpenScanPath( ps );
879
880	IODataToRegister( ps, ps->RegRedChDarkOffset,
881					  ps->Asic96Reg.RD_RedChDarkOff );
882    IODataToRegister( ps, ps->RegGreenChDarkOffset,
883					  ps->Asic96Reg.RD_GreenChDarkOff );
884    IODataToRegister( ps, ps->RegBlueChDarkOffset,
885					  ps->Asic96Reg.RD_BlueChDarkOff );
886
887    ps->CloseScanPath( ps );
888}
889
890/**
891 */
892static void dacP96FillEvenOddControl( pScanData ps )
893{
894    ps->OpenScanPath( ps );
895
896	IODataToRegister( ps, ps->RegRedChEvenOffset,
897					  ps->Asic96Reg.RD_RedChEvenOff );
898	IODataToRegister( ps, ps->RegGreenChEvenOffset,
899					  ps->Asic96Reg.RD_GreenChEvenOff );
900	IODataToRegister( ps, ps->RegBlueChEvenOffset,
901					  ps->Asic96Reg.RD_BlueChEvenOff );
902	IODataToRegister( ps, ps->RegRedChOddOffset,
903					  ps->Asic96Reg.RD_RedChOddOff );
904	IODataToRegister( ps, ps->RegGreenChOddOffset,
905					  ps->Asic96Reg.RD_GreenChOddOff );
906	IODataToRegister( ps, ps->RegBlueChOddOffset,
907					  ps->Asic96Reg.RD_BlueChOddOff );
908
909    ps->CloseScanPath( ps );
910}
911
912/** Used for capture data to pScanData->pPrescan16.
913 *  Used to replace:
914 *	1) ReadFBKScanLine (3 * 1024, 5)
915 *	2) ReadOneScanLine (3 * 2560, 11)
916 *	4) ReadShadingScanLine (3 * 1280, 6)
917 */
918static void dacP96ReadDataWithinOneSecond( pScanData ps,
919										   ULong dwLen, Byte bBlks )
920{
921	TimerDef timer;
922
923    MiscStartTimer( &timer, _SECOND );
924
925    while((IODataRegisterFromScanner( ps, ps->RegFifoOffset) < bBlks) &&
926	   		!MiscCheckTimer(&timer));
927
928    IOReadScannerImageData( ps, ps->pPrescan16, dwLen );
929}
930
931/**
932 */
933static void dacP96GetEvenOddOffset( pUChar pb, pWordVal pwv )
934{
935	ULong	dw;
936    UShort	we, wo;
937
938    for (dw = 8, we = wo = 0; dw; dw-- ) {
939		we += *pb++;
940		wo += *pb++;
941    }
942
943    pwv->b1st = (Byte)(we >> 3);
944    pwv->b2nd = (Byte)(wo >> 3);
945}
946
947/**
948 */
949static void dacP96SumAverageShading( pScanData ps, pUChar pDest, pUChar pSrce )
950{
951	ULong  dw;
952	UShort wLeft[6];
953	UShort wSumL, wSumR;
954
955    pSrce += ps->Offset70 + ps->Device.DataOriginX;
956    pDest += ps->Offset70 + ps->Device.DataOriginX;
957
958    wLeft[0] = wLeft[1] = wLeft[2] =
959	wLeft[3] = wLeft[4] = wLeft[5] = (UShort)*pSrce;
960
961    wSumL = wLeft[0] * 6;
962    wSumR = (UShort)pSrce[1] + pSrce[2] + pSrce[3] + pSrce[4] +
963		            pSrce[5] + pSrce[6];
964
965/*  for (dw = 2772; dw; dw--, pSrce++, pDest++) */
966    for (dw = ps->BufferSizePerModel - 6; dw; dw--, pSrce++, pDest++) {
967
968		*pDest = (Byte)(((UShort)*pSrce * 4 + wSumL + wSumR) / 16);
969		wSumL  = wSumL - wLeft [0] + (UShort)*pSrce;
970
971		wLeft[0] = wLeft[1];
972		wLeft[1] = wLeft[2];
973		wLeft[2] = wLeft[3];
974		wLeft[3] = wLeft[4];
975		wLeft[4] = wLeft[5];
976		wLeft[5] = (UShort)*pSrce;
977		wSumR = wSumR - (UShort) *(pSrce + 1) + (UShort) *(pSrce + 7);
978    }
979}
980
981/**
982 */
983static void dacP96WriteLinearGamma( pScanData ps,
984								    pUChar pBuf, ULong dwEntries, Byte bBank )
985{
986	ULong   dw;
987    pULong	pdw = (pULong)(pBuf + ps->ShadingBufferSize);
988
989    for (dw = 0; dwEntries; pdw++, dwEntries--, dw += 0x01010101)
990		*pdw = dw;
991
992    ps->Asic96Reg.RD_MemAccessControl = bBank;
993
994    dacP96FillWhole4kRAM( ps, pBuf );
995}
996
997/**
998 */
999static void dacP96FillChannelShadingOffset( pScanData ps )
1000{
1001    ps->OpenScanPath( ps );
1002
1003	IODataToRegister( ps, ps->RegRedChShadingOffset,
1004					  ps->Asic96Reg.u28.RD_RedChShadingOff);
1005	IODataToRegister( ps, ps->RegGreenChShadingOffset,
1006					  ps->Asic96Reg.u29.RD_GreenChShadingOff);
1007	IODataToRegister( ps, ps->RegBlueChShadingOffset,
1008					  ps->Asic96Reg.RD_BlueChShadingOff);
1009
1010    ps->CloseScanPath( ps );
1011}
1012
1013/**
1014 */
1015static void dacP96GetHilightShadow( pScanData ps,
1016									pUChar pBuf, pUChar pChOff, pUChar pHigh )
1017{
1018 	ULong dw;
1019
1020	/* GetShadingImageExtent (ps) */
1021	if (ps->DataInf.wAppDataType < COLOR_256GRAY)
1022		dw = (ULong)(ps->DataInf.crImage.cx & 0xfff8);
1023	else
1024		dw = (ULong)ps->DataInf.crImage.cx;
1025
1026    for( pBuf += ps->DataInf.crImage.x, *pChOff = 0xff, *pHigh = 0;
1027		 dw; dw--, pBuf++ ) {
1028
1029		if (*pChOff < *pBuf) {
1030		    if (*pHigh < *pBuf)
1031				*pHigh = *pBuf; /* brightest */
1032		} else
1033		    *pChOff = *pBuf;	/* darkest */
1034    }
1035}
1036
1037/**
1038 */
1039static void dacP96ReadColorShadingLine( pScanData ps )
1040{
1041    Byte	 b2ndDiscard, b3rdDiscard, b1stReadLines, b2ndReadLines;
1042    Byte	 b3rdReadLines;
1043	ULong	 dw;
1044    DataType Data;
1045
1046    /* ClearScanBuffer1 (ps) */
1047	/* buffer to keep sum of data */
1048    memset( ps->pScanBuffer1, 0, ps->BufferForDataRead1 );
1049
1050    b2ndDiscard   = ps->b2ndLinesOffset;
1051    b3rdDiscard   = ps->b1stLinesOffset;
1052    b1stReadLines = b2ndReadLines = b3rdReadLines = 8;
1053
1054    while( _TRUE ) {
1055
1056		/* ReadShadingScanLine(ps) */
1057		dacP96ReadDataWithinOneSecond( ps, ps->ShadingScanLineLen,
1058					 				   ps->ShadingScanLineBlks );
1059
1060		if (b1stReadLines) {
1061
1062		    b1stReadLines--;
1063
1064	    	/* SumAdd10BitShadingR */
1065		    for (dw = 0; dw < ps->BufferSizeBase; dw++)
1066    			((pUShort)ps->pScanBuffer1)[dw] += (UShort)ps->pPrescan16 [dw];
1067		}
1068
1069		if (!b2ndDiscard) {
1070		    if (b2ndReadLines) {
1071				b2ndReadLines--;
1072				/* SumAdd10BitShadingG */
1073				for (dw = ps->BufferSizeBase;dw < (ULong)ps->BufferSizeBase * 2;dw++) {
1074				    ((pUShort)ps->pScanBuffer1)[dw] +=
1075													(UShort)ps->pPrescan16[dw];
1076				}
1077		    }
1078		} else
1079		    b2ndDiscard--;
1080
1081		if (!b3rdDiscard) {
1082		    if (b3rdReadLines) {
1083				b3rdReadLines--;
1084				/* SumAdd10BitShadingB */
1085				for (dw = ps->BufferSizeBase * 2;
1086						dw < (ULong)ps->BufferSizeBase * 3; dw++) {
1087				    ((pUShort)ps->pScanBuffer1)[dw] +=
1088													(UShort)ps->pPrescan16[dw];
1089				}
1090		    } else
1091				break;
1092		} else
1093		    b3rdDiscard--;
1094
1095		IORegisterDirectToScanner( ps, ps->RegRefreshScanState );
1096    }
1097
1098    for (dw = 0; dw < (ULong)ps->BufferSizeBase * 3; dw++) {
1099
1100		Data.wOverlap.b1st =
1101		Data.wOverlap.b2nd = (Byte)(((pUShort)ps->pScanBuffer1)[dw] / 8);
1102		((pUShort)ps->pPrescan16)[dw] = Data.wValue;
1103    }
1104}
1105
1106/**
1107 */
1108static void dacP96SetShadingGainProc( pScanData ps, Byte bHigh, ULong dwCh )
1109{
1110	Byte	bDark, bGain, bGainX2, bGainX4, bMask;
1111	pUChar	pbChDark, pbSrce, pbDest;
1112	ULong	dw;
1113
1114    pbChDark = NULL, pbSrce = NULL, pbDest = NULL;
1115    bDark = 0, bGain = 0, bGainX2 = 0, bGainX4 = 0, bMask = 0;
1116
1117    switch( dwCh ) {
1118
1119	case 0: 	/* red */
1120	    pbChDark = &ps->Asic96Reg.u28.RD_RedChShadingOff;
1121	    pbSrce   = ps->pPrescan16;
1122	    pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->Device.DataOriginX;
1123	    bGainX2  = 1;
1124	    bGainX4  = 3;
1125	    bMask    = 0x3c;
1126	    break;
1127
1128	case 1: 	/* green */
1129	    pbChDark = &ps->Asic96Reg.u29.RD_GreenChShadingOff;
1130	    pbSrce   = ps->pPrescan16 + ps->BufferSizePerModel;
1131	    pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->ShadingBankSize +
1132				   ps->Device.DataOriginX;
1133	    bGainX2  = 4;
1134	    bGainX4  = 0x0c;
1135	    bMask    = 0x33;
1136	    break;
1137
1138	case 2:
1139	    pbChDark = &ps->Asic96Reg.RD_BlueChShadingOff;
1140	    pbSrce   = ps->pPrescan16 + ps->BufferSizePerModel * 2;
1141	    pbDest   = ps->pScanBuffer1 + ps->Offset70 + ps->ShadingBankSize * 2 +
1142				   ps->Device.DataOriginX;
1143	    bGainX2  = 0x10;
1144	    bGainX4  = 0x30;
1145	    bMask    = 0x0f;
1146    }
1147
1148    bDark = *pbChDark;
1149    if ((bHigh -= bDark) > 60U) {
1150		/* Hilight - Shadow > 60, Quality not so good */
1151		bGain = bGainX2;		/* Gain x 2 */
1152		if (bHigh > 120U)
1153		    bGain = bGainX4;	/* Poor quality, Gain x 4 */
1154    } else
1155		bGain = 0;
1156
1157    ps->Asic96Reg.RD_ShadingCorrectCtrl &= bMask;
1158    ps->Asic96Reg.RD_ShadingCorrectCtrl |= bGain;
1159
1160    if (!bGain) {
1161		/* GammaGain1 (ps) */
1162		for (dw = ps->BufferSizePerModel; dw; dw--, pbSrce++, pbDest++)
1163		    if (*pbSrce > bDark)
1164				*pbDest = (*pbSrce - bDark) * 4;
1165	    	else
1166				*pbDest = 0;
1167    } else
1168		if (bGain == bGainX2) {
1169			/* GammaGain2 */
1170		    for (dw = ps->BufferSizePerModel; dw; dw--, pbSrce++, pbDest++)
1171				if (*pbSrce > bDark)
1172				    *pbDest = (*pbSrce - bDark) * 2;
1173				else
1174				    *pbDest = 0;
1175		} else {
1176			/* GammaGain4 (ps) */
1177			memcpy( pbDest, pbSrce, ps->BufferSizePerModel );
1178		    *pbChDark = 0;
1179		}
1180}
1181
1182/**
1183 */
1184static void dacP96FillShadingAndGammaTable( pScanData ps )
1185{
1186    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankRed;		/* R */
1187	dacP96FillWhole4kRAM( ps, ps->pPrescan16 );
1188
1189    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankGreen;	/* G */
1190	dacP96FillWhole4kRAM( ps, ps->pPrescan16 );
1191
1192    ps->Asic96Reg.RD_MemAccessControl = ps->ShadingBankBlue;	/* B */
1193	dacP96FillWhole4kRAM( ps, ps->pPrescan16 );
1194}
1195
1196/**
1197 */
1198static void dacP96SetInitialGainRAM( pScanData ps )
1199{
1200    ULong  dw, dw1;
1201	pULong pdw = (pULong)(ps->pPrescan16 + ps->ShadingBufferSize);
1202
1203	memset( ps->pPrescan16, 0xff, ps->ShadingBufferSize );
1204
1205    for (dw = 256, dw1 = 0; dw; dw--, dw1 += 0x01010101, pdw++)
1206		*pdw = dw1;
1207
1208	dacP96FillShadingAndGammaTable( ps );
1209}
1210
1211/**
1212 */
1213static void dacP96Adjust10BitShading( pScanData ps )
1214{
1215	pULong	pdw;
1216	ULong	dw;
1217	Byte	bRedHigh, bGreenHigh, bBlueHigh;
1218
1219    /* ShadingMotorRunLoop(ps)
1220	 * set scan states as:
1221     *	 40h, 00, 00, 00, 40h, 01, 03, 02, ... (repeat)
1222     * so, read a R/G/B line every 2 steps
1223	 */
1224    pdw = (pULong)ps->a_nbNewAdrPointer;
1225    for (dw = 0; dw < 4; dw++) {
1226		*pdw++ = 0x40;
1227		*pdw++ = 0x02030140;
1228	}
1229
1230    dacP96SetInitialGainRAM( ps);	/* initiates the shading buffers and maps */
1231
1232    /* SetAdjustShadingRegister(ps) */
1233    /* Prepare Physical/2 dpi, 8.5" scanning condition for reading the shading area */
1234    ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
1235    ps->Asic96Reg.RD_MotorControl = ps->IgnorePF | ps->MotorOn |
1236									_MotorDirForward;
1237    ps->AsicReg.RD_ModelControl   = ps->Device.ModelCtrl | _ModelWhiteIs0;
1238    ps->AsicReg.RD_Dpi    		  = ps->PhysicalDpi / 2;
1239    ps->AsicReg.RD_Origin 		  = (UShort)(ps->Offset70 +
1240                                             ps->Device.DataOriginX);
1241    ps->AsicReg.RD_Pixels 		  = ps->BufferSizeBase;
1242    IOPutOnAllRegisters( ps );
1243
1244    ps->Asic96Reg.RD_ShadingCorrectCtrl = _ShadingRCorrectX4|_ShadingGCorrectX4|
1245									      _ShadingBCorrectX4;
1246	IOCmdRegisterToScanner( ps, ps->RegShadingCorrectCtrl,
1247						 			    ps->Asic96Reg.RD_ShadingCorrectCtrl );
1248
1249    /* Read shaded data and do average */
1250	dacP96ReadColorShadingLine( ps );
1251
1252    /* ExpandAndAverage (ps) ------------------------------------------------*/
1253/*
1254	 for (dw = 0; dw < 1280 * 3; dw++)
1255   {
1256	Data.wOverlap.b1st =
1257	Data.wOverlap.b2nd = (Byte)(((pUShort) ps->pScanBuffer1)[dw] / 8);
1258	((pULong) ps->pPrescan16)[dw] = Data.wValue;
1259  }
1260*/
1261	/* CalculateShadingOffset (ps); */
1262    dacP96GetHilightShadow( ps, ps->pPrescan16,
1263						&ps->Asic96Reg.u28.RD_RedChShadingOff, &bRedHigh );
1264
1265    dacP96GetHilightShadow( ps, ps->pPrescan16 + ps->BufferSizePerModel,
1266			      &ps->Asic96Reg.u29.RD_GreenChShadingOff, &bGreenHigh );
1267
1268    dacP96GetHilightShadow( ps, ps->pPrescan16 + ps->BufferSizePerModel * 2,
1269				      &ps->Asic96Reg.RD_BlueChShadingOff, &bBlueHigh );
1270
1271	/* SubTheImageDataBase (ps) */
1272	dacP96SetShadingGainProc( ps, bRedHigh,   0 );	/* red	 */
1273	dacP96SetShadingGainProc( ps, bGreenHigh, 1 );	/* green */
1274	dacP96SetShadingGainProc( ps, bBlueHigh,  2 );	/* blue	 */
1275	dacP96FillChannelShadingOffset( ps );
1276
1277	IOCmdRegisterToScanner( ps, ps->RegShadingCorrectCtrl,
1278						    ps->Asic96Reg.RD_ShadingCorrectCtrl );
1279
1280	dacP96SumAverageShading( ps, ps->pPrescan16, ps->pScanBuffer1 );
1281	dacP96SumAverageShading( ps, ps->pPrescan16 + ps->ShadingBankSize,
1282			  			     ps->pScanBuffer1 + ps->ShadingBankSize );
1283	dacP96SumAverageShading( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
1284					         ps->pScanBuffer1 + ps->ShadingBankSize * 2 );
1285
1286    /* --------------------------------------------------------------------- */
1287
1288    /* PrewriteBackToGammaShadingRAM( ps) */
1289    dacP96WriteLinearGamma( ps, ps->pPrescan16, 256, ps->ShadingBankRed );
1290   	dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize, 256,
1291							ps->ShadingBankGreen );
1292   	dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
1293    					    256, ps->ShadingBankBlue );
1294}
1295
1296/**
1297 */
1298static Bool dacP96003WaitForShading( pScanData ps )
1299{
1300	int 		bCorrectTimes;
1301	DataPointer	p;
1302    ULong		dw;
1303    UShort		w;
1304    WordVal 	wv;
1305	pUChar		pbReg[3];
1306    Byte		b[3];
1307
1308	DBG( DBG_LOW, "dacP96003WaitForShading()\n" );
1309
1310    /* TurnOnLamp () */
1311	ps->AsicReg.RD_ScanControl |= ps->bLampOn;
1312	IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
1313
1314	ps->Asic96Reg.RD_LedControl = _LedActControl | _LedMotorActEnable;
1315	IOCmdRegisterToScanner(ps, ps->RegLedControl, ps->Asic96Reg.RD_LedControl);
1316
1317    if ( ps->GotoShadingPosition( ps )) {
1318
1319    	/* AdjustRGBGain () =================================================*/
1320		ps->Asic96Reg.RD_RedGainOut  = ps->Asic96Reg.RD_GreenGainOut =
1321		ps->Asic96Reg.RD_BlueGainOut = 8;
1322		ps->Asic96Reg.u26.RD_ModelControl2 = _Model2DirectOutPort;
1323
1324		IOCmdRegisterToScanner(ps, ps->RegModelControl2, _Model2DirectOutPort);
1325
1326		for ( bCorrectTimes = 4; bCorrectTimes >= 1; bCorrectTimes-- ) {
1327
1328			ps->PauseColorMotorRunStates( ps );
1329
1330			/* SetRGBGainRegister () ----------------------------------------*/
1331		    ps->AsicReg.RD_ScanControl = ps->bLampOn | _SCAN_BYTEMODE;
1332		    dacP96SetInitialGainRAM( ps );
1333
1334		    /* SetInitialGainRegister () ++++++++++++++++++++++++++++++++++++*/
1335		    ps->Asic96Reg.u28.RD_RedChShadingOff	=
1336			ps->Asic96Reg.u29.RD_GreenChShadingOff	=
1337		    ps->Asic96Reg.RD_BlueChShadingOff		=
1338		    ps->Asic96Reg.RD_RedChDarkOff		 	=
1339		    ps->Asic96Reg.RD_GreenChDarkOff			=
1340		    ps->Asic96Reg.RD_BlueChDarkOff			=
1341		    ps->Asic96Reg.RD_RedChEvenOff			=
1342		    ps->Asic96Reg.RD_GreenChEvenOff			=
1343		    ps->Asic96Reg.RD_BlueChEvenOff			=
1344		    ps->Asic96Reg.RD_RedChOddOff			=
1345		    ps->Asic96Reg.RD_GreenChOddOff			=
1346		    ps->Asic96Reg.RD_BlueChOddOff			= 0;
1347		    ps->Asic96Reg.RD_ShadingCorrectCtrl = _ShadingRCorrectX4 |
1348					 					    	  _ShadingGCorrectX4 |
1349											      _ShadingBCorrectX4;
1350
1351			dacP96FillChannelShadingOffset( ps );
1352		    dacP96FillChannelDarkOffset( ps );
1353			dacP96FillEvenOddControl( ps );
1354
1355		    /* FillGainOutDirectPort (); */
1356			ps->OpenScanPath( ps );
1357			IODataToRegister( ps, ps->RegRedGainOutDirect,
1358							  ps->Asic96Reg.RD_RedGainOut );
1359			IODataToRegister( ps, ps->RegGreenGainOutDirect,
1360							  ps->Asic96Reg.RD_GreenGainOut );
1361			IODataToRegister( ps, ps->RegBlueGainOutDirect,
1362							  ps->Asic96Reg.RD_BlueGainOut );
1363
1364		    /* FillGainInitialRestRegister (); */
1365		    IODataToRegister( ps, ps->RegModelControl2,
1366							  ps->Asic96Reg.u26.RD_ModelControl2 );
1367			IODataToRegister( ps, ps->RegThresholdGapControl,
1368			 			      ps->AsicReg.RD_ThresholdGapCtrl );
1369			IODataToRegister( ps, ps->RegLedControl,
1370							  ps->Asic96Reg.RD_LedControl );
1371
1372		    IODataToRegister( ps, ps->RegShadingCorrectCtrl,
1373						      ps->Asic96Reg.RD_ShadingCorrectCtrl );
1374
1375			ps->CloseScanPath( ps );
1376
1377		    ps->Asic96Reg.RD_MotorControl = 0;
1378			IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );
1379
1380			ps->AsicReg.RD_ModeControl    = _ModeScan;
1381			ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
1382			ps->Asic96Reg.RD_MotorControl = (ps->IgnorePF |
1383										     ps->MotorOn | _MotorDirForward);
1384
1385			ps->AsicReg.RD_Origin       = 142;
1386			ps->AsicReg.RD_ModelControl = ps->Device.ModelCtrl | _ModelWhiteIs0;
1387            ps->AsicReg.RD_Dpi          = ps->PhysicalDpi;
1388			ps->AsicReg.RD_Pixels       = ps->BufferSizePerModel;
1389
1390			IOPutOnAllRegisters( ps );
1391
1392			/*---------------------------------------------------------------*/
1393
1394		    /* ReadOneScanLine (); */
1395		    dacP96ReadDataWithinOneSecond( ps, ps->OneScanLineLen, 11 );
1396
1397			/* AdjustGain () */
1398			/*	FindTheMaxGain (), AdjustGainOutData (); */
1399
1400		    pbReg[0] = &ps->Asic96Reg.RD_RedGainOut;
1401		    pbReg[1] = &ps->Asic96Reg.RD_GreenGainOut;
1402	    	pbReg[2] = &ps->Asic96Reg.RD_BlueGainOut;
1403
1404		    for (w = 0, p.pb = ps->pPrescan16; w < 3; w++) {
1405/* CHANGE: org was:	for (dw = 2560, b[w] = 0; dw; dw--, p.pb++) { */
1406				for (dw = (ps->OneScanLineLen/3), b[w] = 0; dw; dw--, p.pb++) {
1407
1408				    if (b[w] < *p.pb)
1409						b[w] = *p.pb;
1410				}
1411
1412				if (b[w] < _GAIN_LOW)
1413				    *(pbReg[w]) += a_bCorrectTimesTable[bCorrectTimes - 1];
1414				else
1415				    if (b[w] > _GAIN_P96_HIGH)
1416						*(pbReg[w]) -= a_bCorrectTimesTable[bCorrectTimes - 1];
1417		    }
1418		}
1419
1420    	/*===================================================================*/
1421
1422	    /* SonyFBK ()/ToshibaFBK ()====================================*/
1423		/*FillRGBDarkLevel0Table (); */
1424		memset( ps->pPrescan16, 0xff, ps->ShadingBankSize );
1425
1426		for( dw = 0, p.pb = ps->pPrescan16 + ps->ShadingBufferSize;
1427                                    		    dw <=255; dw++, p.pb++ ) {
1428		    *p.pb = (Byte) dw;
1429		}
1430
1431		dacP96FillShadingAndGammaTable( ps );
1432
1433		ps->PauseColorMotorRunStates( ps );
1434
1435		/* SetReadFBKRegister () */
1436		ps->Asic96Reg.RD_MotorControl = 0;
1437		IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );
1438
1439		ps->AsicReg.RD_ModeControl    = _ModeScan;
1440		ps->AsicReg.RD_ScanControl    = ps->bLampOn | _SCAN_BYTEMODE;
1441		ps->Asic96Reg.RD_MotorControl = ps->IgnorePF | ps->MotorOn |
1442								        _MotorDirForward;
1443
1444		ps->AsicReg.RD_Origin       = 22;
1445		ps->AsicReg.RD_ModelControl = ps->Device.ModelCtrl | _ModelWhiteIs0;
1446        ps->AsicReg.RD_Dpi          = ps->PhysicalDpi;
1447		ps->AsicReg.RD_Pixels       = ps->FBKScanLineLenBase;
1448
1449		IOPutOnAllRegisters( ps );
1450
1451		/* ReadFBKScanLine () */
1452		dacP96ReadDataWithinOneSecond( ps, ps->FBKScanLineLen,
1453													   ps->FBKScanLineBlks );
1454
1455	    /*===================================================================*/
1456		if ( ps->fSonyCCD ) {
1457
1458		    /* FillChannelDarkLevelControl (); */
1459		    for ( p.pb = ps->pPrescan16 + 32, w = 0, dw = 16;
1460				  dw; dw--, p.pb++) {
1461				  w += (UShort) *p.pb;
1462			}
1463
1464		    ps->Asic96Reg.RD_RedChDarkOff = (Byte)(w / 16);
1465
1466		    for ( p.pb = ps->pPrescan16 + 32 + ps->FBKScanLineLenBase, w = 0, dw = 16;
1467				  dw; dw--, p.pb++ ) {
1468				w += (UShort)*p.pb;
1469			}
1470
1471			ps->Asic96Reg.RD_GreenChDarkOff = (Byte)(w / 16);
1472
1473	    	for ( p.pb = ps->pPrescan16 + 32 + ps->FBKScanLineLenBase * 2, w = 0, dw = 16;
1474				  dw; dw--,	p.pb++) {
1475				w += (UShort)*p.pb;
1476			}
1477
1478		    ps->Asic96Reg.RD_BlueChDarkOff = (Byte)(w / 16);
1479
1480		    dacP96FillChannelDarkOffset( ps );
1481
1482		} else {
1483
1484		    /* FillToshibaDarkLevelControl (); */
1485			dacP96GetEvenOddOffset( ps->pPrescan16 + 32, &wv );
1486		    ps->Asic96Reg.RD_RedChEvenOff = wv.b1st;
1487		    ps->Asic96Reg.RD_RedChOddOff  = wv.b2nd;
1488
1489			dacP96GetEvenOddOffset( ps->pPrescan16 + 32 + ps->FBKScanLineLenBase, &wv );
1490		    ps->Asic96Reg.RD_GreenChEvenOff = wv.b1st;
1491		    ps->Asic96Reg.RD_GreenChOddOff = wv.b2nd;
1492
1493			dacP96GetEvenOddOffset( ps->pPrescan16 + 32 + ps->FBKScanLineLenBase * 2, &wv );
1494			ps->Asic96Reg.RD_BlueChEvenOff = wv.b1st;
1495			ps->Asic96Reg.RD_BlueChOddOff  = wv.b2nd;
1496
1497			dacP96FillEvenOddControl( ps );
1498		}
1499
1500		/*	SetInitialGainRAM (); */
1501		dacP96Adjust10BitShading( ps );
1502
1503		return _TRUE;
1504    }
1505
1506    return _FALSE;
1507}
1508
1509/**
1510 */
1511static void dacP96001ToSetShadingAddress( pScanData ps, pUChar pData )
1512{
1513    ps->OpenScanPath( ps );
1514
1515    IODataToRegister( ps, ps->RegMemAccessControl,
1516											ps->Asic96Reg.RD_MemAccessControl);
1517
1518    ps->AsicReg.RD_ModeControl = _ModeProgram;
1519    IODataToRegister( ps, ps->RegModeControl, _ModeProgram );
1520
1521    ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
1522    IODataToRegister( ps, ps->RegMotorControl, ps->Asic96Reg.RD_MotorControl);
1523
1524    memset( ps->pScanBuffer1, 0, (64 + 8 + ps->Offset70));
1525  	memcpy( ps->pScanBuffer1 + 64 + 8 + ps->Offset70, pData,
1526    												_BUF_SIZE_BASE_CONST * 2 );
1527
1528    IOMoveDataToScanner( ps, ps->pScanBuffer1,
1529							_BUF_SIZE_BASE_CONST * 2 + 64 + 8 + ps->Offset70 );
1530
1531    ps->AsicReg.RD_ModeControl = _ModeScan;
1532    IODataToRegister( ps, ps->RegModeControl, _ModeScan );
1533
1534    ps->CloseScanPath( ps );
1535}
1536
1537/**
1538 */
1539static void dacP96001WriteBackToColorShadingRam( pScanData ps )
1540{
1541    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3a);
1542    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 );
1543
1544    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3e);
1545    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 + _BUF_SIZE_BASE_CONST*2);
1546
1547    ps->Asic96Reg.RD_MemAccessControl = (_MemBankSize4k96001 | 0x3c);
1548    dacP96001ToSetShadingAddress( ps, ps->pPrescan16 + _BUF_SIZE_BASE_CONST*4);
1549}
1550
1551/**
1552 */
1553static void dacP96001ModifyShadingColor( pByte pData, Byte bMul )
1554{
1555    UShort w;
1556	ULong  dw;
1557
1558    for ( dw = 0; dw < _BUF_SIZE_BASE_CONST * 2; dw++ ) {
1559
1560		w = (UShort)(Byte)(~pData[dw]) * bMul / 100U;
1561
1562		if (w >= 255U)
1563	    	pData[dw] = 0;
1564		else
1565		    pData[dw] = (Byte)~w;
1566    }
1567}
1568
1569/**
1570 */
1571static Byte dacP96001FBKReading( pScanData ps, Byte bValue,
1572								 Byte bReg, pByte pbSave, Bool bFBKModify )
1573{
1574    TimerDef timer;
1575    UShort	 w, wSum;
1576    Byte	 addrSeq[8] = { 0x40, 0x20, 0x10, 0x08, 4, 2, 1, 0 };
1577    Byte	 bTemp, bFBKTemp, bFBKIndex;
1578
1579    if( bFBKModify ) {
1580		bFBKIndex = 3;
1581		bFBKTemp = *pbSave;
1582    } else {
1583		bFBKTemp = 0x80;
1584		bFBKIndex = 0;
1585    }
1586
1587    while( _TRUE ) {
1588
1589		*pbSave = bFBKTemp;
1590		IOCmdRegisterToScanner( ps, bReg, bFBKTemp );
1591
1592		/* SetColorRunTable (BYTE) */
1593		memset( ps->a_nbNewAdrPointer, bValue, _SCANSTATE_BYTES );
1594		MotorSetConstantMove( ps, 0 );
1595
1596		/* SetReadFBK (pScanData) */
1597		ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
1598		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1599										ps->Asic96Reg.RD_MotorControl );
1600
1601		ps->AsicReg.RD_ModeControl  = _ModeScan;
1602		ps->AsicReg.RD_ScanControl  = _SCAN_BYTEMODE | ps->bLampOn;
1603		ps->AsicReg.RD_ModelControl =
1604					(_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0 );
1605
1606		ps->AsicReg.RD_Dpi    = 300;
1607		ps->AsicReg.RD_Origin = 22;
1608		ps->AsicReg.RD_Pixels = 1024;
1609		IOPutOnAllRegisters( ps );
1610
1611		ps->Asic96Reg.RD_MotorControl =
1612						  	   (ps->FullStep | ps->MotorOn | _MotorDirForward);
1613		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1614											   ps->Asic96Reg.RD_MotorControl );
1615
1616		MiscStartTimer( &timer, _SECOND );
1617		while((IODataRegisterFromScanner( ps, ps->RegFifoOffset) < 1) &&
1618													!MiscCheckTimer( &timer ));
1619
1620		IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );
1621		IOReadScannerImageData( ps, ps->pScanBuffer1, 64 );
1622
1623		for( w = 26, wSum = 0; w < 42; w++)
1624		    wSum += ps->pScanBuffer1[w];
1625
1626		wSum >>= 4;
1627		bTemp = addrSeq[bFBKIndex++];
1628
1629		if( bTemp ) {
1630		    if( wSum < 0xfe )
1631				bFBKTemp += bTemp;
1632		    else
1633				bFBKTemp -= bTemp;
1634		} else {
1635		    return bFBKTemp;
1636		}
1637    }
1638}
1639
1640/**
1641 */
1642static Bool dacP96001WaitForShading( pScanData ps )
1643{
1644	Bool   bFBKModify;
1645    Byte   bRSave;
1646    Byte   bGSave;
1647    Byte   bBSave;
1648    ULong  dw;
1649    pULong pdw;
1650
1651	DBG( DBG_LOW, "dacP96001WaitForShading()\n" );
1652
1653    ps->AsicReg.RD_ScanControl |= ps->bLampOn;
1654    IOCmdRegisterToScanner(ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl);
1655
1656    if ( ps->GotoShadingPosition( ps )) {
1657
1658		_DODELAY( 250 );
1659
1660	    /* AdjustMostWideOffset70 (pScanData) -------------------------------*/
1661		/* FillABitGray (pScanData)*/
1662		memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
1663		ps->a_nbNewAdrPointer[8]  =
1664		ps->a_nbNewAdrPointer[24] = 0x30;
1665
1666		MotorSetConstantMove( ps, 32 );
1667
1668		/* SetMaxWideRegister (pScanData) */
1669		ps->AsicReg.RD_ModeControl = _ModeScan;
1670		ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE | ps->bLampOn;
1671
1672		ps->Asic96Reg.RD_MotorControl =
1673 							  (ps->MotorOn | ps->IgnorePF | _MotorDirForward);
1674		ps->AsicReg.RD_ModelControl =
1675					  (_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0);
1676
1677		ps->AsicReg.RD_Dpi    = 300;
1678		ps->AsicReg.RD_Origin = 64 + 8;
1679		ps->AsicReg.RD_Pixels = 2700;
1680		IOPutOnAllRegisters( ps );
1681
1682		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1683                                ps->Asic96Reg.RD_MotorControl );
1684
1685		/* ReadMaxWideLine */
1686		dacP96ReadDataWithinOneSecond( ps, 2700, 5 );
1687
1688	    /* AdjustOffset70Proc (pScanData)------------------------------------*/
1689		{
1690		    ULong dwSum, dw, dwLeft, dwCenter;
1691
1692		    /* AverageWideBank (pScanData) */
1693		    for( dwSum = 0, dw = 0; dw < 2700; dw++ )
1694				dwSum += (ULong)ps->pPrescan16[dw];
1695
1696			dwSum /= 2700UL;
1697
1698		    if( dwSum <= 0x80 ) {
1699
1700				memcpy( ps->pScanBuffer1, ps->pPrescan16, 140 );
1701				memcpy( ps->pScanBuffer1 + 140,
1702       						ps->pPrescan16 + _BUF_SIZE_BASE_CONST * 2, 140);
1703
1704				/* BlackOffsetCheck (pScanData) */
1705				for( dw = dwLeft = 0; dw < 140; dw++ ) {
1706				    if( ps->pScanBuffer1[dw] >= 0xe0 )
1707						dwLeft++;
1708				    else
1709						break;
1710				}
1711
1712				/* WhiteOffsetCheck (pScanData) */
1713				for( dw = 140, dwCenter = 0; dw < 280; dw++ ) {
1714				    if( ps->pScanBuffer1[dw] < 0xe0 )
1715						dwCenter++;
1716				    else
1717						break;
1718				}
1719
1720				if (dwLeft) {
1721				    ps->Offset70 = (dwLeft + dwCenter) / 2 + 14;
1722				} else {
1723				    if (dwCenter == 140)
1724						ps->Offset70 = 70;
1725		    		else
1726						ps->Offset70 = dwCenter / 2 + 2;
1727				}
1728	    	}
1729		}
1730
1731		memset( ps->pPrescan16, 0, ps->BufferSizePerModel * 3 );
1732		dacP96001WriteBackToColorShadingRam( ps );
1733
1734		/* SetFBK */
1735		if((IODataRegisterFromScanner(ps, ps->RegReadIOBufBus) & 0x0f) == 0x0f)
1736	    	bFBKModify = 0;
1737		else
1738		    bFBKModify = 1;
1739
1740		dacP96001FBKReading(ps, 0x10, ps->RegRedDCAdjust,  &bRSave,bFBKModify);
1741		dacP96001FBKReading(ps, 0x30, ps->RegGreenDCAdjust,&bGSave,bFBKModify);
1742		dacP96001FBKReading(ps, 0x20, ps->RegBlueDCAdjust, &bBSave,bFBKModify);
1743
1744		ps->OpenScanPath( ps );
1745		IODataToRegister( ps, ps->RegRedDCAdjust,   (Byte)(bRSave + 2));
1746		IODataToRegister( ps, ps->RegGreenDCAdjust, (Byte)(bGSave + 2));
1747		IODataToRegister( ps, ps->RegBlueDCAdjust,  bBSave);
1748		ps->CloseScanPath( ps );
1749
1750		/* Turn off and then turn on motor */
1751		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1752				         (Byte)(ps->Asic96Reg.RD_MotorControl & ~ps->MotorOn));
1753		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1754											   ps->Asic96Reg.RD_MotorControl );
1755
1756		/* FillABitColor (pScanData) */
1757		pdw = (pULong)ps->a_nbNewAdrPointer;
1758		for( dw = 0; dw < 4; dw++) {
1759		    *pdw++ = 0x40;
1760		    *pdw++ = 0x2030140;
1761		}
1762
1763		IOSetToMotorRegister( ps );
1764
1765		/* SetShadingRegister (pScanData) */
1766		ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
1767		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1768												ps->Asic96Reg.RD_MotorControl );
1769		ps->AsicReg.RD_ModeControl    = _ModeScan;
1770		ps->AsicReg.RD_LineControl    = ps->TimePerLine;
1771		ps->AsicReg.RD_ScanControl    = _SCAN_BYTEMODE | ps->bLampOn;
1772		ps->Asic96Reg.RD_MotorControl = ps->FullStep | _MotorDirForward;
1773
1774		ps->AsicReg.RD_ModelControl =
1775						(_ModelMemSize32k96001 | _ModelDpi300 | _ModelWhiteIs0);
1776		ps->AsicReg.RD_Dpi    = 150;
1777		ps->AsicReg.RD_Origin = (UShort)(64 + 8 + ps->Offset70);
1778		ps->AsicReg.RD_Pixels = ps->BufferSizeBase;
1779		IOPutOnAllRegisters( ps );
1780
1781		IOCmdRegisterToScanner( ps, ps->RegMotorControl,
1782					    (Byte)(ps->MotorOn | ps->IgnorePF | _MotorDirForward));
1783
1784		dacP96ReadColorShadingLine( ps );
1785
1786		/* ModifyShadingColor (pScanData) */
1787		dacP96001ModifyShadingColor( ps->pPrescan16, 103 );
1788		dacP96001ModifyShadingColor( ps->pPrescan16 +
1789											_BUF_SIZE_BASE_CONST * 2 * 2, 97);
1790		dacP96001WriteBackToColorShadingRam( ps );
1791		return _TRUE;
1792    }
1793    return _FALSE;
1794}
1795
1796/**
1797 */
1798static void dacP98003GainOffsetToDAC( pScanData ps, Byte ch, Byte reg, Byte d )
1799{
1800    if( ps->Device.bDACType == _DA_SAMSUNG8531 ) {
1801
1802    	IODataToRegister( ps, ps->RegADCAddress, 0 );
1803    	IODataToRegister( ps, ps->RegADCData, ch );
1804    	IODataToRegister( ps, ps->RegADCSerialOutStr, ch);
1805    }
1806
1807    IODataToRegister( ps, ps->RegADCAddress, reg );
1808    IODataToRegister( ps, ps->RegADCData, d );
1809    IODataToRegister( ps, ps->RegADCSerialOutStr, d );
1810}
1811
1812/**
1813 */
1814static void dacP98003AdjustRGBGain( pScanData ps )
1815{
1816    ULong i;
1817    Byte  bHi[3];
1818
1819    DBG( DBG_LOW, "dacP98003AdjustRGBGain()\n" );
1820
1821    ps->Shade.Gain.Colors.Red   =
1822    ps->Shade.Gain.Colors.Green =
1823    ps->Shade.Gain.Colors.Blue  =  ps->Shade.bUniGain;
1824
1825    ps->Shade.Hilight.Colors.Red   =
1826    ps->Shade.Hilight.Colors.Green =
1827    ps->Shade.Hilight.Colors.Blue  = 0;
1828
1829    ps->Shade.bGainHigh = _GAIN_P98003_HIGH;
1830    ps->Shade.bGainLow  = _GAIN_P98003_LOW;
1831
1832    ps->Shade.fStop = _FALSE;
1833
1834    for( i = 10; i-- && !ps->Shade.fStop; ) {
1835
1836        ps->Shade.fStop = _TRUE;
1837
1838        /* SetRGBGainRegister () */
1839        IODataToRegister( ps, ps->RegModeControl, _ModeIdle );
1840
1841        ps->AsicReg.RD_ScanControl = _SCAN_BYTEMODE;
1842        IOSelectLampSource( ps );
1843    	IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
1844
1845        DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );
1846
1847        ps->AsicReg.RD_ModeControl   = _ModeScan;
1848        ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
1849        ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;
1850
1851    	if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
1852	        ps->AsicReg.RD_Origin = (UShort)ps->Device.DataOriginX >> 1;
1853    	else
1854	        ps->AsicReg.RD_Origin = (UShort)ps->Device.DataOriginX;
1855
1856        ps->AsicReg.RD_Dpi    = 300;
1857        ps->AsicReg.RD_Pixels = 2560;
1858
1859    	/* PauseColorMotorRunStates () */
1860    	memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
1861	    ps->a_nbNewAdrPointer[1] = 0x77;
1862
1863	    IOPutOnAllRegisters( ps );
1864
1865    	_DODELAY( 70 );
1866
1867        /* read one shading line and work on it */
1868	    if( IOReadOneShadingLine( ps, (pUChar)ps->Bufs.b1.pShadingRam, 2560)) {
1869
1870        	if ( ps->DataInf.wPhyDataType <= COLOR_256GRAY ) {
1871
1872        		bHi[1] = DacP98003SumGains(
1873                                 (pUChar)ps->Bufs.b1.pShadingRam + 2560, 2560);
1874		        if( bHi[1] )
1875        		    DacP98003AdjustGain( ps, _CHANNEL_GREEN, bHi[1] );
1876		        else {
1877        		    ps->Shade.fStop = _FALSE;
1878		        }
1879    	    } else {
1880        		bHi[0] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam, 2560);
1881		        bHi[1] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam + 2560, 2560);
1882        		bHi[2] = DacP98003SumGains((pUChar)ps->Bufs.b1.pShadingRam + 5120, 2560);
1883
1884		        if (!bHi[0] || !bHi[1] || !bHi[2] ) {
1885        		    ps->Shade.fStop = _FALSE;
1886		        } else {
1887        		    DacP98003AdjustGain( ps, _CHANNEL_RED,   bHi[0] );
1888        		    DacP98003AdjustGain( ps, _CHANNEL_GREEN, bHi[1] );
1889        		    DacP98003AdjustGain( ps, _CHANNEL_BLUE,  bHi[2] );
1890		        }
1891    	    }
1892	    } else
1893    	    ps->Shade.fStop = _FALSE;
1894    }
1895
1896#ifdef DEBUG
1897    if( !ps->Shade.fStop )
1898        DBG( DBG_LOW, "dacP98003AdjustRGBGain() - all loops done!!!\n" );
1899#endif
1900
1901    DacP98003FillToDAC( ps, &ps->Device.RegDACGain, &ps->Shade.Gain );
1902}
1903
1904/**
1905 */
1906static UShort dacP98003SumDarks( pScanData ps, pUShort data )
1907{
1908    UShort i, loop;
1909
1910    if( ps->Device.bCCDID == _CCD_3799 ) {
1911    	if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
1912    	    data += 0x18;
1913	    else
1914	        data += 0x30;
1915    } else {
1916    	if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
1917	        data += 0x18;
1918    	else
1919	        data += 0x20;
1920    }
1921
1922    for( i = 0, loop = 16; loop--; data++ )
1923    	i += *data;
1924    i >>= 4;
1925
1926    return i;
1927}
1928
1929/**
1930 */
1931static void dacP98003AdjustShadingWaveform( pScanData ps )
1932{
1933    Byte	       b;
1934    UShort         count, wR, wG, wB, tmp;
1935    DataType       var;
1936    DataPointer    pvar, psum;
1937    RBGPtrDef      cp;
1938    pRGBUShortDef  pRGB, pwsum;
1939
1940    DBG( DBG_LOW, "dacP98003AdjustShadingWaveForm()\n" );
1941
1942    memset( &cp, 0, sizeof(RBGPtrDef));
1943    memset( ps->Bufs.b2.pSumBuf, 0, (5400 * 3 * 2));
1944
1945    /* SetAdjustShadingRegister () */
1946    IODataToRegister( ps, ps->RegModeControl, _ModeIdle );
1947
1948    ps->AsicReg.RD_LineControl    = _LOBYTE(ps->Shade.wExposure);
1949    ps->AsicReg.RD_ExtLineControl = _HIBYTE(ps->Shade.wExposure);
1950    IODataToRegister( ps, ps->RegExtendedLineControl,
1951                      ps->AsicReg.RD_ExtLineControl );
1952    IODataToRegister( ps, ps->RegLineControl, ps->AsicReg.RD_LineControl );
1953
1954    ps->AsicReg.RD_XStepTime    = _LOBYTE(ps->Shade.wExposure);
1955    ps->AsicReg.RD_ExtXStepTime = _HIBYTE(ps->Shade.wExposure);
1956    IODataToRegister( ps, ps->RegExtendedXStep, ps->AsicReg.RD_ExtXStepTime );
1957    IODataToRegister( ps, ps->RegXStepTime, ps->AsicReg.RD_XStepTime );
1958
1959    ps->AsicReg.RD_ModeControl   = _ModeScan;
1960    ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
1961    ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;
1962
1963   	if( ps->Shade.bIntermediate & _ScanMode_AverageOut ) {
1964
1965    	ps->AsicReg.RD_Dpi     = 300;
1966    	ps->AsicReg.RD_Pixels  = 2700;
1967    	ps->Shade.shadingBytes = 2700 * 2;
1968    } else {
1969    	ps->AsicReg.RD_Dpi     = 600;
1970    	ps->AsicReg.RD_Pixels  = 5400;
1971    	ps->Shade.shadingBytes = 5400 * 2;
1972    }
1973    ps->AsicReg.RD_Origin = _SHADING_BEGINX;
1974
1975    for( pvar.pdw = (pULong)ps->a_nbNewAdrPointer,
1976         var.dwValue = _SCANSTATE_BYTES >> 2; var.dwValue--; pvar.pdw++) {
1977    	*pvar.pdw = 0x00f00080;
1978    }
1979
1980    ps->Scan.fRefreshState = _FALSE;
1981    IOPutOnAllRegisters( ps );
1982    _DODELAY( 55 );
1983
1984    /* SetupHilightShadow () */
1985    if( ps->Shade.pHilight ) {
1986
1987        memset( ps->Shade.pHilight, 0,
1988    	        ps->Shade.shadingBytes * ps->Shade.skipHilight * 3 );
1989
1990        memset((pUChar)ps->Shade.pHilight +
1991                ps->Shade.shadingBytes * ps->Shade.skipHilight * 3, 0xff,
1992			    ps->Shade.shadingBytes * ps->Shade.skipShadow * 3 );
1993    }
1994
1995
1996    for( count = 32; count--;) {
1997
1998        IOReadOneShadingLine( ps,
1999                             ((pUChar)ps->Bufs.b1.pShadingRam)+_SHADING_BEGINX,
2000	                                                     ps->Shade.shadingBytes );
2001
2002	    /* SaveHilightShadow() */
2003    	if( ps->Shade.pHilight ) {
2004
2005           	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2006
2007        		cp.red.usp   = ps->Bufs.b1.pShadingRam + _SHADING_BEGINX;
2008		        cp.green.usp = cp.red.usp   + ps->AsicReg.RD_Pixels;
2009        		cp.blue.usp  = cp.green.usp + ps->AsicReg.RD_Pixels;
2010		        pvar.pusrgb = (pRGBUShortDef)ps->Shade.pHilight +
2011                                                         _SHADING_BEGINX;
2012
2013        		for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2014                                                              var.dwValue--;) {
2015        		    pRGB = pvar.pusrgb++;
2016		            wR = *cp.red.usp;
2017        		    wG = *cp.green.usp;
2018		            wB = *cp.blue.usp;
2019
2020        		    for( b = ps->Shade.skipHilight; b--;
2021                                               pRGB += ps->AsicReg.RD_Pixels) {
2022
2023            			if( wR > pRGB->Red ) {
2024            			    tmp = wR;
2025			                wR  = pRGB->Red;
2026            			    pRGB->Red = tmp;
2027			            }
2028            			if( wG > pRGB->Green ) {
2029            			    tmp = wG;
2030			                wG  = pRGB->Green;
2031            			    pRGB->Green = tmp;
2032			            }
2033            			if( wB > pRGB->Blue ) {
2034            			    tmp = wB;
2035			                wB  = pRGB->Blue;
2036            			    pRGB->Blue = tmp;
2037			            }
2038        		    }
2039
2040        		    wR = *cp.red.usp++;
2041		            wG = *cp.green.usp++;
2042        		    wB = *cp.blue.usp++;
2043		            for(b = ps->Shade.skipShadow; b--;
2044                                               pRGB += ps->AsicReg.RD_Pixels) {
2045
2046            			if (wR < pRGB->Red) {
2047            			    tmp = wR;
2048			                wR  = pRGB->Red;
2049            			    pRGB->Red = tmp;
2050			            }
2051            			if (wG < pRGB->Green) {
2052            			    tmp = wG;
2053			                wG  = pRGB->Green;
2054            			    pRGB->Green = tmp;
2055			            }
2056            			if (wB < pRGB->Blue) {
2057            			    tmp = wB;
2058			                wB  = pRGB->Blue;
2059            			    pRGB->Blue = tmp;
2060			            }
2061        		    }
2062    	        }
2063
2064    	    } else {
2065
2066        		cp.green.usp = ps->Bufs.b1.pShadingRam +
2067                               ps->AsicReg.RD_Pixels + _SHADING_BEGINX;
2068        		cp.blue.usp  = (pUShort) ps->Shade.pHilight + _SHADING_BEGINX;
2069
2070        		for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2071                                                              var.dwValue--;) {
2072        		    cp.red.usp = cp.blue.usp++;
2073		            wG = *cp.green.usp;
2074        		    for( b = ps->Shade.skipHilight; b--;
2075	                                    cp.red.usp += ps->AsicReg.RD_Pixels) {
2076            			if( wG > *cp.red.usp ) {
2077            			    tmp = wG;
2078			                wG  = *cp.red.usp;
2079            			    *cp.red.usp = tmp;
2080			            }
2081        		    }
2082		            wG = *cp.green.usp++;
2083        		    for (b = ps->Shade.skipShadow; b--;
2084                  		                cp.red.usp += ps->AsicReg.RD_Pixels) {
2085            			if( wG < *cp.red.usp ) {
2086            			    tmp = wG;
2087			                wG  = *cp.red.usp;
2088            			    *cp.red.usp = tmp;
2089			            }
2090        		    }
2091		        }
2092    	    }
2093	    }
2094
2095    	/* AddToSumBuffer() */
2096       	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2097
2098    	    cp.red.usp   = ps->Bufs.b1.pShadingRam + _SHADING_BEGINX;
2099	        cp.green.usp = cp.red.usp   + ps->AsicReg.RD_Pixels;
2100	        cp.blue.usp  = cp.green.usp + ps->AsicReg.RD_Pixels;
2101
2102    	    pvar.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2103
2104	        for( var.dwValue = (ULong)ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2105     	         var.dwValue--;
2106                 pvar.pulrgb++, cp.red.usp++, cp.green.usp++, cp.blue.usp++) {
2107        		pvar.pulrgb->Red   += (ULong)*cp.red.usp;
2108		        pvar.pulrgb->Green += (ULong)*cp.green.usp;
2109        		pvar.pulrgb->Blue  += (ULong)*cp.blue.usp;
2110	        }
2111
2112    	} else {
2113
2114    	    cp.green.usp = ps->Bufs.b1.pShadingRam + ps->AsicReg.RD_Pixels +
2115                                                               _SHADING_BEGINX;
2116	        pvar.pdw  = (pULong)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2117	        for(var.dwValue = (ULong)ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2118                            	    var.dwValue--; pvar.pdw++, cp.green.usp++) {
2119		        *pvar.pdw += (ULong)*cp.green.usp;
2120    	    }
2121        }
2122
2123   	    if( IOReadFifoLength( ps ) < ps->AsicReg.RD_Pixels )
2124           IORegisterToScanner( ps, ps->RegRefreshScanState );
2125    }
2126
2127    /* AverageAfterSubHilightShadow() */
2128    if( ps->Shade.pHilight ) {
2129
2130        if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2131
2132      	    psum.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2133	        pwsum       = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2134	        pvar.pusrgb = (pRGBUShortDef)ps->Shade.pHilight + _SHADING_BEGINX;
2135
2136      	    for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2137                                                              var.dwValue--;) {
2138           		pRGB = pvar.pusrgb++;
2139
2140	            for( b = ps->Shade.skipHilight + ps->Shade.skipShadow;
2141                                        b--; pRGB += ps->AsicReg.RD_Pixels ) {
2142
2143           		    psum.pulrgb->Red   -= (ULong)pRGB->Red;
2144    	            psum.pulrgb->Green -= (ULong)pRGB->Green;
2145           		    psum.pulrgb->Blue  -= (ULong)pRGB->Blue;
2146	            }
2147
2148           		pwsum->Red   = (UShort)(psum.pulrgb->Red   / ps->Shade.dwDiv);
2149    	        pwsum->Green = (UShort)(psum.pulrgb->Green / ps->Shade.dwDiv);
2150           		pwsum->Blue  = (UShort)(psum.pulrgb->Blue  / ps->Shade.dwDiv);
2151       	    	psum.pulrgb++;
2152	            pwsum++;
2153   	        }
2154        } else {
2155       	    cp.green.ulp = (pULong)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2156            cp.blue.usp  = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2157   	        pvar.pw      = (pUShort)ps->Shade.pHilight  + _SHADING_BEGINX;
2158
2159       	    for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2160                                                              var.dwValue--;) {
2161           		cp.red.usp = pvar.pw++;
2162
2163    	        for( b = ps->Shade.skipHilight + ps->Shade.skipShadow;
2164                                     b--; cp.red.usp += ps->AsicReg.RD_Pixels )
2165   		            *cp.green.ulp -= *cp.red.usp;
2166
2167           		*cp.blue.usp = (UShort)(*cp.green.ulp / ps->Shade.dwDiv);
2168           		cp.blue.usp++;
2169	            cp.green.ulp++;
2170       	    }
2171        }
2172    } else {
2173       	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2174
2175   	        psum.pulrgb = (pRGBULongDef)ps->Bufs.b2.pSumBuf  + _SHADING_BEGINX;
2176            pwsum       = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2177
2178   	        for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2179                                                              var.dwValue--;) {
2180           		pwsum->Red   = (UShort)(psum.pulrgb->Red   >> 5);
2181    	        pwsum->Green = (UShort)(psum.pulrgb->Green >> 5);
2182           		pwsum->Blue  = (UShort)(psum.pulrgb->Blue  >> 5);
2183	            psum.pulrgb++;
2184       		    pwsum++;
2185       	    }
2186        } else {
2187   	        cp.green.ulp = (pULong)ps->Bufs.b2.pSumBuf  + _SHADING_BEGINX;
2188            cp.blue.usp  = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2189
2190   	        for (var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2191                                                              var.dwValue--;) {
2192           		*cp.blue.usp = (UShort)(*cp.green.ulp >> 5);
2193           		cp.blue.usp++;
2194       	    	cp.green.ulp++;
2195       	    }
2196        }
2197    }
2198
2199    /* Process negative & transparency here */
2200    if( ps->DataInf.dwScanFlag & SCANDEF_TPA )
2201   	    TPAP98003FindCenterPointer( ps );
2202
2203    if( ps->DataInf.dwScanFlag & SCANDEF_Negative )
2204		TPAP98003Reshading( ps );
2205
2206    pRGB = (pRGBUShortDef)&ps->Shade.pCcdDac->GainResize;
2207
2208   	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2209
2210        	pwsum = (pRGBUShortDef)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2211
2212       	    for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2213                                                            var.dwValue--;) {
2214
2215  	        if ((short)(pwsum->Red -= ps->Shade.DarkOffset.Colors.Red) > 0) {
2216       	    	pwsum->Red = pwsum->Red * pRGB->Red / 100U;
2217	            if( pwsum->Red > 0xfff )
2218       		        pwsum->Red = 0xfff;
2219       	    } else
2220               	pwsum->Red = 0;
2221
2222       	    if((short)(pwsum->Green -= ps->Shade.DarkOffset.Colors.Green) > 0) {
2223               	pwsum->Green = pwsum->Green * pRGB->Green / 100U;
2224           	    if( pwsum->Green > 0xfff )
2225               	    pwsum->Green = 0xfff;
2226           	} else
2227               	pwsum->Green = 0;
2228
2229       	    if ((short)(pwsum->Blue -= ps->Shade.DarkOffset.Colors.Blue) > 0) {
2230           	    pwsum->Blue = pwsum->Blue * pRGB->Blue / 100U;
2231               	if( pwsum->Blue > 0xfff )
2232    	            pwsum->Blue = 0xfff;
2233           	} else
2234               	pwsum->Blue = 0;
2235
2236           	wR = (UShort)(pwsum->Red >> 4);
2237         	pwsum->Red <<= 12;
2238   	        pwsum->Red |= wR;
2239            wR = (UShort)(pwsum->Green >> 4);
2240       	    pwsum->Green <<= 12;
2241   	        pwsum->Green |= wR;
2242       	    wR = (UShort)(pwsum->Blue>> 4);
2243       	    pwsum->Blue <<= 12;
2244   	        pwsum->Blue |= wR;
2245       	    pwsum++;
2246       	}
2247   } else {
2248
2249       	cp.green.usp = (pUShort)ps->Bufs.b2.pSumBuf + _SHADING_BEGINX;
2250
2251   	    for( var.dwValue = ps->AsicReg.RD_Pixels - _SHADING_BEGINX;
2252                                                            var.dwValue--;) {
2253
2254   	        if((short)(*cp.green.usp -= ps->Shade.DarkOffset.Colors.Green) > 0) {
2255
2256           		*cp.green.usp = *cp.green.usp * pRGB->Green / 100U;
2257           		if( *cp.green.usp > 0xfff )
2258           		    *cp.green.usp = 0xfff;
2259            } else
2260           		*cp.green.usp = 0;
2261
2262       	    wR = (UShort)(*cp.green.usp >> 4);
2263   	        *cp.green.usp <<= 12;
2264       	    *cp.green.usp |= wR;
2265
2266       	    cp.green.usp++;
2267        }
2268    }
2269
2270    /* DownloadShadingAndSetDark() */
2271    dacP98DownloadShadingTable( ps, ps->Bufs.b2.pSumBuf, (5400 * 3 * 2));
2272}
2273
2274/**
2275 */
2276static void dacP98003AdjustDark( pScanData ps )
2277{
2278    ULong  i;
2279    UShort wDarks[3];
2280
2281    DBG( DBG_LOW, "dacP98003AdjustDark()\n" );
2282
2283    ps->Shade.DarkDAC.Colors = ps->Shade.pCcdDac->DarkDAC.Colors;
2284    ps->Shade.fStop = _FALSE;
2285
2286    for( i = 16; i-- && !ps->Shade.fStop;) {
2287
2288    	ps->Shade.fStop = _TRUE;
2289
2290    	/* FillDarkToDAC() */
2291        DacP98003FillToDAC( ps, &ps->Device.RegDACOffset, &ps->Shade.DarkDAC );
2292
2293        IODataToRegister( ps, ps->RegModeControl, _ModeIdle );
2294
2295        ps->AsicReg.RD_ScanControl = (_SCAN_12BITMODE + _SCAN_1ST_AVERAGE);
2296        IOSelectLampSource( ps );
2297    	IODataToRegister( ps, ps->RegScanControl, ps->AsicReg.RD_ScanControl );
2298
2299        ps->AsicReg.RD_StepControl   = _MOTOR0_SCANSTATE;
2300        ps->AsicReg.RD_Motor0Control = _FORWARD_MOTOR;
2301
2302        ps->AsicReg.RD_Origin = _SHADING_BEGINX;
2303        ps->AsicReg.RD_Pixels = 512;
2304
2305    	if( ps->Shade.bIntermediate & _ScanMode_AverageOut )
2306	        ps->AsicReg.RD_Dpi = 300;
2307    	else
2308	        ps->AsicReg.RD_Dpi = 600;
2309
2310
2311    	/* PauseColorMotorRunStates () */
2312    	memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
2313	    ps->a_nbNewAdrPointer[1] = 0x77;
2314
2315	    IOPutOnAllRegisters( ps );
2316    	_DODELAY( 70 );
2317
2318        /* read one shading line and work on it */
2319	    if( IOReadOneShadingLine(ps, (pUChar)ps->Bufs.b1.pShadingRam, 512*2)) {
2320
2321        	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2322
2323            	wDarks[0] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam );
2324                wDarks[1] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
2325                                               ps->AsicReg.RD_Pixels );
2326		        wDarks[2] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
2327                                               ps->AsicReg.RD_Pixels * 2UL);
2328
2329                if( !wDarks[0] || !wDarks[1] || !wDarks[2] ) {
2330		            ps->Shade.fStop = _FALSE;
2331		        } else {
2332		            ps->Shade.DarkOffset.wColors[0] = wDarks[0];
2333		            ps->Shade.DarkOffset.wColors[1] = wDarks[1];
2334		            ps->Shade.DarkOffset.wColors[2] = wDarks[2];
2335		            (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
2336                                               _CHANNEL_RED, wDarks[0] );
2337		            (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
2338                                               _CHANNEL_GREEN, wDarks[1] );
2339        		    (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
2340                                               _CHANNEL_BLUE, wDarks[2] );
2341	        	}
2342	        } else {
2343        		wDarks[1] = dacP98003SumDarks( ps, ps->Bufs.b1.pShadingRam +
2344                                               ps->AsicReg.RD_Pixels );
2345        		if (!wDarks[1] )
2346        		    ps->Shade.fStop = _FALSE;
2347        		else {
2348        		    ps->Shade.DarkOffset.wColors[1] = wDarks[1];
2349		            (*(ps->Device).fnDACDark)( ps, ps->Shade.pCcdDac,
2350                                               _CHANNEL_GREEN, wDarks[1] );
2351        		}
2352	        }
2353    	} else
2354            ps->Shade.fStop = _FALSE;
2355    }
2356
2357    /* CalculateDarkDependOnCCD() */
2358   	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2359    	(*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_RED   );
2360    	(*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_GREEN );
2361    	(*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_BLUE  );
2362    } else
2363    	(*(ps->Device).fnDarkOffset)( ps, ps->Shade.pCcdDac, _CHANNEL_GREEN );
2364}
2365
2366/**
2367 */
2368static Bool dacP98003WaitForShading( pScanData ps )
2369{
2370    ULong i, tmp;
2371    Byte  bScanControl;
2372
2373	DBG( DBG_LOW, "dacP98003WaitForShading()\n" );
2374
2375	/*
2376	 * before getting the shading data, (re)init the ASIC
2377	 */
2378	ps->ReInitAsic( ps, _TRUE );
2379
2380    ps->Shade.DarkOffset.Colors.Red   = 0;
2381    ps->Shade.DarkOffset.Colors.Green = 0;
2382    ps->Shade.DarkOffset.Colors.Blue  = 0;
2383
2384    IORegisterToScanner( ps, ps->RegResetMTSC );
2385
2386    IODataToRegister( ps, ps->RegModelControl, ps->AsicReg.RD_ModelControl);
2387    IODataToRegister( ps, ps->RegMotorDriverType,
2388                                            ps->AsicReg.RD_MotorDriverType );
2389    IODataToRegister( ps, ps->RegScanControl1,
2390                                        (_SCANSTOPONBUFFULL| _MFRC_BY_XSTEP));
2391    ps->GotoShadingPosition( ps );
2392
2393    bScanControl = ps->AsicReg.RD_ScanControl;
2394
2395    /* SetShadingMapForGainDark */
2396    memset( ps->Bufs.b2.pSumBuf, 0xff, (5400 * 3 * 2));
2397
2398    /* DownloadShadingAndSetDark() */
2399    dacP98DownloadShadingTable( ps, ps->Bufs.b2.pSumBuf, (5400 * 3 * 2));
2400
2401    for( i = 0, tmp = 0; i < 1024; tmp += 0x01010101, i += 4 ) {
2402    	ps->Bufs.b1.Buf.pdw[i]   =
2403    	ps->Bufs.b1.Buf.pdw[i+1] =
2404    	ps->Bufs.b1.Buf.pdw[i+2] =
2405    	ps->Bufs.b1.Buf.pdw[i+3] = tmp;
2406    }
2407
2408    memcpy( ps->Bufs.b1.pShadingMap + 4096, ps->Bufs.b1.pShadingMap, 4096 );
2409    memcpy( ps->Bufs.b1.pShadingMap + 8192, ps->Bufs.b1.pShadingMap, 4096 );
2410    dacP98DownloadMapTable( ps, ps->Bufs.b1.pShadingMap );
2411
2412    DBG( DBG_LOW, "wExposure = %u\n", ps->Shade.wExposure);
2413    DBG( DBG_LOW, "wXStep    = %u\n", ps->Shade.wXStep);
2414
2415    ps->AsicReg.RD_LineControl    = (_LOBYTE(ps->Shade.wExposure));
2416    ps->AsicReg.RD_ExtLineControl = (_HIBYTE(ps->Shade.wExposure));
2417    IODataToRegister(ps, ps->RegExtendedLineControl,
2418                                            ps->AsicReg.RD_ExtLineControl );
2419    IODataToRegister(ps, ps->RegLineControl, ps->AsicReg.RD_LineControl );
2420
2421    dacP98003AdjustRGBGain( ps );
2422    dacP98003AdjustDark( ps );
2423    dacP98003AdjustShadingWaveform( ps );
2424
2425    ps->AsicReg.RD_ScanControl = bScanControl;
2426
2427	/* here we have to download the table in any case...*/
2428	dacP98DownloadMapTable( ps, ps->a_bMapTable );
2429
2430    MotorP98003BackToHomeSensor( ps );
2431
2432    return _TRUE;
2433}
2434
2435/************************ exported functions *********************************/
2436
2437/**
2438 */
2439_LOC int DacInitialize( pScanData ps )
2440{
2441	DBG( DBG_HIGH, "DacInitialize()\n" );
2442
2443	if( NULL == ps )
2444		return _E_NULLPTR;
2445
2446	/*
2447	 * depending on the asic, we set some functions
2448	 */
2449	if( _ASIC_IS_98003 == ps->sCaps.AsicID ) {
2450
2451		ps->WaitForShading = dacP98003WaitForShading;
2452
2453    } else if( _ASIC_IS_98001 == ps->sCaps.AsicID ) {
2454
2455		ps->WaitForShading = dacP98WaitForShading;
2456
2457	} else if( _ASIC_IS_96003 == ps->sCaps.AsicID ) {
2458
2459		ps->WaitForShading = dacP96003WaitForShading;
2460
2461	} else if( _ASIC_IS_96001 == ps->sCaps.AsicID ) {
2462
2463		ps->WaitForShading = dacP96001WaitForShading;
2464
2465	} else {
2466
2467		DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" );
2468		return _E_NOSUPP;
2469	}
2470	return _OK;
2471}
2472
2473/** Fill out the R/G/B GainOut value
2474 */
2475_LOC void DacP98FillGainOutDirectPort( pScanData ps )
2476{
2477	ps->OpenScanPath( ps );
2478
2479    IODataRegisterToDAC( ps, 0x28, ps->bRedGainIndex   );
2480    IODataRegisterToDAC( ps, 0x29, ps->bGreenGainIndex );
2481    IODataRegisterToDAC( ps, 0x2a, ps->bBlueGainIndex  );
2482
2483	ps->CloseScanPath( ps );
2484}
2485
2486/**
2487 */
2488_LOC void DacP98FillShadingDarkToShadingRegister( pScanData ps )
2489{
2490	pUChar pValue;
2491	Byte   bReg;
2492
2493	DBG( DBG_LOW, "DacP98FillShadingDarkToShadingRegister()\n" );
2494
2495	ps->AsicReg.RD_RedDarkOff   = ps->Shade.DarkOffset.Colors.Red;
2496    ps->AsicReg.RD_GreenDarkOff = ps->Shade.DarkOffset.Colors.Green;
2497    ps->AsicReg.RD_BlueDarkOff  = ps->Shade.DarkOffset.Colors.Blue;
2498
2499    pValue = (pUChar)&ps->AsicReg.RD_RedDarkOff;
2500    for (bReg = ps->RegRedChDarkOffsetLow; bReg <= ps->RegBlueChDarkOffsetHigh;
2501	 	 bReg++, pValue++) {
2502
2503		IODataToRegister( ps, bReg, *pValue );
2504	}
2505}
2506
2507/**
2508 */
2509_LOC void DacP98AdjustDark( pScanData ps )
2510{
2511	Byte bCorrectTimes;		/* used to be a global var !*/
2512
2513	DBG( DBG_LOW, "DacP98AdjustDark()\n" );
2514
2515    ps->Shade.pCcdDac->DarkDAC.Colors.Red   = ps->bsPreRedDAC;
2516    ps->Shade.pCcdDac->DarkDAC.Colors.Green = ps->bsPreGreenDAC;
2517    ps->Shade.pCcdDac->DarkDAC.Colors.Blue  = ps->bsPreBlueDAC;
2518
2519    if( ps->DataInf.dwScanFlag & SCANDEF_Negative ) {
2520		bCorrectTimes = 6;
2521	} else {
2522		bCorrectTimes = 5;
2523	}
2524
2525/* CHANGE
2526** original code seems to be buggy : for (bCorrectTimes ; bCorrectTimes--;) {
2527*/
2528	for (;bCorrectTimes ; bCorrectTimes-- ) {
2529
2530    	ps->OpenScanPath( ps );
2531  		dacP98FillDarkDAC( ps );
2532		dacP98SetReadFBKRegister( ps );
2533       	ps->CloseScanPath( ps );
2534
2535    	IOPutOnAllRegisters( ps );
2536
2537		ps->PauseColorMotorRunStates( ps );		/* stop scan states */
2538
2539		IOReadOneShadingLine( ps, ps->pScanBuffer1, 512*2 );
2540
2541		dacP98FillChannelDarkLevelControl( ps );
2542
2543		if(dacP98CheckChannelDarkLevel( ps ))
2544	    	break;
2545    }
2546
2547	ps->Shade.DarkOffset.Colors.Red=
2548                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Red,
2549                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Red,
2550                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Red );
2551
2552    ps->Shade.DarkOffset.Colors.Green =
2553                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Green,
2554                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Green,
2555                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Green );
2556
2557    ps->Shade.DarkOffset.Colors.Blue  =
2558                dacP98CalDarkOff( ps, ps->Shade.DarkOffset.Colors.Blue,
2559                                  ps->Shade.pCcdDac->DarkCmpHi.Colors.Blue,
2560                                  ps->Shade.pCcdDac->DarkOffSub.Colors.Blue );
2561}
2562
2563/**
2564 */
2565_LOC void DacP96WriteBackToGammaShadingRAM( pScanData ps )
2566{
2567	/* ModifyGammaShadingOffset(ps) */
2568    ps->OpenScanPath( ps);
2569
2570    IODataToRegister( ps, ps->RegRedChShadingOffset,
2571					  ps->Asic96Reg.u28.RD_RedChShadingOff );
2572	IODataToRegister( ps, ps->RegGreenChShadingOffset,
2573	     (Byte)((ULong)ps->Asic96Reg.u29.RD_GreenChShadingOff * 96UL/100UL));
2574
2575	IODataToRegister( ps, ps->RegBlueChShadingOffset,
2576			    (Byte)((ULong)ps->Asic96Reg.RD_BlueChShadingOff * 91UL/100UL));
2577
2578    ps->CloseScanPath( ps );
2579
2580	dacP96WriteLinearGamma( ps, ps->pPrescan16, 256, ps->ShadingBankRed);
2581	dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize,
2582           										    256, ps->ShadingBankGreen);
2583	dacP96WriteLinearGamma( ps, ps->pPrescan16 + ps->ShadingBankSize * 2,
2584					  					            256, ps->ShadingBankBlue);
2585}
2586
2587/**
2588 */
2589_LOC void DacP98003FillToDAC( pScanData ps, pRGBByteDef regs, pColorByte data )
2590{
2591   	if ( ps->DataInf.wPhyDataType > COLOR_256GRAY ) {
2592
2593        dacP98003GainOffsetToDAC( ps, _DAC_RED, regs->Red, data->Colors.Red );
2594        dacP98003GainOffsetToDAC( ps, _DAC_GREENCOLOR,
2595                                            regs->Green, data->Colors.Green );
2596        dacP98003GainOffsetToDAC( ps, _DAC_BLUE,
2597                                            regs->Blue, data->Colors.Blue );
2598    } else {
2599        dacP98003GainOffsetToDAC( ps, _DAC_GREENMONO, regs->Green,
2600                                          			      data->Colors.Green );
2601    }
2602}
2603
2604/**
2605 */
2606_LOC void DacP98003AdjustGain( pScanData ps, ULong color, Byte hilight )
2607{
2608    if( hilight < ps->Shade.bGainLow ) {
2609
2610        if( ps->Shade.Hilight.bColors[color] < ps->Shade.bGainHigh ) {
2611
2612    	    ps->Shade.fStop = _FALSE;
2613    	    ps->Shade.Hilight.bColors[color] = hilight;
2614
2615    	    if( hilight <= (Byte)(ps->Shade.bGainLow - hilight))
2616        		ps->Shade.Gain.bColors[color] += ps->Shade.bGainDouble;
2617	        else
2618    		    ps->Shade.Gain.bColors[color]++;
2619	    }
2620    } else {
2621    	if( hilight > ps->Shade.bGainHigh ) {
2622    	    ps->Shade.fStop = _FALSE;
2623	        ps->Shade.Hilight.bColors[color] = hilight;
2624    	    ps->Shade.Gain.bColors[color]--;
2625    	} else
2626    	    ps->Shade.Hilight.bColors[color] = hilight;
2627	}
2628
2629    if( ps->Shade.Gain.bColors[color] > ps->Shade.bMaxGain ) {
2630        ps->Shade.Gain.bColors[color] = ps->Shade.bMaxGain;
2631    }
2632}
2633
2634/**
2635 */
2636_LOC Byte DacP98003SumGains( pUChar pb, ULong pixelsLine )
2637{
2638    Byte   bHilight, tmp;
2639    ULong  dwPixels, dwAve;
2640    UShort sum;
2641
2642    for( bHilight = 0, dwPixels = pixelsLine >> 4; dwPixels--; ) {
2643
2644    	for( sum = 0, dwAve = 16; dwAve--; pb++)
2645	        sum += (UShort)*pb;
2646
2647    	sum >>= 4;
2648        tmp = (Byte)sum;
2649
2650	    if( tmp > bHilight )
2651	        bHilight = tmp;
2652    }
2653    return bHilight;
2654}
2655
2656/* END PLUSTEK-PP_DAC.C .....................................................*/
2657