xref: /third_party/backends/backend/u12-image.c (revision 141cc406)
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
54static u_short wPreviewScanned = 0;
55
56static ExpXStepDef negScan[5] = {
57	{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
58};
59
60static ExpXStepDef posScan[5] = {
61	{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
62};
63
64static ExpXStepDef nmlScan[5] = {
65	{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96},
66};
67
68/*************************** local functions *********************************/
69
70/**
71 */
72static 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 */
124static 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 */
152static SANE_Bool fnEveryLine( U12_Device *dev )
153{
154	_VAR_NOT_USED( dev );
155	return SANE_TRUE;
156}
157
158static 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
169static 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 */
186static 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 */
194static 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 */
214static 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 */
235static 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 */
307static u_short
308u12image_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 */
329static 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 */
421static 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 */
477static 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 */
688static 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 */
732static 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 */
807static 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 */
844static 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