1 /* @file u12_image.c
2  * @brief functions to convert scanner data into image data
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 - fixed fnColor42() to return 16bit values instead of
10  *          only 12bit (this is the maximum the scanner can)
11  *        - added scaling function u12image_ScaleX()
12  * .
13  * <hr>
14  * This file is part of the SANE package.
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License as
18  * published by the Free Software Foundation; either version 2 of the
19  * License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
28  *
29  * As a special exception, the authors of SANE give permission for
30  * additional uses of the libraries contained in this release of SANE.
31  *
32  * The exception is that, if you link a SANE library with other files
33  * to produce an executable, this does not by itself cause the
34  * resulting executable to be covered by the GNU General Public
35  * License.  Your use of that executable is in no way restricted on
36  * account of linking the SANE library code into it.
37  *
38  * This exception does not, however, invalidate any other reasons why
39  * the executable file might be covered by the GNU General Public
40  * License.
41  *
42  * If you submit changes to SANE to the maintainers to be included in
43  * a subsequent release, you agree by submitting the changes that
44  * those changes may be distributed with this exception intact.
45  *
46  * If you write modifications of your own for SANE, it is your choice
47  * whether to permit this exception to apply to your modifications.
48  * If you do not wish that, delete this exception notice.
49  * <hr>
50  */
51 
52 /*************************** local vars **************************************/
53 
54 static u_short wPreviewScanned = 0;
55 
56 static ExpXStepDef negScan[5] = {
57 	{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
58 };
59 
60 static ExpXStepDef posScan[5] = {
61 	{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
62 };
63 
64 static ExpXStepDef nmlScan[5] = {
65 	{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96},
66 };
67 
68 /*************************** local functions *********************************/
69 
70 /**
71  */
fnReadToDriver( U12_Device *dev )72 static SANE_Bool fnReadToDriver( U12_Device *dev )
73 {
74 	dev->regs.RD_ModeControl = _ModeFifoBSel;
75 	u12io_ReadMonoData( dev, dev->scan.BufPut.blue.bp,
76 	                    dev->DataInf.dwAsicBytesPerPlane );
77 
78 	dev->regs.RD_ModeControl = _ModeFifoGSel;
79 	u12io_ReadMonoData( dev, dev->scan.BufPut.green.bp,
80 	                    dev->DataInf.dwAsicBytesPerPlane );
81 
82 	if( dev->scan.gd_gk.wGreenKeep )
83 		dev->scan.gd_gk.wGreenKeep--;
84 	else {
85 		dev->scan.BufPut.green.bp += dev->DataInf.dwAsicBytesPerPlane;
86 
87 		if( dev->scan.BufPut.green.bp >= dev->scan.BufEnd.green.bp )
88 		    dev->scan.BufPut.green.bp = dev->scan.BufBegin.green.bp;
89 	}
90 
91 	dev->regs.RD_ModeControl = _ModeFifoRSel;
92 	u12io_ReadMonoData( dev, dev->scan.BufPut.red.bp,
93 	                    dev->DataInf.dwAsicBytesPerPlane );
94 
95 	dev->scan.BufPut.red.bp += dev->DataInf.dwAsicBytesPerPlane;
96 	if( dev->scan.BufPut.red.bp >= dev->scan.BufEnd.red.bp )
97 		dev->scan.BufPut.red.bp = dev->scan.BufBegin.red.bp;
98 
99 	if( dev->scan.bd_rk.wRedKeep ) {
100 		dev->scan.bd_rk.wRedKeep--;
101 		return SANE_FALSE;
102 
103 	} else {
104 
105 		dev->scan.BufData.green.bp = dev->scan.BufGet.green.bp;
106 		dev->scan.BufData.red.bp   = dev->scan.BufGet.red.bp;
107 		dev->scan.BufData.blue.bp  = dev->scan.BufGet.blue.bp;
108 
109 		dev->scan.BufGet.red.bp   += dev->DataInf.dwAsicBytesPerPlane;
110 		dev->scan.BufGet.green.bp += dev->DataInf.dwAsicBytesPerPlane;
111 
112 		if( dev->scan.BufGet.red.bp >= dev->scan.BufEnd.red.bp )
113 			dev->scan.BufGet.red.bp = dev->scan.BufBegin.red.bp;
114 
115 		if( dev->scan.BufGet.green.bp >= dev->scan.BufEnd.green.bp )
116 			dev->scan.BufGet.green.bp = dev->scan.BufBegin.green.bp;
117 
118 		return SANE_TRUE;
119 	}
120 }
121 
122 /**
123  */
fnReadOutScanner( U12_Device *dev )124 static SANE_Bool fnReadOutScanner( U12_Device *dev )
125 {
126 	if( dev->scan.bd_rk.wBlueDiscard ) {
127 
128 		dev->scan.bd_rk.wBlueDiscard--;
129 		dev->regs.RD_ModeControl = _ModeFifoBSel;
130 
131 		u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
132 		                dev->DataInf.dwAsicBytesPerPlane );
133 
134 		if( dev->scan.gd_gk.wGreenDiscard ) {
135 			dev->scan.gd_gk.wGreenDiscard--;
136 
137 			dev->regs.RD_ModeControl = _ModeFifoGSel;
138 			u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
139 			                    dev->DataInf.dwAsicBytesPerPlane );
140 		}
141 		return SANE_FALSE;
142 
143 	} else {
144 		u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
145 		                     dev->DataInf.dwAsicBytesPerPlane );
146 		return SANE_TRUE;
147 	}
148 }
149 
150 /** some sampling functions
151  */
fnEveryLine( U12_Device *dev )152 static SANE_Bool fnEveryLine( U12_Device *dev )
153 {
154 	_VAR_NOT_USED( dev );
155 	return SANE_TRUE;
156 }
157 
fnSampleLines( U12_Device *dev )158 static SANE_Bool fnSampleLines( U12_Device *dev )
159 {
160 	dev->DataInf.wYSum += dev->DataInf.xyAppDpi.y;
161 
162 	if( dev->DataInf.wYSum >= dev->DataInf.xyPhyDpi.y ) {
163 		dev->DataInf.wYSum -= dev->DataInf.xyPhyDpi.y;
164 		return	SANE_TRUE;
165 	}
166 	return SANE_FALSE;
167 }
168 
fnSamplePreview( U12_Device *dev )169 static SANE_Bool fnSamplePreview( U12_Device *dev )
170 {
171 	dev->DataInf.wYSum += wPreviewScanned;
172 	if( dev->DataInf.wYSum >= 150 ) {
173 
174 		dev->DataInf.wYSum -= 150;
175 		return SANE_TRUE;
176 	}
177 
178 	return SANE_FALSE;
179 }
180 
181 /** this function is used when
182  * - the data type is B/W or GrayScale.
183  * - the required horizontal resolution doesn't exceed the optic spec.
184  * - the required vertical resolution exceeds the optic spec.
185  */
fnDataDirect( U12_Device *dev, void *src, void *dest, u_long len )186 static void fnDataDirect( U12_Device *dev, void *src, void *dest, u_long len )
187 {
188 	_VAR_NOT_USED( dev );
189 	memcpy( dest, src, len );
190 }
191 
192 /** merges the color planes to pixels style without enlarge operation.
193  */
fnColorDirect( U12_Device *dev, void *pb, void *img, u_long len )194 static void fnColorDirect( U12_Device *dev, void *pb, void *img, u_long len )
195 {
196 	SANE_Byte  *src;
197 	RGBByteDef *dest;
198 
199 	src  = (SANE_Byte*)img;
200 	dest = (RGBByteDef*)pb;
201 
202 	for ( len = dev->DataInf.dwAsicPixelsPerPlane; len; len--, src++, dest++) {
203 
204 		dest->Red   = *src;
205 		dest->Green = src[dev->DataInf.dwAsicPixelsPerPlane];
206 		dest->Blue  = src[dev->DataInf.dwAsicPixelsPerPlane*2];
207 	}
208 }
209 
210 /** merges the color planes to pixels style without enlarge operation.
211  *  The scanner returns the pixel data in Motorola-Format, so we have to swap
212  *  (at least on x86)
213  */
fnColor42( U12_Device *dev, void *pb, void *img, u_long len )214 static void fnColor42( U12_Device *dev, void *pb, void *img, u_long len )
215 {
216 	u_short      *src;
217 	RGBUShortDef *dest;
218 
219 	register u_long i;
220 
221 	_VAR_NOT_USED( len );
222 	src  = (u_short*)img;
223 	dest = (RGBUShortDef*)pb;
224 
225 	for ( i = dev->DataInf.dwAsicPixelsPerPlane; i; i--, src++, dest++) {
226 
227 		dest->Red   = (*src) << 4;
228 		dest->Green = (src[dev->DataInf.dwAsicPixelsPerPlane]) << 4;
229 		dest->Blue  = (src[dev->DataInf.dwAsicPixelsPerPlane * 2]) << 4;
230 	}
231 }
232 
233 /**
234  */
u12image_SetupScanStateVariables( U12_Device *dev, u_long index )235 static void u12image_SetupScanStateVariables( U12_Device *dev, u_long index )
236 {
237 	DataType var;
238 
239 	DBG( _DBG_INFO, "u12image_SetupScanStateVariables(%lu)\n", index );
240 	dev->scan.dpiIdx = index;
241 
242 	if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA)) {
243 
244 		dev->shade.wExposure = nmlScan[index].exposureTime;
245 		dev->shade.wXStep     = nmlScan[index].xStepTime;
246 
247 		if( dev->shade.intermediate & _ScanMode_AverageOut ) {
248 			dev->shade.wExposure >>= 1;
249 			dev->shade.wXStep    >>= 1;
250 		}
251 	} else {
252 		if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency ) {
253 			dev->shade.wExposure = posScan[index].exposureTime;
254 			dev->shade.wXStep    = posScan[index].xStepTime;
255 		} else {
256 			dev->shade.wExposure = dev->scan.negScan[index].exposureTime;
257 			dev->shade.wXStep    = dev->scan.negScan[index].xStepTime;
258 		}
259 	}
260 	dev->scan.dwInterval = 1;
261 
262 	if( dev->DataInf.wPhyDataType == COLOR_BW )
263 		var.dwValue = 0;
264 	else {
265 		if( dev->DataInf.wPhyDataType == COLOR_256GRAY )
266     		var.dwValue = 2500;
267 		else
268 			var.dwValue = 3200;
269 	}
270 
271 	/* for small size/descreen */
272 	if((dev->DataInf.xyAppDpi.y >= 300) && var.dwValue &&
273 	   (dev->DataInf.dwAsicBytesPerPlane <= var.dwValue)) {
274 		dev->scan.dwInterval <<= 1;
275 	}
276 
277 	if( var.dwValue && dev->DataInf.dwAsicBytesPerPlane > var.dwValue ) {
278 		if((var.dwValue << 1) > dev->DataInf.dwAsicBytesPerPlane)
279 			dev->scan.dwInterval <<= 1;
280 		else
281 			if((var.dwValue << 2) > dev->DataInf.dwAsicBytesPerPlane)
282 				dev->scan.dwInterval <<= 2;
283 			else
284 				dev->scan.dwInterval <<= 3;
285 	}
286 
287 	if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
288 
289 		if( dev->DataInf.xyPhyDpi.y > 75U ) {
290 			if( dev->f0_8_16 ) {
291 				dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 75U;
292 			} else {
293 				dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 150U;
294 			}
295 		} else {
296 			dev->scan.gd_gk.wGreenDiscard = 1;
297 		}
298 
299 		dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard << 1;
300 	} else {
301 		dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard = 0;
302 	}
303 }
304 
305 /** limit the resolution
306  */
307 static u_short
u12image_GetPhysDPI( U12_Device *dev, ImgDef *img, SANE_Bool fDpiX )308 u12image_GetPhysDPI( U12_Device *dev, ImgDef *img, SANE_Bool fDpiX )
309 {
310 	if( fDpiX ) {
311 
312 		if( img->xyDpi.x > dev->dpi_max_x )
313 			return dev->dpi_max_x;
314 		else
315 			return img->xyDpi.x;
316 
317 	} else {
318 
319 		if( img->xyDpi.y > dev->dpi_max_y )
320 				return dev->dpi_max_y;
321 		else
322 			return img->xyDpi.y;
323 	}
324 }
325 
326 /** calculate the image properties according to the scanmode
327  *  set all internally needed information
328  */
u12image_GetImageInfo( U12_Device *dev, ImgDef *image )329 static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image )
330 {
331 	DBG( _DBG_INFO, "u12image_GetImageInfo()\n" );
332 
333 	dev->DataInf.xyPhyDpi.x = u12image_GetPhysDPI(dev, image, SANE_TRUE );
334 	dev->DataInf.xyPhyDpi.y = u12image_GetPhysDPI(dev, image, SANE_FALSE);
335 
336 	DBG( _DBG_INFO, "* xyPhyDpi.x = %u, xyPhyDpi.y = %u\n",
337 	                dev->DataInf.xyPhyDpi.x, dev->DataInf.xyPhyDpi.y );
338 
339 	DBG( _DBG_INFO, "* crArea.x = %u, crArea.y = %u\n",
340 	                image->crArea.x, image->crArea.y );
341 
342 	DBG( _DBG_INFO, "* crArea.cx = %u, crArea.cy = %u\n",
343 	                image->crArea.cx, image->crArea.cy );
344 
345 	dev->DataInf.xyRatio = (double)dev->DataInf.xyPhyDpi.y/
346 	                       (double)dev->DataInf.xyPhyDpi.x;
347 
348 	dev->DataInf.dwAppLinesPerArea = (u_long)image->crArea.cy *
349 									  image->xyDpi.y / _MEASURE_BASE;
350 
351     dev->DataInf.dwAppPixelsPerLine = (u_long)image->crArea.cx *
352 									   image->xyDpi.x / _MEASURE_BASE;
353 
354 	dev->DataInf.dwPhysBytesPerLine = (u_long)image->crArea.cx *
355 									   dev->DataInf.xyPhyDpi.x / _MEASURE_BASE;
356 
357     if( image->wDataType <= COLOR_BW ) {
358 		dev->DataInf.dwAsicPixelsPerPlane =
359 		                  (dev->DataInf.dwAppPixelsPerLine+7UL) & 0xfffffff8UL;
360 		dev->DataInf.dwAppPhyBytesPerLine =
361 		dev->DataInf.dwAppBytesPerLine 	  =
362 		dev->DataInf.dwAsicBytesPerLine   =
363 		dev->DataInf.dwAsicBytesPerPlane  = dev->DataInf.dwAsicPixelsPerPlane>>3;
364     } else {
365 		dev->DataInf.dwAsicBytesPerPlane  =
366 		dev->DataInf.dwAsicPixelsPerPlane = dev->DataInf.dwAppPixelsPerLine;
367 	}
368 
369 	if( COLOR_TRUE42 == image->wDataType ) {
370 		dev->DataInf.dwAsicBytesPerPlane *= 2;
371 	}
372 
373 	switch( image->wDataType ) {
374 
375 	case COLOR_BW:
376 		dev->scan.DataProcess     = fnDataDirect;
377 		dev->DataInf.wPhyDataType = COLOR_BW;
378 		dev->shade.intermediate   = _ScanMode_Mono;
379 		break;
380 
381 	case COLOR_256GRAY:
382 		dev->scan.DataProcess     = fnDataDirect;
383 		dev->DataInf.dwAsicBytesPerLine =
384 		dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine;
385 		dev->DataInf.wPhyDataType = COLOR_256GRAY;
386 		dev->shade.intermediate   = _ScanMode_Mono;
387 		break;
388 
389 	case COLOR_TRUE24:
390 		dev->scan.DataProcess = fnColorDirect;
391 		dev->DataInf.dwAsicBytesPerLine =
392 		dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 3;
393 		dev->DataInf.wPhyDataType = COLOR_TRUE24;
394 		dev->shade.intermediate  = _ScanMode_Color;
395 		break;
396 
397 	case COLOR_TRUE42:
398 		dev->scan.DataProcess = fnColor42;
399 		dev->DataInf.dwAsicBytesPerLine =
400 		dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 6;
401 		dev->DataInf.wPhyDataType = COLOR_TRUE42;
402 		dev->shade.intermediate  = _ScanMode_Color;
403 		break;
404 	}
405 
406 	/* raus mit einem von beiden!!!!*/
407 	dev->DataInf.dwAppBytesPerLine = dev->DataInf.dwAppPhyBytesPerLine;
408 
409 	DBG( _DBG_INFO, "AppLinesPerArea    = %lu\n", dev->DataInf.dwAppLinesPerArea    );
410 	DBG( _DBG_INFO, "AppPixelsPerLine   = %lu\n", dev->DataInf.dwAppPixelsPerLine   );
411 	DBG( _DBG_INFO, "AppPhyBytesPerLine = %lu\n", dev->DataInf.dwAppPhyBytesPerLine );
412 	DBG( _DBG_INFO, "AppBytesPerLine    = %lu\n", dev->DataInf.dwAppBytesPerLine    );
413 	DBG( _DBG_INFO, "AsicPixelsPerPlane = %lu\n", dev->DataInf.dwAsicPixelsPerPlane );
414 	DBG( _DBG_INFO, "AsicBytesPerPlane  = %lu\n", dev->DataInf.dwAsicBytesPerPlane  );
415 	DBG( _DBG_INFO, "AsicBytesPerLine   = %lu\n", dev->DataInf.dwAsicBytesPerLine   );
416 	DBG( _DBG_INFO, "Physical Bytes     = %lu\n", dev->DataInf.dwPhysBytesPerLine   );
417 }
418 
419 /**
420  */
imageSetupScanSettings( U12_Device *dev, ImgDef *img )421 static int imageSetupScanSettings( U12_Device *dev, ImgDef *img )
422 {
423 	u_short brightness;
424 
425 	DBG( _DBG_INFO, "imageSetupScanSettings()\n" );
426 
427 	dev->DataInf.dwScanFlag = img->dwFlag;
428 	dev->DataInf.crImage    = img->crArea;
429 
430 	DBG( _DBG_INFO,"* DataInf.dwScanFlag = 0x%08lx\n",dev->DataInf.dwScanFlag);
431 
432 	dev->DataInf.crImage.x <<= 1;
433 
434 	dev->DataInf.xyAppDpi     = img->xyDpi;
435 	dev->DataInf.wAppDataType = img->wDataType;
436 
437 	u12image_GetImageInfo( dev, img );
438 
439 	dev->scan.lBufferAdjust = (long)dev->DataInf.dwAppBytesPerLine;
440 
441 	DBG( _DBG_INFO, "* Scan settings:\n" );
442 	DBG( _DBG_INFO, "* ImageInfo: (x=%u,y=%u,dx=%u,dy=%u)\n",
443 			 dev->DataInf.crImage.x,  dev->DataInf.crImage.y,
444 			 dev->DataInf.crImage.cx, dev->DataInf.crImage.cy );
445 
446 	/*
447 	 * 0                   _DEF_BW_THRESHOLD                     255
448 	 * +-------------------------+--------------------------------+
449 	 * |<------- Black --------->|<----------- White ------------>|
450 	 *  So, if user wish to make image darker, the threshold value should be
451 	 *  higher than _defBwThreshold, otherwise it should lower than the
452 	 *  _DefBwThreshold.
453 	 *  Darker = _DEF_BW_THRESHOLD + White * Input / 127;
454 	 *             Input < 0, and White = 255 - _DEF_BW_THRESHOLD, so
455 	 *           = _DEF_BW_THRESHOLD - (255 - _DEF_BW_THRESHOLD) * Input / 127;
456 	 *  The brighter is the same idea.
457 	 */
458 
459 /* CHECK: We have now two methods for setting the brightness...
460 */
461 	DBG( _DBG_INFO, "* brightness = %i\n", dev->DataInf.siBrightness );
462 	if ( dev->DataInf.siBrightness < 0) {
463 		brightness = (u_short)(_DEF_BW_THRESHOLD -
464 			       (255 - _DEF_BW_THRESHOLD) * dev->DataInf.siBrightness /127);
465 	} else {
466 		brightness = (u_short)(_DEF_BW_THRESHOLD -
467 					       _DEF_BW_THRESHOLD * dev->DataInf.siBrightness /127);
468 	}
469 
470 	dev->regs.RD_ThresholdControl = brightness;
471 	DBG( _DBG_INFO, "* RD_ThresholdControl = %i\n", brightness );
472 	return 0;
473 }
474 
475 /** PrepareScanningVariables() !!!
476  */
u12image_SetupScanSettings( U12_Device *dev, ImgDef *img )477 static SANE_Status u12image_SetupScanSettings( U12_Device *dev, ImgDef *img )
478 {
479 	DBG( _DBG_INFO, "u12image_SetupScanSettings()\n" );
480 
481 	wPreviewScanned   = 0;
482 	dev->scan.dpiIdx  = 0;
483 	dev->scan.negScan = negScan;
484 
485 	imageSetupScanSettings( dev, img );
486 
487 	if( !(dev->DataInf.dwScanFlag & _SCANDEF_TPA )) {
488 
489 		dev->scan.dwScanOrigin = dev->adj.upNormal * 4 + _RFT_SCANNING_ORG;
490 
491 	} else if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency) {
492 
493 		dev->scan.dwScanOrigin = dev->adj.upPositive * 4 + _POS_SCANNING_ORG;
494 	} else {
495 		dev->scan.dwScanOrigin = dev->adj.upNegative * 4 + _NEG_SCANNING_ORG;
496 	}
497 	dev->scan.dwScanOrigin += 64 /*dev->dwModelOriginY*/;
498 
499 	if( dev->DataInf.xyAppDpi.y <= 75 ) {
500 
501 		if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
502 
503 			dev->scan.bDiscardAll   = 0;
504 			dev->DataInf.xyPhyDpi.y = 150;
505 			dev->shade.intermediate |= _ScanMode_AverageOut;
506 			u12image_SetupScanStateVariables( dev, 1 );
507 	        dev->scan.gd_gk.wGreenDiscard = 0;
508 
509 			if( dev->DataInf.xyAppDpi.y >= 38 )
510 				dev->scan.bd_rk.wBlueDiscard = 1;
511 			else
512 				dev->scan.bd_rk.wBlueDiscard = 0;
513 
514 			if( dev->DataInf.wPhyDataType >= COLOR_256GRAY ) {
515 				dev->shade.wXStep    = 6;
516 				dev->shade.wExposure = 8 * dev->shade.wXStep;
517 			}
518 		} else {
519 			if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA) &&
520 			    (dev->DataInf.xyAppDpi.y <= 50) &&
521 			    (dev->DataInf.wPhyDataType >= COLOR_TRUE24)) {
522 				dev->shade.intermediate |= _ScanMode_AverageOut;
523 			}
524 
525 			if((dev->DataInf.wPhyDataType<COLOR_TRUE24) || dev->f0_8_16 ||
526 			         (dev->shade.intermediate & _ScanMode_AverageOut)) {
527 
528 				dev->scan.bDiscardAll   = 1;
529 				dev->DataInf.xyPhyDpi.y = 75;
530 				u12image_SetupScanStateVariables( dev, 0 );
531     		} else {
532 				dev->scan.bDiscardAll   = 2;
533 				dev->DataInf.xyPhyDpi.y = 150;
534 				u12image_SetupScanStateVariables( dev, 1 );
535 			}
536 		}
537 	} else {
538 		if( dev->DataInf.xyAppDpi.y <= 150 ) {
539 
540 			dev->scan.bDiscardAll   = 2;
541 			dev->DataInf.xyPhyDpi.y = 150;
542 			u12image_SetupScanStateVariables( dev, 1 );
543 
544 		} else if( dev->DataInf.xyAppDpi.y <= 300 ) {
545 
546 			dev->scan.bDiscardAll   = 4;
547 			dev->DataInf.xyPhyDpi.y = 300;
548 			u12image_SetupScanStateVariables( dev, 2 );
549 
550 		} else if( dev->DataInf.xyAppDpi.y <= 600 ) {
551 
552 			dev->scan.bDiscardAll   = 8;
553 			dev->DataInf.xyPhyDpi.y = 600;
554 			u12image_SetupScanStateVariables( dev, 3 );
555 
556 		} else {
557 
558 			dev->scan.bDiscardAll   = 16;
559 			dev->DataInf.xyPhyDpi.y = 1200;
560 			u12image_SetupScanStateVariables( dev, 4 );
561 		}
562 	}
563 
564 	/* ------- lines to sample or not? ------- */
565 	if( dev->DataInf.xyAppDpi.y == dev->DataInf.xyPhyDpi.y ) {
566 		DBG( _DBG_INFO, "* Sample every line\n" );
567 		dev->scan.DoSample = fnEveryLine;
568 	} else {
569 		if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
570 
571 			DBG( _DBG_INFO, "* Sample preview\n" );
572 			dev->scan.DoSample = fnSamplePreview;
573 			dev->DataInf.wYSum = 150;
574 
575 			if( dev->DataInf.xyAppDpi.y >= 38 )
576 				wPreviewScanned = dev->DataInf.xyAppDpi.y * 2;
577 			else if( dev->DataInf.xyAppDpi.y >= 19 )
578 				wPreviewScanned = dev->DataInf.xyAppDpi.y * 4;
579 			else
580 				wPreviewScanned = dev->DataInf.xyAppDpi.y * 8;
581 		} else {
582 
583 			DBG( _DBG_INFO, "* Sample lines (%u - %u)...\n",
584 						  dev->DataInf.xyPhyDpi.y, dev->DataInf.xyAppDpi.y );
585 			dev->scan.DoSample = fnSampleLines;
586 			dev->DataInf.wYSum = dev->DataInf.xyPhyDpi.y - dev->DataInf.xyAppDpi.y;
587 		}
588 	}
589 
590 	/* now assign the buffer pointers for image acquisition
591 	 */
592 	dev->scan.p48BitBuf.pb = NULL;
593 
594 	if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
595 
596 		u_long r, g, b;
597 
598 		r = (u_long)_SIZE_REDFIFO /
599 			dev->DataInf.dwAsicBytesPerPlane - dev->scan.bd_rk.wRedKeep;
600 		g = (u_long)_SIZE_GREENFIFO /
601 			dev->DataInf.dwAsicBytesPerPlane - dev->scan.gd_gk.wGreenKeep;
602 
603 		if((int)r < 16 || (int)g < 16) {
604 
605 			b = (u_long)(dev->scan.bd_rk.wRedKeep +
606 			             dev->scan.gd_gk.wGreenKeep + 2U) *
607 			             dev->DataInf.dwAsicBytesPerPlane;
608 
609 			DBG( _DBG_INFO, "48Bit buffer request: "
610 			     "len=%lu bytes, available=%lu\n", b, _SIZE_TOTAL_BUF_TPA );
611 
612 			if( b > _SIZE_TOTAL_BUF_TPA ) {
613 				DBG( _DBG_ERROR, "Not that much FIFO memory available!\n" );
614 				return SANE_STATUS_NO_MEM;
615 			}
616 
617 			dev->scan.p48BitBuf.pb = dev->bufs.b1.pReadBuf;
618 		}
619 	}
620 
621 	if( dev->scan.p48BitBuf.pb ){
622 		dev->scan.DataRead          = fnReadToDriver;
623 		dev->scan.BufGet.red.bp     =
624 		dev->scan.BufPut.red.bp     =
625 		dev->scan.BufBegin.red.bp   = dev->scan.p48BitBuf.pb;
626 		dev->scan.BufEnd.red.bp     =
627 		dev->scan.BufBegin.green.bp =
628 		dev->scan.BufGet.green.bp   =
629 		dev->scan.BufPut.green.bp   = dev->scan.p48BitBuf.pb +
630 		                              dev->DataInf.dwAsicBytesPerLine *
631 		                              (dev->scan.bd_rk.wRedKeep + 1U);
632 
633 		dev->scan.BufEnd.green.bp = dev->scan.BufBegin.green.bp +
634 		                            dev->DataInf.dwAsicBytesPerLine *
635 		                            (dev->scan.gd_gk.wGreenKeep + 1U);
636 		dev->scan.BufPut.blue.bp =
637 		dev->scan.BufGet.blue.bp = dev->bufs.b1.pReadBuf +
638 		                           dev->DataInf.dwAsicBytesPerLine * 2;
639 	} else {
640 		dev->scan.DataRead         = fnReadOutScanner;
641 		dev->scan.BufPut.red.bp    = dev->bufs.b1.pReadBuf;
642 		dev->scan.BufData.green.bp =
643 		dev->scan.BufPut.green.bp  = dev->scan.BufPut.red.bp +
644 		                             dev->DataInf.dwAsicBytesPerLine;
645 		dev->scan.BufPut.blue.bp   = dev->scan.BufPut.green.bp +
646 		                             dev->DataInf.dwAsicBytesPerLine;
647 
648 		dev->scan.BufData.red.bp  = dev->scan.BufPut.red.bp;
649 		dev->scan.BufData.blue.bp = dev->scan.BufPut.blue.bp;
650 	}
651 
652 /* CHECK: maybe remove this stuff */
653 #if 0
654 	if( ps->DataInf.dwScanFlag & _SCANDEF_Transparency) {
655 	    posScan[1].exposureTime = 96;
656 	    posScan[1].xStepTime    = 12;
657 	    posScan[2].exposureTime = 96;
658 	    posScan[2].xStepTime    = 24;
659 	    posScan[3].exposureTime = 96;
660 	    posScan[3].xStepTime    = 48;
661 	    posScan[4].exposureTime = 96;
662 	    posScan[4].xStepTime    = 96;
663 
664 	    /* Reset shading Exposure Time & xStep Time */
665 	    ps->Shade.wExposure = posScan[ps->Scan.dpiIdx].exposureTime;
666 	    ps->Shade.wXStep    = posScan[ps->Scan.dpiIdx].xStepTime;
667 	}
668 	else if( ps->DataInf.dwScanFlag & _SCANDEF_Negative) {
669         ps->Scan.negScan[1].exposureTime = 96;
670         ps->Scan.negScan[1].xStepTime    = 12;
671         ps->Scan.negScan[2].exposureTime = 96;
672         ps->Scan.negScan[2].xStepTime    = 24;
673         ps->Scan.negScan[3].exposureTime = 96;
674         ps->Scan.negScan[3].xStepTime    = 48;
675         ps->Scan.negScan[4].exposureTime = 96;
676         ps->Scan.negScan[4].xStepTime    = 96;
677 
678 	    /* Reset shading Exposure Time & xStep Time */
679     	ps->Shade.wExposure = ps->Scan.negScan[ps->Scan.dpiIdx].exposureTime;
680 		ps->Shade.wXStep    = ps->Scan.negScan[ps->Scan.dpiIdx].xStepTime;
681     }
682 #endif
683 	return SANE_STATUS_GOOD;
684 }
685 
686 /**
687  */
u12image_DataIsReady( U12_Device *dev, void* buf )688 static SANE_Bool u12image_DataIsReady( U12_Device *dev, void* buf )
689 {
690 	DBG( _DBG_READ, "* DataIsReady()\n" );
691 
692 	if( dev->scan.bDiscardAll ) {
693 		dev->scan.bDiscardAll--;
694 
695 		if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
696 			dev->regs.RD_ModeControl = _ModeFifoGSel;
697 			u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
698 			                            dev->DataInf.dwAsicBytesPerPlane );
699 		} else {
700 			u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
701 			                     dev->DataInf.dwAsicBytesPerPlane );
702 		}
703 		return SANE_FALSE;
704 	}
705 
706 	if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
707 
708 		dev->regs.RD_ModeControl = _ModeFifoGSel;
709 		u12io_ReadMonoData( dev, buf, dev->DataInf.dwAsicBytesPerPlane );
710 
711 	} else {
712 
713 		if( !dev->scan.DataRead( dev )) {
714 			return SANE_FALSE;
715 		}
716 	}
717 
718 	if( dev->scan.DoSample( dev )) {
719 
720 		/* direct is done here without copying...*/
721 		if( fnDataDirect != dev->scan.DataProcess ) {
722 			(*dev->scan.DataProcess)(dev, buf, (void*)(dev->scan.BufPut.red.bp),
723                                         dev->DataInf.dwAppPhyBytesPerLine);
724 		}
725 		return SANE_TRUE;
726 	}
727 	return SANE_FALSE;
728 }
729 
730 /**
731  */
u12image_ReadOneImageLine( U12_Device *dev, void* buf )732 static SANE_Status u12image_ReadOneImageLine( U12_Device *dev, void* buf )
733 {
734 	SANE_Byte  b, state;
735 	TimerDef  timer, t2;
736 
737 	DBG( _DBG_READ, "u12image_ReadOneImageLine()\n" );
738 
739 	u12io_StartTimer( &timer, _LINE_TIMEOUT );
740 	u12io_StartTimer( &t2, _SECOND*2 );
741 	do {
742 
743 		state = u12io_GetScanState( dev );
744 		dev->scan.bNowScanState = (state & _SCANSTATE_MASK);
745 
746 		if( state & _SCANSTATE_STOP ) {
747 
748 			DBG( _DBG_READ, "* SCANSTATE_STOP\n" );
749 			u12motor_ModuleForwardBackward( dev );
750 
751 			if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo )
752 				if( u12image_DataIsReady( dev, buf ))
753 					return SANE_STATUS_GOOD;
754 
755 		} else {
756 
757 			dev->scan.bModuleState = _MotorInNormalState;
758 			b = dev->scan.bNowScanState - dev->scan.oldScanState;
759 
760 			if((char) b < 0)
761 				b += _NUMBER_OF_SCANSTEPS;
762 
763 			if( b >= dev->scan.bRefresh ) {
764 
765 				u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
766 				dev->scan.oldScanState = u12io_GetScanState( dev );
767 				dev->scan.oldScanState &= _SCANSTATE_MASK;
768 			}
769 
770 			if( u12io_GetFifoLength( dev ) >= dev->scan.dwMaxReadFifo ) {
771 
772 				if( u12image_DataIsReady( dev, buf ))
773 					return SANE_STATUS_GOOD;
774 			}
775 			else {
776 
777 				b = dev->scan.bNowScanState - dev->scan.oldScanState;
778 
779 				if((char) b < 0)
780 					b += _NUMBER_OF_SCANSTEPS;
781 
782 				if( b >= dev->scan.bRefresh ) {
783 
784 					u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
785 					dev->scan.oldScanState = u12io_GetScanState( dev );
786 					dev->scan.oldScanState &= _SCANSTATE_MASK;
787 				}
788 
789 				if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo ) {
790 					if( u12image_DataIsReady( dev, buf ))
791 						return SANE_STATUS_GOOD;
792 				}
793 			}
794 		}
795 
796 	} while( !u12io_CheckTimer( &timer ));
797 
798 	DBG( _DBG_ERROR, "Timeout - Scanner malfunction !!\n" );
799 	u12motor_ToHomePosition( dev, SANE_TRUE );
800 
801 	/* timed out, scanner malfunction */
802 	return SANE_STATUS_IO_ERROR;
803 }
804 
805 /**
806  */
u12image_PrepareScaling( U12_Device *dev )807 static void u12image_PrepareScaling( U12_Device *dev )
808 {
809 	int    step;
810 	double ratio;
811 
812 	dev->scaleBuf = NULL;
813 	DBG( _DBG_INFO, "APP-DPIX=%u, MAX-DPIX=%u\n",
814 		             dev->DataInf.xyAppDpi.x, dev->dpi_max_x );
815 
816 	if( dev->DataInf.xyAppDpi.x > dev->dpi_max_x ) {
817 
818 		dev->scaleBuf = malloc( dev->DataInf.dwAppBytesPerLine );
819 
820 		ratio = (double)dev->DataInf.xyAppDpi.x/(double)dev->dpi_max_x;
821 		dev->scaleIzoom = (int)(1.0/ratio * 1000);
822 
823 		switch( dev->DataInf.wAppDataType ) {
824 
825 			case COLOR_BW      : step = 0;  break;
826 			case COLOR_256GRAY : step = 1;  break;
827 			case COLOR_TRUE24  : step = 3;  break;
828 			case COLOR_TRUE42  : step = 6;  break;
829 			default			   : step = 99; break;
830 		}
831 		dev->scaleStep = step;
832 
833 		DBG( _DBG_INFO, "u12image_PrepareScaling: izoom=%i, step=%u\n",
834 		                dev->scaleIzoom, step );
835 	} else {
836 
837 		DBG( _DBG_INFO, "u12image_PrepareScaling: DISABLED\n" );
838 	}
839 }
840 
841 /** scaling picture data in x-direction, using a DDA algorithm
842  *  (digital differential analyzer).
843  */
u12image_ScaleX( U12_Device *dev, SANE_Byte *ib, SANE_Byte *ob )844 static void u12image_ScaleX( U12_Device *dev, SANE_Byte *ib, SANE_Byte *ob )
845 {
846 	SANE_Byte tmp;
847 	int       ddax;
848 	u_long    i, j, x;
849 
850 	/* when not supported, only copy the data */
851 	if( 99 == dev->scaleStep ) {
852 		memcpy( ob, ib, dev->DataInf.dwAppBytesPerLine );
853 		return;
854 	}
855 
856 	/* now scale... */
857 	if( 0 == dev->scaleStep ) {
858 
859 		/* binary scaling */
860 		ddax = 0;
861 		x    = 0;
862 		memset( ob, 0, dev->DataInf.dwAppBytesPerLine );
863 
864 		for( i = 0; i < dev->DataInf.dwPhysBytesPerLine*8; i++ ) {
865 
866 			ddax -= 1000;
867 
868 			while( ddax < 0 ) {
869 
870 				tmp = ib[(i>>3)];
871 
872 				if((x>>3) < dev->DataInf.dwAppBytesPerLine ) {
873 					if( 0 != (tmp &= (1 << ((~(i & 0x7))&0x7))))
874 						ob[x>>3] |= (1 << ((~(x & 0x7))&0x7));
875 				}
876 				x++;
877 				ddax += dev->scaleIzoom;
878 			}
879 		}
880 
881 	} else {
882 
883 		/* color and gray scaling */
884 		ddax = 0;
885 		x    = 0;
886 		for( i = 0; i < dev->DataInf.dwPhysBytesPerLine*dev->scaleStep;
887 		                                                  i+=dev->scaleStep ) {
888 
889 			ddax -= 1000;
890 
891 			while( ddax < 0 ) {
892 
893 				for( j = 0; j < (u_long)dev->scaleStep; j++ ) {
894 
895 					if((x+j) < dev->DataInf.dwAppBytesPerLine ) {
896 						ob[x+j] = ib[i+j];
897 					}
898 				}
899 				x    += dev->scaleStep;
900 				ddax += dev->scaleIzoom;
901 			}
902 		}
903 	}
904 }
905 
906 /* END U12_IMAGE.C ..........................................................*/
907