1 /* @file u12-shading.c -
2  * @brief all the shading functions
3  *
4  * based on sources acquired from Plustek Inc.
5  * Copyright (C) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de>
6  *
7  * History:
8  * - 0.01 - initial version
9  * - 0.02 -
10  * .
11  * <hr>
12  * This file is part of the SANE package.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
26  *
27  * As a special exception, the authors of SANE give permission for
28  * additional uses of the libraries contained in this release of SANE.
29  *
30  * The exception is that, if you link a SANE library with other files
31  * to produce an executable, this does not by itself cause the
32  * resulting executable to be covered by the GNU General Public
33  * License.  Your use of that executable is in no way restricted on
34  * account of linking the SANE library code into it.
35  *
36  * This exception does not, however, invalidate any other reasons why
37  * the executable file might be covered by the GNU General Public
38  * License.
39  *
40  * If you submit changes to SANE to the maintainers to be included in
41  * a subsequent release, you agree by submitting the changes that
42  * those changes may be distributed with this exception intact.
43  *
44  * If you write modifications of your own for SANE, it is your choice
45  * whether to permit this exception to apply to your modifications.
46  * If you do not wish that, delete this exception notice.
47  * <hr>
48  */
49 
50 #define _GAIN_HIGH 240 /* Volt. max. value */
51 #define _GAIN_LOW  220 /* Volt. min. value */
52 
53 #define _CHANNEL_RED   0
54 #define _CHANNEL_GREEN 1
55 #define _CHANNEL_BLUE  2
56 
57 /* for DAC programming */
58 #define _VALUE_CONFIG   0x51
59 #define _DAC_RED        (SANE_Byte)(_VALUE_CONFIG | 0x00)
60 #define _DAC_GREENCOLOR (SANE_Byte)(_VALUE_CONFIG | 0x04)
61 #define _DAC_GREENMONO  (SANE_Byte)(_VALUE_CONFIG | 0x06)
62 #define _DAC_BLUE       (SANE_Byte)(_VALUE_CONFIG | 0x08)
63 
64 
65 /* forward declarations ... */
66 static void u12tpa_Reshading( U12_Device * );
67 static void u12tpa_FindCenterPointer( U12_Device * );
68 
69 /**
70  */
71 static void
u12shading_DownloadShadingTable( U12_Device *dev, SANE_Byte *buf, u_long len )72 u12shading_DownloadShadingTable( U12_Device *dev, SANE_Byte *buf, u_long len )
73 {
74 	SANE_Byte *val, *rb;
75 	SANE_Byte  reg, regs[20];
76 	int        c;
77 
78 	DBG( _DBG_INFO, "u12shading_DownloadShadingTable()\n" );
79 
80 	u12io_DataToRegister( dev, REG_MODECONTROL, _ModeShadingMem );
81 	u12io_DataToRegister( dev, REG_MEMORYLO,  0 );
82 	u12io_DataToRegister( dev, REG_MEMORYHI, 0 );
83 
84 	/* set 12 bits output color */
85 	u12io_DataToRegister( dev, REG_SCANCONTROL,
86 	                  (SANE_Byte)(dev->regs.RD_ScanControl | _SCAN_12BITMODE));
87 
88 	u12io_MoveDataToScanner( dev, buf, len );
89 
90 	regs[0] = REG_MODECONTROL;
91 	regs[1] = _ModeScan;
92 
93 	/* FillShadingDarkToShadingRegister() */
94 	dev->regs.RD_RedDarkOff   = dev->shade.DarkOffset.Colors.Red;
95 	dev->regs.RD_GreenDarkOff = dev->shade.DarkOffset.Colors.Green;
96 	dev->regs.RD_BlueDarkOff  = dev->shade.DarkOffset.Colors.Blue;
97 
98 	val = (SANE_Byte*)&dev->regs.RD_RedDarkOff;
99 	rb  = &regs[2];
100 	c   = 1;
101 	for( reg = REG_REDCHDARKOFFSETLO;
102 	     reg <= REG_BLUECHDARKOFFSETHI; reg++, val++) {
103 
104 		*(rb++) = reg;
105 		*(rb++) = *val;
106 		c++;
107 	}
108 	u12io_DataToRegs( dev, regs, c );
109 }
110 
111 /**
112  */
u12shadingAdjustShadingWaveform( U12_Device *dev )113 static SANE_Status u12shadingAdjustShadingWaveform( U12_Device *dev )
114 {
115 	SANE_Byte     b;
116 	u_short       count, wR, wG, wB, tmp;
117 	DataType      var;
118 	DataPointer   pvar, psum;
119 	RBGPtrDef     cp;
120 	RGBUShortDef *pRGB, *pwsum;
121 	u_long        shadingBytes;
122 
123 	DBG( _DBG_INFO, "u12shading_AdjustShadingWaveForm()\n" );
124 
125 	memset( &cp, 0, sizeof(RBGPtrDef));
126 	memset( dev->bufs.b2.pSumBuf, 0, (5400 * 3 * 2));
127 
128 	u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
129 
130 	dev->regs.RD_LineControl    = _LOBYTE(dev->shade.wExposure);
131 	dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure);
132 	u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL,
133 	                      dev->regs.RD_ExtLineControl );
134 	u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl );
135 
136 	dev->regs.RD_XStepTime    = _LOBYTE(dev->shade.wExposure);
137 	dev->regs.RD_ExtXStepTime = _HIBYTE(dev->shade.wExposure);
138 	u12io_DataToRegister( dev, REG_EXTENDEDXSTEP, dev->regs.RD_ExtXStepTime );
139 	u12io_DataToRegister( dev, REG_XSTEPTIME, dev->regs.RD_XStepTime );
140 
141 	dev->regs.RD_ModeControl   = _ModeScan;
142 	dev->regs.RD_StepControl   = _MOTOR0_SCANSTATE;
143 	dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
144 
145 	if( dev->shade.intermediate & _ScanMode_AverageOut ) {
146 
147 		dev->regs.RD_Dpi    = 300;
148 		dev->regs.RD_Pixels = 2700;
149 		shadingBytes        = 2700 * 2;
150 	} else {
151 		dev->regs.RD_Dpi    = 600;
152 		dev->regs.RD_Pixels = 5400;
153 		shadingBytes        = 5400 * 2;
154 	}
155 	dev->regs.RD_Origin = _SHADING_BEGINX;
156 
157 	for( pvar.pdw = (u_long*)dev->scanStates,
158 		var.dwValue = _SCANSTATE_BYTES >> 2; var.dwValue--; pvar.pdw++) {
159 		*pvar.pdw = 0x00f00080;
160 	}
161 
162 	dev->scan.refreshState = SANE_FALSE;
163 	u12io_PutOnAllRegisters( dev );
164 /*	_DODELAY( 100 ); */
165 
166 	if( dev->shade.pHilight ) {
167 
168 		memset( dev->shade.pHilight, 0,
169 		        shadingBytes * dev->shade.skipHilight * 3 );
170 
171 		memset((SANE_Byte*)dev->shade.pHilight +
172 		        shadingBytes * dev->shade.skipHilight * 3, 0xff,
173 		        shadingBytes * dev->shade.skipShadow * 3 );
174 	}
175 
176 	for( count = 32; count--; ) {
177 
178 		if( u12io_IsEscPressed()) {
179 			DBG( _DBG_INFO, "* CANCEL detected!\n" );
180 			return SANE_STATUS_CANCELLED;
181 		}
182 
183 		u12io_ReadOneShadingLine( dev, ((SANE_Byte*)dev->bufs.b1.pShadingRam)+
184 		                           _SHADING_BEGINX, shadingBytes );
185 
186 		if( dev->shade.pHilight ) {
187 
188 			if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
189 
190 				cp.red.usp   = dev->bufs.b1.pShadingRam + _SHADING_BEGINX;
191 				cp.green.usp = cp.red.usp   + dev->regs.RD_Pixels;
192 				cp.blue.usp  = cp.green.usp + dev->regs.RD_Pixels;
193 				pvar.pusrgb  = (RGBUShortDef*)dev->shade.pHilight +
194 				                                              _SHADING_BEGINX;
195 
196 				for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
197 				                                              var.dwValue--;) {
198 					pRGB = pvar.pusrgb++;
199 					wR = *cp.red.usp;
200 					wG = *cp.green.usp;
201 					wB = *cp.blue.usp;
202 
203 					for( b = dev->shade.skipHilight; b--;
204 					                            pRGB += dev->regs.RD_Pixels ) {
205 						if( wR > pRGB->Red ) {
206 							tmp = wR;
207 							wR  = pRGB->Red;
208 							pRGB->Red = tmp;
209 						}
210 						if( wG > pRGB->Green ) {
211 							tmp = wG;
212 							wG  = pRGB->Green;
213 							pRGB->Green = tmp;
214 						}
215 						if( wB > pRGB->Blue ) {
216 							tmp = wB;
217 							wB  = pRGB->Blue;
218 							pRGB->Blue = tmp;
219 						}
220 					}
221 
222 					wR = *cp.red.usp++;
223 					wG = *cp.green.usp++;
224 					wB = *cp.blue.usp++;
225 
226 					for( b = dev->shade.skipShadow; b--;
227 					                            pRGB += dev->regs.RD_Pixels ) {
228 						if( wR < pRGB->Red ) {
229 							tmp = wR;
230 							wR  = pRGB->Red;
231 							pRGB->Red = tmp;
232 						}
233 						if( wG < pRGB->Green ) {
234 							tmp = wG;
235 							wG  = pRGB->Green;
236 							pRGB->Green = tmp;
237 						}
238 						if( wB < pRGB->Blue ) {
239 							tmp = wB;
240 							wB  = pRGB->Blue;
241 							pRGB->Blue = tmp;
242 						}
243 					}
244 				}
245 			} else {
246 
247 				cp.green.usp = dev->bufs.b1.pShadingRam +
248 				               dev->regs.RD_Pixels + _SHADING_BEGINX;
249 				cp.blue.usp  = (u_short*)dev->shade.pHilight + _SHADING_BEGINX;
250 
251 				for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
252 				                                              var.dwValue--;) {
253 					cp.red.usp = cp.blue.usp++;
254 					wG = *cp.green.usp;
255 					for( b = dev->shade.skipHilight; b--;
256 					                       cp.red.usp += dev->regs.RD_Pixels) {
257 						if( wG > *cp.red.usp ) {
258 							tmp = wG;
259 							wG  = *cp.red.usp;
260 							*cp.red.usp = tmp;
261 						}
262 					}
263 					wG = *cp.green.usp++;
264 					for( b = dev->shade.skipShadow; b--;
265 					                      cp.red.usp += dev->regs.RD_Pixels ) {
266 						if( wG < *cp.red.usp ) {
267 							tmp = wG;
268 							wG  = *cp.red.usp;
269 							*cp.red.usp = tmp;
270 						}
271 					}
272 				}
273 			}
274 		}
275 
276 		/* AddToSumBuffer() */
277 		if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
278 
279 			cp.red.usp   = dev->bufs.b1.pShadingRam + _SHADING_BEGINX;
280 			cp.green.usp = cp.red.usp   + dev->regs.RD_Pixels;
281 			cp.blue.usp  = cp.green.usp + dev->regs.RD_Pixels;
282 
283 			pvar.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
284 
285 			for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX;
286 			     var.dwValue--;
287 			     pvar.pulrgb++, cp.red.usp++, cp.green.usp++, cp.blue.usp++) {
288 				pvar.pulrgb->Red   += (u_long)*cp.red.usp;
289 				pvar.pulrgb->Green += (u_long)*cp.green.usp;
290 				pvar.pulrgb->Blue  += (u_long)*cp.blue.usp;
291 			}
292 
293 		} else {
294 
295 			cp.green.usp = dev->bufs.b1.pShadingRam +
296 			               dev->regs.RD_Pixels +  _SHADING_BEGINX;
297 			pvar.pdw  = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
298 			for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX;
299 			     var.dwValue--; pvar.pdw++, cp.green.usp++) {
300 				*pvar.pdw += (u_long)*cp.green.usp;
301 			}
302 		}
303 
304 		u12io_ResetFifoLen();
305 		if( u12io_GetFifoLength( dev ) < dev->regs.RD_Pixels )
306 			u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
307 	}
308 
309 	/* AverageAfterSubHilightShadow() */
310 	if( dev->shade.pHilight ) {
311 		if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
312 
313 			psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
314 			pwsum       = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
315 			pvar.pusrgb = (RGBUShortDef*)dev->shade.pHilight + _SHADING_BEGINX;
316 
317 			for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
318                                                               var.dwValue--;) {
319 				pRGB = pvar.pusrgb++;
320 
321 				for( b = dev->shade.skipHilight + dev->shade.skipShadow;
322 				                           b--; pRGB += dev->regs.RD_Pixels ) {
323 
324 					psum.pulrgb->Red   -= (u_long)pRGB->Red;
325 					psum.pulrgb->Green -= (u_long)pRGB->Green;
326 					psum.pulrgb->Blue  -= (u_long)pRGB->Blue;
327 				}
328 
329 				pwsum->Red   = (u_short)(psum.pulrgb->Red   / dev->shade.dwDiv);
330 				pwsum->Green = (u_short)(psum.pulrgb->Green / dev->shade.dwDiv);
331 				pwsum->Blue  = (u_short)(psum.pulrgb->Blue  / dev->shade.dwDiv);
332 				psum.pulrgb++;
333 				pwsum++;
334 			}
335 		} else {
336 			cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
337 			cp.blue.usp  = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
338 			pvar.pw      = (u_short*)dev->shade.pHilight  + _SHADING_BEGINX;
339 
340 			for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
341 			                                                  var.dwValue--;) {
342 				cp.red.usp = pvar.pw++;
343 
344 				for( b = dev->shade.skipHilight + dev->shade.skipShadow;
345 				                       b--; cp.red.usp += dev->regs.RD_Pixels )
346 					*cp.green.ulp -= *cp.red.usp;
347 
348 				*cp.blue.usp = (u_short)(*cp.green.ulp / dev->shade.dwDiv);
349 				cp.blue.usp++;
350 				cp.green.ulp++;
351 			}
352 		}
353 	} else {
354 
355 		if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
356 
357 			psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf  + _SHADING_BEGINX;
358 			pwsum       = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
359 
360 			for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
361 			                                                  var.dwValue--;) {
362 				pwsum->Red   = (u_short)(psum.pulrgb->Red   >> 5);
363 				pwsum->Green = (u_short)(psum.pulrgb->Green >> 5);
364 				pwsum->Blue  = (u_short)(psum.pulrgb->Blue  >> 5);
365 				psum.pulrgb++;
366 				pwsum++;
367 			}
368 		} else {
369 			cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf  + _SHADING_BEGINX;
370 			cp.blue.usp  = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
371 
372 			for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
373 			                                                  var.dwValue--;) {
374 				*cp.blue.usp = (u_short)(*cp.green.ulp >> 5);
375 				cp.blue.usp++;
376 				cp.green.ulp++;
377 			}
378 		}
379 	}
380 
381 	/* Process negative & transparency here */
382 	if( dev->DataInf.dwScanFlag & _SCANDEF_TPA )
383 		u12tpa_FindCenterPointer( dev );
384 
385 	if( dev->DataInf.dwScanFlag & _SCANDEF_Negative )
386 		u12tpa_Reshading( dev );
387 
388 	pRGB = (RGBUShortDef*)&dev->shade.pCcdDac->GainResize;
389 
390 	if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
391 
392 		pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
393 
394 		for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
395 		                                                      var.dwValue--;) {
396 
397 			if ((short)(pwsum->Red -= dev->shade.DarkOffset.Colors.Red) > 0) {
398 				pwsum->Red = pwsum->Red * pRGB->Red / 100U;
399 				if( pwsum->Red > 0xfff )
400 					pwsum->Red = 0xfff;
401 			} else
402 				pwsum->Red = 0;
403 
404 			if((short)(pwsum->Green -= dev->shade.DarkOffset.Colors.Green) > 0) {
405 				pwsum->Green = pwsum->Green * pRGB->Green / 100U;
406 				if( pwsum->Green > 0xfff )
407 					pwsum->Green = 0xfff;
408 			} else
409 				pwsum->Green = 0;
410 
411 			if ((short)(pwsum->Blue -= dev->shade.DarkOffset.Colors.Blue) > 0) {
412 				pwsum->Blue = pwsum->Blue * pRGB->Blue / 100U;
413 				if( pwsum->Blue > 0xfff )
414 					pwsum->Blue = 0xfff;
415 			} else
416 				pwsum->Blue = 0;
417 
418 			wR = (u_short)(pwsum->Red >> 4);
419 			pwsum->Red <<= 12;
420 			pwsum->Red |= wR;
421 			wR = (u_short)(pwsum->Green >> 4);
422 			pwsum->Green <<= 12;
423 			pwsum->Green |= wR;
424 			wR = (u_short)(pwsum->Blue>> 4);
425 			pwsum->Blue <<= 12;
426 			pwsum->Blue |= wR;
427 			pwsum++;
428 		}
429 	} else {
430 
431 		cp.green.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
432 
433 		for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
434 		                                                      var.dwValue--;) {
435 
436 			if((short)(*cp.green.usp -= dev->shade.DarkOffset.Colors.Green) > 0) {
437 
438 				*cp.green.usp = *cp.green.usp * pRGB->Green / 100U;
439 				if( *cp.green.usp > 0xfff )
440 					*cp.green.usp = 0xfff;
441 			} else
442 				*cp.green.usp = 0;
443 
444 			wR = (u_short)(*cp.green.usp >> 4);
445 			*cp.green.usp <<= 12;
446 			*cp.green.usp |= wR;
447 
448 			cp.green.usp++;
449 		}
450 	}
451 
452 	u12shading_DownloadShadingTable(dev, dev->bufs.b2.pSumBuf, (5400 * 3 * 2));
453 	return SANE_STATUS_GOOD;
454 }
455 
456 /**
457  */
u12shading_GainOffsetToDAC( U12_Device *dev, SANE_Byte ch, SANE_Byte reg, SANE_Byte d )458 static void u12shading_GainOffsetToDAC( U12_Device *dev, SANE_Byte ch,
459                                         SANE_Byte reg, SANE_Byte d )
460 {
461 	if( dev->DACType == _DA_SAMSUNG8531 ) {
462 		u12io_DataRegisterToDAC( dev, 0, ch );
463 	}
464 	u12io_DataRegisterToDAC( dev, reg, d );
465 }
466 
467 /**
468  */
u12shading_FillToDAC( U12_Device *dev, RGBByteDef *regs, ColorByte *data )469 static void u12shading_FillToDAC( U12_Device *dev,
470                                   RGBByteDef *regs, ColorByte *data )
471 {
472 	if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
473 
474 		u12shading_GainOffsetToDAC(dev, _DAC_RED, regs->Red, data->Colors.Red);
475 		u12shading_GainOffsetToDAC(dev, _DAC_GREENCOLOR,
476                                               regs->Green, data->Colors.Green);
477 		u12shading_GainOffsetToDAC(dev, _DAC_BLUE,
478                                                 regs->Blue, data->Colors.Blue);
479 	} else {
480 		u12shading_GainOffsetToDAC(dev, _DAC_GREENMONO, regs->Green,
481 		                                                   data->Colors.Green);
482     }
483 }
484 
485 /**
486  */
u12shading_SumGains( SANE_Byte *pb, u_long pixelsLine )487 static SANE_Byte u12shading_SumGains( SANE_Byte *pb, u_long pixelsLine )
488 {
489 	SANE_Byte hilight, tmp;
490 	u_long    dwPixels, dwAve;
491 	u_short   sum;
492 
493 	hilight = 0;
494 	for( dwPixels = pixelsLine >> 4; dwPixels--; ) {
495 
496 		for( sum = 0, dwAve = 16; dwAve--; pb++ )
497 			sum += (u_short)*pb;
498 
499 		sum >>= 4;
500 		tmp = (SANE_Byte)sum;
501 
502 		if( tmp > hilight )
503 			hilight = tmp;
504 	}
505 	return hilight;
506 }
507 
508 /**
509  */
510 static void
u12shading_AdjustGain( U12_Device *dev, u_long color, SANE_Byte hilight )511 u12shading_AdjustGain( U12_Device *dev, u_long color, SANE_Byte hilight )
512 {
513 	if( hilight < dev->shade.bGainLow ) {
514 
515 		if( dev->shade.Hilight.bColors[color] < dev->shade.bGainHigh ) {
516 
517 			dev->shade.fStop = SANE_FALSE;
518 			dev->shade.Hilight.bColors[color] = hilight;
519 
520 			if( hilight <= (SANE_Byte)(dev->shade.bGainLow - hilight))
521 				dev->shade.Gain.bColors[color] += dev->shade.bGainDouble;
522 			else
523 				dev->shade.Gain.bColors[color]++;
524 		}
525 	} else {
526 		if( hilight > dev->shade.bGainHigh ) {
527 			dev->shade.fStop = SANE_FALSE;
528 			dev->shade.Hilight.bColors[color] = hilight;
529 			dev->shade.Gain.bColors[color]--;
530 		} else {
531 			dev->shade.Hilight.bColors[color] = hilight;
532 		}
533 	}
534 
535 	if( dev->shade.Gain.bColors[color] > dev->shade.bMaxGain ) {
536 		dev->shade.Gain.bColors[color] = dev->shade.bMaxGain;
537 	}
538 }
539 
540 /**
541  */
u12shading_AdjustRGBGain( U12_Device *dev )542 static SANE_Status u12shading_AdjustRGBGain( U12_Device *dev )
543 {
544 	int       i;
545 	SANE_Byte hi[3];
546 
547 	DBG( _DBG_INFO, "u12shading_AdjustRGBGain()\n" );
548 
549 	dev->shade.Gain.Colors.Red   =
550 	dev->shade.Gain.Colors.Green =
551 	dev->shade.Gain.Colors.Blue  =  dev->shade.bUniGain;
552 
553 	dev->shade.Hilight.Colors.Red   =
554 	dev->shade.Hilight.Colors.Green =
555 	dev->shade.Hilight.Colors.Blue  = 0;
556 
557 	dev->shade.bGainHigh = _GAIN_HIGH;
558 	dev->shade.bGainLow  = _GAIN_LOW;
559 
560 	dev->shade.fStop = SANE_FALSE;
561 
562 	for( i = 10; i-- && !dev->shade.fStop; ) {
563 
564 		if( u12io_IsEscPressed()) {
565 			DBG( _DBG_INFO, "* CANCEL detected!\n" );
566 			return SANE_STATUS_CANCELLED;
567 		}
568 
569 		dev->shade.fStop = SANE_TRUE;
570 
571 		u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
572 
573 		dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
574 		u12hw_SelectLampSource( dev );
575 		u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
576 
577 		u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
578 
579 		dev->regs.RD_ModeControl   = _ModeScan;
580 		dev->regs.RD_StepControl   = _MOTOR0_SCANSTATE;
581 		dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
582 
583 		if( dev->shade.intermediate & _ScanMode_AverageOut )
584 			dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X >> 1;
585 		else
586 			dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X;
587 
588 		dev->regs.RD_Dpi    = 300;
589 		dev->regs.RD_Pixels = 2560;
590 
591 		memset( dev->scanStates, 0, _SCANSTATE_BYTES );
592 		dev->scanStates[1] = 0x77;
593 
594 		u12io_PutOnAllRegisters( dev );
595 /*		_DODELAY( 100 ); */
596 
597 		/* read one shading line and work on it */
598 		if( u12io_ReadOneShadingLine( dev,
599 		                         (SANE_Byte*)dev->bufs.b1.pShadingRam, 2560)) {
600 
601 			if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
602 
603 				hi[1] = u12shading_SumGains(
604 				           (SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560);
605 				if( hi[1] ) {
606 					u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] );
607 				} else {
608 					dev->shade.fStop = SANE_FALSE;
609 				}
610 			} else {
611 				hi[0] = u12shading_SumGains(
612 				                   (SANE_Byte*)dev->bufs.b1.pShadingRam, 2560);
613 				hi[1] = u12shading_SumGains(
614 				            (SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560);
615 				hi[2] = u12shading_SumGains(
616 				            (SANE_Byte*)dev->bufs.b1.pShadingRam + 5120, 2560);
617 
618 				if (!hi[0] || !hi[1] || !hi[2] ) {
619 					dev->shade.fStop = SANE_FALSE;
620 				} else {
621 					u12shading_AdjustGain( dev, _CHANNEL_RED,   hi[0] );
622 					u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] );
623 					u12shading_AdjustGain( dev, _CHANNEL_BLUE,  hi[2] );
624 				}
625 			}
626 		} else
627 			dev->shade.fStop = SANE_FALSE;
628 	}
629 
630 	if( !dev->shade.fStop )
631 		DBG( _DBG_INFO, "u12shading_AdjustRGBGain() - all loops done!!!\n" );
632 
633 	u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
634 	return SANE_STATUS_GOOD;
635 }
636 
637 /**
638  */
u12shading_SumDarks( U12_Device *dev, u_short *data )639 static u_short u12shading_SumDarks( U12_Device *dev, u_short *data )
640 {
641 	u_short i, loop;
642 
643 	if( dev->CCDID == _CCD_3799 ) {
644 		if( dev->shade.intermediate & _ScanMode_AverageOut )
645 			data += 0x18;
646 		else
647 			data += 0x30;
648 	} else {
649 		if( dev->shade.intermediate & _ScanMode_AverageOut )
650 			data += 0x18;
651     	else
652 			data += 0x20;
653 	}
654 
655 	for( i = 0, loop = 16; loop--; data++ )
656 		i += *data;
657 	i >>= 4;
658 
659 	return i;
660 }
661 
662 /**
663  */
u12shadingAdjustDark( U12_Device *dev )664 static SANE_Status u12shadingAdjustDark( U12_Device *dev )
665 {
666 	u_long  i;
667 	u_short wDarks[3];
668 
669 	DBG( _DBG_INFO, "u12shadingAdjustDark()\n" );
670 	dev->shade.DarkDAC.Colors = dev->shade.pCcdDac->DarkDAC.Colors;
671 	dev->shade.fStop = SANE_FALSE;
672 
673 	for( i = 16; i-- && !dev->shade.fStop;) {
674 
675 		if( u12io_IsEscPressed()) {
676 			DBG( _DBG_INFO, "* CANCEL detected!\n" );
677 			return SANE_STATUS_CANCELLED;
678 		}
679 
680 		dev->shade.fStop = SANE_TRUE;
681 
682 		u12shading_FillToDAC( dev, &dev->RegDACOffset, &dev->shade.DarkDAC );
683 		u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
684 
685 		dev->regs.RD_ScanControl = (_SCAN_12BITMODE + _SCAN_1ST_AVERAGE);
686 		u12hw_SelectLampSource( dev );
687 		u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
688 
689 		dev->regs.RD_StepControl   = _MOTOR0_SCANSTATE;
690 		dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
691 
692 		dev->regs.RD_Origin = _SHADING_BEGINX;
693 		dev->regs.RD_Pixels = 512;
694 
695 		if( dev->shade.intermediate & _ScanMode_AverageOut )
696 			dev->regs.RD_Dpi = 300;
697 		else
698 			dev->regs.RD_Dpi = 600;
699 
700 		memset( dev->scanStates, 0, _SCANSTATE_BYTES );
701 		dev->scanStates[1] = 0x77;
702 
703 		u12io_PutOnAllRegisters( dev );
704 /*		_DODELAY( 100 ); */
705 
706 		/* read one shading line and work on it */
707 		if( u12io_ReadOneShadingLine(dev,
708 		                        (SANE_Byte*)dev->bufs.b1.pShadingRam, 512*2)) {
709 
710 			if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
711 
712 				wDarks[0] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam);
713 				wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
714                                                 dev->regs.RD_Pixels );
715 				wDarks[2] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
716 				                                dev->regs.RD_Pixels * 2UL);
717 
718 				if( !wDarks[0] || !wDarks[1] || !wDarks[2] ) {
719 					dev->shade.fStop = SANE_FALSE;
720 				} else {
721 					dev->shade.DarkOffset.wColors[0] = wDarks[0];
722 					dev->shade.DarkOffset.wColors[1] = wDarks[1];
723 					dev->shade.DarkOffset.wColors[2] = wDarks[2];
724 					(*dev->fnDACDark)( dev,dev->shade.pCcdDac,
725 					                           _CHANNEL_RED, wDarks[0] );
726 					(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
727 					                           _CHANNEL_GREEN, wDarks[1] );
728 					(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
729 					                           _CHANNEL_BLUE, wDarks[2] );
730 				}
731 			} else {
732 				wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
733                                                 dev->regs.RD_Pixels );
734 				if(!wDarks[1] ) {
735 					dev->shade.fStop = SANE_FALSE;
736 				} else {
737 					dev->shade.DarkOffset.wColors[1] = wDarks[1];
738 					(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
739 				                                   _CHANNEL_GREEN, wDarks[1] );
740 				}
741 			}
742 		} else {
743 			dev->shade.fStop = SANE_FALSE;
744 		}
745 	}
746 
747 	/* CalculateDarkDependOnCCD() */
748 	if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
749 		(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_RED   );
750 		(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN );
751 		(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_BLUE  );
752 	} else {
753 		(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN );
754 	}
755 	return SANE_STATUS_GOOD;
756 }
757 
758 /** here we download the current mapping table
759  */
u12shading_DownloadMapTable( U12_Device *dev, SANE_Byte *buf )760 static void u12shading_DownloadMapTable( U12_Device *dev, SANE_Byte *buf )
761 {
762 	SANE_Byte addr, regs[6];
763 	int       i;
764 
765 	u12io_DataToRegister( dev, REG_SCANCONTROL,
766 	          (SANE_Byte)((dev->regs.RD_ScanControl & 0xfc) | _SCAN_BYTEMODE));
767 
768 	/* prepare register settings... */
769 	regs[0] = REG_MODECONTROL;
770 	regs[1] = _ModeMappingMem;
771 	regs[2] = REG_MEMORYLO;
772 	regs[3] = 0;
773 	regs[4] = REG_MEMORYHI;
774 
775 	for( i = 3, addr = _MAP_ADDR_RED; i--; addr += _MAP_ADDR_SIZE ) {
776 
777 		regs[5] = addr;
778 		u12io_DataToRegs( dev, regs, 3 );
779 
780 		u12io_MoveDataToScanner( dev, buf, 4096 );
781 		buf += 4096;
782 	}
783 
784 	u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
785 }
786 
787 /**
788  */
u12shading_DoCalibration( U12_Device *dev )789 static SANE_Status u12shading_DoCalibration( U12_Device *dev )
790 {
791 	SANE_Byte   tb[4096*3];
792 	u_long      i, tmp;
793 	SANE_Byte   bScanControl, rb[20];
794 	SANE_Status res;
795 	int         c;
796 
797 	DBG( _DBG_INFO, "u12shading_DoCalibration()\n" );
798 
799 	/** before getting the shading data, (re)init the ASIC
800 	 */
801 	u12hw_InitAsic( dev, SANE_TRUE );
802 
803 	dev->shade.DarkOffset.Colors.Red   = 0;
804 	dev->shade.DarkOffset.Colors.Green = 0;
805 	dev->shade.DarkOffset.Colors.Blue  = 0;
806 
807 	c = 0;
808 	_SET_REG( rb, c, REG_RESETMTSC, 0 );
809 	_SET_REG( rb, c, REG_MODELCONTROL, dev->regs.RD_ModelControl);
810 	_SET_REG( rb, c, REG_MOTORDRVTYPE, dev->regs.RD_MotorDriverType );
811 	_SET_REG( rb, c, REG_SCANCONTROL1, (_SCANSTOPONBUFFULL| _MFRC_BY_XSTEP));
812 
813 	u12io_DataToRegs( dev, rb, c );
814 
815 	res = u12motor_GotoShadingPosition( dev );
816 	if( SANE_STATUS_GOOD != res )
817 		return res;
818 
819 	bScanControl = dev->regs.RD_ScanControl;
820 
821     /* SetShadingMapForGainDark */
822 	memset( dev->bufs.b2.pSumBuf, 0xff, (5400 * 3 * 2));
823 	u12shading_DownloadShadingTable( dev, dev->bufs.b2.pSumBuf, (5400*3*2));
824 
825 	for( i = 0, tmp = 0; i < 1024; tmp += 0x01010101, i += 4 ) {
826 		dev->bufs.b1.Buf.pdw[i]   =
827 		dev->bufs.b1.Buf.pdw[i+1] =
828 		dev->bufs.b1.Buf.pdw[i+2] =
829 		dev->bufs.b1.Buf.pdw[i+3] = tmp;
830 	}
831 
832 	memcpy( dev->bufs.b1.pShadingMap + 4096, dev->bufs.b1.pShadingMap, 4096 );
833 	memcpy( dev->bufs.b1.pShadingMap + 8192, dev->bufs.b1.pShadingMap, 4096 );
834 	u12shading_DownloadMapTable( dev, dev->bufs.b1.pShadingMap );
835 
836 	DBG( _DBG_INFO, "* wExposure = %u\n", dev->shade.wExposure);
837 	DBG( _DBG_INFO, "* wXStep    = %u\n", dev->shade.wXStep);
838 
839 	dev->regs.RD_LineControl    = (_LOBYTE(dev->shade.wExposure));
840 	dev->regs.RD_ExtLineControl = (_HIBYTE(dev->shade.wExposure));
841 	u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL,
842 	                                            dev->regs.RD_ExtLineControl );
843 	u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl );
844 
845 	res = u12shading_AdjustRGBGain( dev );
846 	if( SANE_STATUS_GOOD != res )
847 		return res;
848 
849 	res = u12shadingAdjustDark( dev );
850 	if( SANE_STATUS_GOOD != res )
851 		return res;
852 
853 	res = u12shadingAdjustShadingWaveform( dev );
854 	if( SANE_STATUS_GOOD != res )
855 		return res;
856 
857 	dev->regs.RD_ScanControl = bScanControl;
858 
859 	/* here we have to prepare and download the table in any case...*/
860 	if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
861 		u12map_Adjust( dev, _MAP_MASTER, tb );
862 	} else {
863 		u12map_Adjust( dev, _MAP_RED, tb   );
864 		u12map_Adjust( dev, _MAP_GREEN, tb );
865 		u12map_Adjust( dev, _MAP_BLUE, tb  );
866 	}
867 
868 	u12shading_DownloadMapTable( dev, tb );
869 
870 	u12motor_BackToHomeSensor( dev );
871 	DBG( _DBG_INFO, "u12shading_DoCalibration() - done.\n" );
872 	return SANE_STATUS_GOOD;
873 }
874 
875 /* END U12-SHADING ..........................................................*/
876