1 /*.............................................................................
2  * Project : SANE library for Plustek flatbed scanners.
3  *.............................................................................
4  */
5 
6 /** @file plustek-usbscan.c
7  *  @brief Scanning...
8  *
9  * Based on sources acquired from Plustek Inc.<br>
10  * Copyright (C) 2001-2013 Gerhard Jaeger <gerhard@gjaeger.de>
11  *
12  * History:
13  * - 0.40 - starting version of the USB support
14  * - 0.41 - minor fixes
15  * - 0.42 - added some stuff for CIS devices
16  * - 0.43 - no changes
17  * - 0.44 - added CIS specific settings and calculations
18  *        - removed usb_IsEscPressed
19  * - 0.45 - fixed the special setting stuff for CanoScan
20  *        - fixed pixel calculation for binary modes
21  *        - fixed cancel hang problem
22  *        - fixed CIS PhyBytes adjustment
23  *        - removed CanoScan specific setting stuff
24  * - 0.46 - fixed problem in usb_SetScanParameters()
25  * - 0.47 - no changes
26  * - 0.48 - minor fixes
27  * - 0.49 - a_bRegs is now part of the device structure
28  *        - using now PhyDpi.y as selector for the motor MCLK range
29  *        - changed usb_MapDownload prototype
30  * - 0.50 - cleanup
31  * - 0.51 - added usb_get_res() and usb_GetPhyPixels()
32  * - 0.52 - removed stuff, that will most probably never be used
33  * .
34  * <hr>
35  * This file is part of the SANE package.
36  *
37  * This program is free software; you can redistribute it and/or
38  * modify it under the terms of the GNU General Public License as
39  * published by the Free Software Foundation; either version 2 of the
40  * License, or (at your option) any later version.
41  *
42  * This program is distributed in the hope that it will be useful, but
43  * WITHOUT ANY WARRANTY; without even the implied warranty of
44  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
45  * General Public License for more details.
46  *
47  * You should have received a copy of the GNU General Public License
48  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
49  *
50  * As a special exception, the authors of SANE give permission for
51  * additional uses of the libraries contained in this release of SANE.
52  *
53  * The exception is that, if you link a SANE library with other files
54  * to produce an executable, this does not by itself cause the
55  * resulting executable to be covered by the GNU General Public
56  * License.  Your use of that executable is in no way restricted on
57  * account of linking the SANE library code into it.
58  *
59  * This exception does not, however, invalidate any other reasons why
60  * the executable file might be covered by the GNU General Public
61  * License.
62  *
63  * If you submit changes to SANE to the maintainers to be included in
64  * a subsequent release, you agree by submitting the changes that
65  * those changes may be distributed with this exception intact.
66  *
67  * If you write modifications of your own for SANE, it is your choice
68  * whether to permit this exception to apply to your modifications.
69  * If you do not wish that, delete this exception notice.
70  * <hr>
71  */
72 
73 #define DIVIDER 8
74 
75 /** array used to get motor-settings and mclk-settings
76  */
77 static int dpi_ranges[] = { 75,100,150,200,300,400,600,800,1200,2400 };
78 
79 static u_char     bMaxITA;
80 
81 static SANE_Bool  m_fAutoPark;
82 static SANE_Bool  m_fFirst;
83 static double     m_dHDPIDivider;
84 static double     m_dMCLKDivider;
85 static ScanParam *m_pParam;
86 static u_char     m_bLineRateColor;
87 static u_char     m_bCM;
88 static u_char	  m_bIntTimeAdjust;
89 static u_char	  m_bOldScanData;
90 static u_short    m_wFastFeedStepSize;
91 static u_short    m_wLineLength;
92 static u_short	  m_wStepSize;
93 static u_long     m_dwPauseLimit;
94 
95 static SANE_Bool  m_fStart = SANE_FALSE;
96 
97 /* Prototype... */
98 static SANE_Bool usb_DownloadShadingData( Plustek_Device*, u_char );
99 
100 /** returns the min of the two values val1 and val2
101  * @param val1 - first parameter
102  * @param val2 - second parameter
103  * @return val1 if val1 < val2, else val1
104  */
105 static u_long
usb_min(u_long val1,u_long val2)106 usb_min( u_long val1, u_long val2 )
107 {
108 	if( val1 > val2 )
109 		return val2;
110 	return val1;
111 }
112 
113 /** returns the max of the two values val1 and val2
114  * @param val1 - first parameter
115  * @param val2 - second parameter
116  * @return val1 if val1 > val2, else val2
117  */
118 static u_long
usb_max(u_long val1,u_long val2)119 usb_max( u_long val1, u_long val2 )
120 {
121 	if( val1 > val2 )
122 		return val1;
123 	return val2;
124 }
125 
126 /** function to get the possible resolution for a specific base resolution,
127  * according to the dividers a LM983x offers.
128  * @param base - scanners optical resolution
129  * @param idx  - which divider to use
130  */
131 static u_short
usb_get_res(u_short base,u_short idx)132 usb_get_res( u_short base, u_short idx )
133 {
134 	double div_list[DIVIDER] = { 12.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0 };
135 
136 	if( idx == 0 || idx > DIVIDER )
137 		return 0;
138 
139 	return (u_short)((double)base/div_list[idx-1]);
140 }
141 
142 /** Set the horizontal DPI divider.
143  * Affected registers:<br>
144  * 0x09 - Horizontal DPI divider HDPI_DIV<br>
145  *
146  * @param dev  - pointer to our device structure,
147  *               it should contain all we need
148  * @param xdpi - user specified horizontal resolution
149  * @return - the function returns the "normalized" horizontal resolution.
150  */
151 static u_short
usb_SetAsicDpiX(Plustek_Device * dev,u_short xdpi)152 usb_SetAsicDpiX( Plustek_Device *dev, u_short xdpi )
153 {
154 	u_short   res;
155 	ScanDef  *scanning = &dev->scanning;
156 	DCapsDef *scaps    = &dev->usbDev.Caps;
157 	u_char   *regs     = dev->usbDev.a_bRegs;
158 
159 	/* limit xdpi to lower value for certain devices...
160 	 */
161 	if( scaps->OpticDpi.x == 1200 &&
162 		scanning->sParam.bDataType != SCANDATATYPE_Color &&
163 		xdpi < 150 &&
164 		scanning->sParam.bDataType == SCANDATATYPE_BW ) {
165 		xdpi = 150;
166 		DBG( _DBG_INFO2, "* LIMIT XDPI to %udpi\n", xdpi );
167 	}
168 
169 	m_dHDPIDivider = (double)scaps->OpticDpi.x / xdpi;
170 
171 	if (m_dHDPIDivider < 1.5)
172 	{
173 		m_dHDPIDivider = 1.0;
174 		regs[0x09]  = 0;
175 	}
176 	else if (m_dHDPIDivider < 2.0)
177 	{
178 		m_dHDPIDivider = 1.5;
179 		regs[0x09]  = 1;
180 	}
181 	else if (m_dHDPIDivider < 3.0)
182 	{
183 		m_dHDPIDivider = 2.0;
184 		regs[0x09]  = 2;
185 	}
186 	else if (m_dHDPIDivider < 4.0)
187 	{
188 		m_dHDPIDivider = 3.0;
189 		regs[0x09]  = 3;
190 	}
191 	else if (m_dHDPIDivider < 6.0)
192 	{
193 		m_dHDPIDivider = 4.0;
194 		regs[0x09]  = 4;
195 	}
196 	else if (m_dHDPIDivider < 8.0)
197 	{
198 		m_dHDPIDivider = 6.0;
199 		regs[0x09]  = 5;
200 	}
201 	else if (m_dHDPIDivider < 12.0)
202 	{
203 		m_dHDPIDivider = 8.0;
204 		regs[0x09]  = 6;
205 	}
206 	else
207 	{
208 		m_dHDPIDivider = 12.0;
209 		regs[0x09]  = 7;
210 	}
211 
212 	/* adjust, if any turbo/preview mode is set, should be 0 here... */
213 	if( regs[0x0a] )
214 		regs[0x09] -= ((regs[0x0a] >> 2) + 2);
215 
216 	DBG( _DBG_INFO2, "* HDPI: %.3f\n", m_dHDPIDivider );
217 	res = (u_short)((double)scaps->OpticDpi.x / m_dHDPIDivider);
218 
219 	DBG( _DBG_INFO2, "* XDPI=%u, HDPI=%.3f\n", res, m_dHDPIDivider );
220 	return res;
221 }
222 
223 /**
224  * @param dev  - pointer to our device structure,
225  *               it should contain all we need
226  * @param ydpi - user specified vertical resolution
227  * @return -
228  */
229 static u_short
usb_SetAsicDpiY(Plustek_Device * dev,u_short ydpi)230 usb_SetAsicDpiY( Plustek_Device *dev, u_short ydpi )
231 {
232 	ScanDef  *scanning = &dev->scanning;
233 	DCapsDef *sCaps    = &dev->usbDev.Caps;
234 	HWDef    *hw       = &dev->usbDev.HwSetting;
235 
236 	u_short wMinDpi, wDpi;
237 
238 	if(0 != sCaps->bSensorDistance )
239 		wMinDpi = sCaps->OpticDpi.y / sCaps->bSensorDistance;
240 	else
241 		wMinDpi = 75;
242 
243 	/* Here we might have to check against the MinDpi value ! */
244 	wDpi = (ydpi + wMinDpi - 1) / wMinDpi * wMinDpi;
245 
246 	/*
247 	 * HEINER: added '*2'
248 	 */
249 	if( wDpi > sCaps->OpticDpi.y * 2 )
250 		wDpi = sCaps->OpticDpi.y * 2;
251 
252 	if( (hw->motorModel == MODEL_Tokyo600) ||
253 		!_IS_PLUSTEKMOTOR(hw->motorModel)) {
254 		/* return wDpi; */
255 	} else if( sCaps->wFlags & DEVCAPSFLAG_Adf && sCaps->OpticDpi.x == 600 ) {
256 		/* for ADF scanner color mode 300 dpi big noise */
257 		if( scanning->sParam.bDataType == SCANDATATYPE_Color &&
258 			scanning->sParam.bBitDepth > 8 && wDpi < 300 ) {
259 			wDpi = 300;
260 		}
261 	} else if( sCaps->OpticDpi.x == 1200 ) {
262 		if( scanning->sParam.bDataType != SCANDATATYPE_Color && wDpi < 200) {
263 			wDpi = 200;
264 		}
265 	}
266 
267 	DBG( _DBG_INFO2, "* YDPI=%u, MinDPIY=%u\n", wDpi, wMinDpi );
268 	return wDpi;
269 }
270 
271 /** set color mode and sensor configuration stuff, according to the data mode
272  * Affected registers:<br>
273  * 0x26 - 0x27 - Color Mode settings<br>
274  * 0x0f - 0x18 - Sensor Configuration - directly from the HwDefs<br>
275  * 0x09        - add Data Mode and Pixel Packing<br>
276  *
277  * @param dev    - pointer to our device structure,
278  *                 it should contain all we need
279  * @param pParam - pointer to the current scan parameters
280  * @return - Nothing
281  */
282 static void
usb_SetColorAndBits(Plustek_Device * dev,ScanParam * pParam)283 usb_SetColorAndBits( Plustek_Device *dev, ScanParam *pParam )
284 {
285 	HWDef    *hw   = &dev->usbDev.HwSetting;
286 	u_char   *regs = dev->usbDev.a_bRegs;
287 
288 	/* Set pixel packing, data mode and AFE operation */
289 	switch( pParam->bDataType ) {
290 		case SCANDATATYPE_Color:
291 			m_bCM = 3;
292 			regs[0x26] = hw->bReg_0x26 & 0x7;
293 
294 			/* if set to one channel color, we select the blue channel
295 			 * as input source, this is the default, but I don't know
296 			 * what happens, if we deselect this
297 			 */
298 			if( regs[0x26] & _ONE_CH_COLOR )
299 				regs[0x26] |= (_BLUE_CH | 0x01);
300 
301 			memcpy( &regs[0x0f], hw->bReg_0x0f_Color, 10 );
302 			break;
303 
304 		case SCANDATATYPE_Gray:
305 			m_bCM = 1;
306 			regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
307 			memcpy( &regs[0x0f], hw->bReg_0x0f_Mono, 10 );
308 			break;
309 
310 		case SCANDATATYPE_BW:
311 			m_bCM = 1;
312 			regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
313 			memcpy( &regs[0x0f], hw->bReg_0x0f_Mono, 10 );
314 			break;
315 	}
316 
317 	regs[0x27] = hw->bReg_0x27;
318 
319 	if( pParam->bBitDepth > 8 ) {
320 		regs[0x09] |= 0x20;         /* 14/16bit image data */
321 
322 	} else if( pParam->bBitDepth == 8 ) {
323 		regs[0x09] |= 0x18;        /* 8bits/per pixel */
324 	}
325 }
326 
327 /**
328  * Data output from NS983X should be times of 2-byte and every line
329  * will append 2 status bytes
330  */
331 static void
usb_GetPhyPixels(Plustek_Device * dev,ScanParam * sp)332 usb_GetPhyPixels( Plustek_Device *dev, ScanParam *sp )
333 {
334 	sp->Size.dwValidPixels = sp->Size.dwPixels * sp->PhyDpi.x / sp->UserDpi.x;
335 
336 	if (sp->bBitDepth == 1) {
337 
338 		/* Pixels should be times of 16 */
339 		sp->Size.dwPhyPixels =
340 		            (sp->Size.dwValidPixels + 15UL) & 0xfffffff0UL;
341 		sp->Size.dwPhyBytes = sp->Size.dwPhyPixels / 8UL + 2UL;
342 
343 	} else if (sp->bBitDepth == 8) {
344 
345 		/* Pixels should be times of 2 */
346 		sp->Size.dwPhyPixels = (sp->Size.dwValidPixels + 1UL) & 0xfffffffeUL;
347 		sp->Size.dwPhyBytes  = sp->Size.dwPhyPixels * sp->bChannels + 2UL;
348 
349 		/* need to be adjusted for CIS devices in color mode */
350 		if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
351 			sp->Size.dwPhyBytes *= 3;
352 		}
353 	}
354 	else /* sp->bBitDepth == 16 */
355 	{
356 		sp->Size.dwPhyPixels = sp->Size.dwValidPixels;
357 		sp->Size.dwPhyBytes  = sp->Size.dwPhyPixels * 2 * sp->bChannels + 2UL;
358 
359 		/* need to be adjusted for CIS devices in color mode */
360 		if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
361 			sp->Size.dwPhyBytes *= 3;
362 		}
363 	}
364 }
365 
366 /** Calculate basic image settings like the number of physical bytes per line
367  * etc...
368  * Affected registers:<br>
369  * 0x22/0x23 - Data Pixels Start<br>
370  * 0x24/0x25 - Data Pixels End<br>
371  * 0x4a/0x4b - Full Steps to Skip at Start of Scan
372  *
373  * @param dev    - pointer to our device structure,
374  *                 it should contain all we need
375  * @param pParam - pointer to the current scan parameters
376  * @return - Nothing
377  */
378 static void
usb_GetScanRect(Plustek_Device * dev,ScanParam * sp)379 usb_GetScanRect( Plustek_Device *dev, ScanParam *sp )
380 {
381 	u_short   wDataPixelStart, wLineEnd;
382 
383 	DCapsDef *sCaps = &dev->usbDev.Caps;
384 	HWDef    *hw    = &dev->usbDev.HwSetting;
385 	u_char   *regs  = dev->usbDev.a_bRegs;
386 
387 	/* Convert pixels to physical dpi based */
388 	usb_GetPhyPixels( dev, sp );
389 
390 	/* Compute data start pixel */
391 #if 0
392 /* HEINER: check ADF stuff... */
393 	if(sp->bCalibration != PARAM_Gain &&
394 		sp->bCalibration != PARAM_Offset && ScanInf.m_fADF)
395 		wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
396 				(u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
397 	else
398 #endif
399 		wDataPixelStart = (u_short)((u_long)sp->Origin.x *
400 		                                            sCaps->OpticDpi.x / 300UL);
401 
402 	/* during the calibration steps, we read the entire CCD data
403 	 */
404 	if((sp->bCalibration != PARAM_Gain)&&(sp->bCalibration != PARAM_Offset)) {
405 /* HEINER: check ADF stuff... */
406 #if 0
407 		if(ScanInf.m_fADF) {
408 			wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
409 			    (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
410 		}
411 #endif
412 		wDataPixelStart += hw->wActivePixelsStart;
413 	}
414 
415 	wLineEnd = wDataPixelStart + (u_short)(m_dHDPIDivider *
416 	                                               sp->Size.dwPhyPixels + 0.5);
417 
418 	DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u\n",
419 	                                               wDataPixelStart, wLineEnd );
420 	if( wDataPixelStart & 1 ) {
421 
422 		wDataPixelStart++;
423 		wLineEnd++;
424 
425 		DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u (ADJ)\n",
426 		                                           wDataPixelStart, wLineEnd );
427 	}
428 
429 	regs[0x22] = _HIBYTE( wDataPixelStart );
430 	regs[0x23] = _LOBYTE( wDataPixelStart );
431 
432 	/* should match: wLineEnd-wDataPixelStart%(m_dHDPIDivider*2) = 0!! */
433 	regs[0x24] = _HIBYTE( wLineEnd );
434 	regs[0x25] = _LOBYTE( wLineEnd );
435 
436 	DBG( _DBG_INFO2, ">> End-Start=%u, HDPI=%.2f\n",
437 	                                 wLineEnd-wDataPixelStart, m_dHDPIDivider);
438 
439 	/* Y origin */
440 	if( sp->bCalibration == PARAM_Scan ) {
441 
442 		if( hw->motorModel == MODEL_Tokyo600 ) {
443 
444 			if(sp->PhyDpi.x <= 75)
445 				sp->Origin.y += 20;
446 			else if(sp->PhyDpi.x <= 100)
447 			{
448 				if (sp->bDataType == SCANDATATYPE_Color)
449 					sp->Origin.y += 0;
450 				else
451 					sp->Origin.y -= 6;
452 			}
453 			else if(sp->PhyDpi.x <= 150)
454 			{
455 				if (sp->bDataType == SCANDATATYPE_Color)
456 					sp->Origin.y -= 0;
457 			}
458 			else if(sp->PhyDpi.x <= 200)
459 			{
460 				if (sp->bDataType == SCANDATATYPE_Color)
461 					sp->Origin.y -= 10;
462 				else
463 					sp->Origin.y -= 4;
464 			}
465 			else if(sp->PhyDpi.x <= 300)
466 			{
467 				if (sp->bDataType == SCANDATATYPE_Color)
468 					sp->Origin.y += 16;
469 				else
470 					sp->Origin.y -= 18;
471 			}
472 			else if(sp->PhyDpi.x <= 400)
473 			{
474 				if (sp->bDataType == SCANDATATYPE_Color)
475 					sp->Origin.y += 15;
476 				else if(sp->bDataType == SCANDATATYPE_BW)
477 					sp->Origin.y += 4;
478 			}
479 			else /* if(sp->PhyDpi.x <= 600) */
480 			{
481 				if (sp->bDataType == SCANDATATYPE_Gray)
482 					sp->Origin.y += 4;
483 			}
484 		}
485 
486 		/* Add gray mode offset (Green offset, we assume the CCD are
487 		 * always be RGB or BGR order).
488 		 */
489 		if (sp->bDataType != SCANDATATYPE_Color)
490 			sp->Origin.y += (u_long)(300UL *
491 			           sCaps->bSensorDistance / sCaps->OpticDpi.y);
492 	}
493 
494 	sp->Origin.y=(u_short)((u_long)sp->Origin.y * hw->wMotorDpi/300UL);
495 
496 	/* Something wrong, but I can not find it. */
497 	if( hw->motorModel == MODEL_HuaLien && sCaps->OpticDpi.x == 600)
498 		sp->Origin.y = sp->Origin.y * 297 / 298;
499 
500 	DBG(_DBG_INFO2,"* Full Steps to Skip at Start = 0x%04x\n",
501 	                sp->Origin.y);
502 
503 	regs[0x4a] = _HIBYTE( sp->Origin.y );
504 	regs[0x4b] = _LOBYTE( sp->Origin.y );
505 }
506 
507 /** preset scan stepsize and fastfeed stepsize
508  */
509 static void
usb_PresetStepSize(Plustek_Device * dev,ScanParam * pParam)510 usb_PresetStepSize( Plustek_Device *dev, ScanParam *pParam )
511 {
512 	u_short ssize;
513 	double  mclkdiv = pParam->dMCLK;
514 	HWDef  *hw      = &dev->usbDev.HwSetting;
515 	u_char *regs    = dev->usbDev.a_bRegs;
516 
517 	ssize = (u_short)((double)CRYSTAL_FREQ / ( mclkdiv * 8.0 *
518             (double)m_bCM * hw->dMaxMotorSpeed * 4.0 * (double)hw->wMotorDpi));
519 
520 	regs[0x46] = _HIBYTE( ssize );
521 	regs[0x47] = _LOBYTE( ssize );
522 	regs[0x48] = _HIBYTE( ssize );
523 	regs[0x49] = _LOBYTE( ssize );
524 
525 	DBG( _DBG_INFO2, "* StepSize(Preset) = %u (0x%04x)\n", ssize, ssize );
526 }
527 
528 /** calculate default phase difference DPD
529  */
530 static void
usb_GetDPD(Plustek_Device * dev)531 usb_GetDPD( Plustek_Device *dev  )
532 {
533 	int    qtcnt;	/* quarter speed count count reg 51 b2..3 */
534 	int    hfcnt;	/* half speed count reg 51 b0..1          */
535 	int    strev;   /* steps to reverse reg 50                */
536 	int    dpd;     /* calculated dpd reg 52:53               */
537 	int    st;      /* step size reg 46:47                    */
538 
539 	HWDef  *hw    = &dev->usbDev.HwSetting;
540 	u_char *regs  = dev->usbDev.a_bRegs;
541 
542 	qtcnt = (regs[0x51] & 0x30) >> 4;  /* quarter speed count */
543 	hfcnt = (regs[0x51] & 0xc0) >> 6;  /* half speed count    */
544 
545 	if( _LM9831 == hw->chip )
546 		strev = regs[0x50] & 0x3f;    /* steps to reverse */
547 	else /* LM9832/3 */
548 	{
549 		if (qtcnt == 3)
550 			qtcnt = 8;
551 		if (hfcnt == 3)
552 			hfcnt = 8;
553 		strev = regs[0x50];           /* steps to reverse */
554 	}
555 
556 	st = regs[0x46] * 256 + regs[0x47];     /* scan step size */
557 
558 	if (m_wLineLength == 0)
559 		dpd = 0;
560 	else
561 	{
562 		dpd = (((qtcnt * 4) + (hfcnt * 2) + strev) * 4 * st) %
563 		                            (m_wLineLength * m_bLineRateColor);
564 		DBG( _DBG_INFO2, "* DPD =%u (0x%04x)\n", dpd, dpd );
565 		dpd = m_wLineLength * m_bLineRateColor - dpd;
566 	}
567 
568 	DBG( _DBG_INFO2, "* DPD =%u (0x%04x), step size=%u, steps2rev=%u\n",
569 	                  dpd, dpd, st, strev);
570 	DBG( _DBG_INFO2, "* llen=%u, lineRateColor=%u, qtcnt=%u, hfcnt=%u\n",
571 	                  m_wLineLength, m_bLineRateColor, qtcnt, hfcnt );
572 
573 	regs[0x51] |= (u_char)((dpd >> 16) & 0x03);
574 	regs[0x52] = (u_char)(dpd >> 8);
575 	regs[0x53] = (u_char)(dpd & 0xFF);
576 }
577 
578 #define MCLKDIV_SCALING 2
579 #define _MIN(a,b) ((a) < (b) ? (a) : (b))
580 #define _MAX(a,b) ((a) > (b) ? (a) : (b))
581 
582 /**
583  */
584 static int
usb_GetMCLKDiv(Plustek_Device * dev)585 usb_GetMCLKDiv( Plustek_Device *dev )
586 {
587 	int     j, pixelbits, pixelsperline, r;
588 	int     minmclk, maxmclk, mclkdiv;
589 	double  hdpi, min_int_time;
590 	u_char *regs = dev->usbDev.a_bRegs;
591 	HWDef  *hw   = &dev->usbDev.HwSetting;
592 
593 	DBG( _DBG_INFO, "usb_GetMCLKDiv()\n" );
594 
595 	r = 8; /* line rate */
596 	if ((regs[0x26] & 7) == 0)
597 		r = 24; /* pixel rate */
598 
599 	/* use high or low res min integration time */
600 	min_int_time = ((regs[0x9]&7) > 2 ? hw->dMinIntegrationTimeLowres:
601 	                                    hw->dMinIntegrationTimeHighres);
602 
603 	minmclk = (int)ceil((double) MCLKDIV_SCALING * CRYSTAL_FREQ *
604 	                       min_int_time /((double)1000. * r * m_wLineLength));
605 	minmclk = _MAX(minmclk,MCLKDIV_SCALING);
606 
607 	maxmclk = (int)(32.5*MCLKDIV_SCALING + .5);
608 
609 	DBG(_DBG_INFO2,"- lower mclkdiv limit=%f\n",(double)minmclk/MCLKDIV_SCALING);
610 	DBG(_DBG_INFO2,"- upper mclkdiv limit=%f\n",(double)maxmclk/MCLKDIV_SCALING);
611 
612 	/* get the bits per pixel */
613 	switch (regs[0x9] & 0x38) {
614 		case 0:	    pixelbits=1; break;
615 		case 0x8:   pixelbits=2; break;
616 		case 0x10:  pixelbits=4; break;
617 		case 0x18:  pixelbits=8; break;
618 		default:	pixelbits=16;break;
619 	}
620 
621 	/* compute the horizontal dpi (pixels per inch) */
622 	j    = regs[0x9] & 0x7;
623 	hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1);
624 
625 	pixelsperline = (int)((256*regs[0x24]+regs[0x25]-256*regs[0x22]-regs[0x23])
626 	                       *pixelbits/(hdpi * 8));
627 	mclkdiv = (int)ceil((double)MCLKDIV_SCALING * pixelsperline * CRYSTAL_FREQ
628 	                /((double) 8. * m_wLineLength * dev->transferRate));
629 
630 	DBG( _DBG_INFO2, "- hdpi          = %.3f\n", hdpi );
631 	DBG( _DBG_INFO2, "- pixelbits     = %u\n", pixelbits );
632 	DBG( _DBG_INFO2, "- pixelsperline = %u\n", pixelsperline );
633 	DBG( _DBG_INFO2, "- linelen       = %u\n", m_wLineLength );
634 	DBG( _DBG_INFO2, "- transferrate  = %lu\n", dev->transferRate );
635 	DBG( _DBG_INFO2, "- MCLK Divider  = %u\n", mclkdiv/MCLKDIV_SCALING );
636 
637 	mclkdiv = _MAX(mclkdiv,minmclk);
638 	mclkdiv = _MIN(mclkdiv,maxmclk);
639 	DBG( _DBG_INFO2, "- Current MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING );
640 
641 	if( dev->transferRate == 2000000 ) {
642 		while (mclkdiv * hdpi < 6.*MCLKDIV_SCALING) {
643 			mclkdiv++;
644 		}
645 		DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n",
646 		     mclkdiv/MCLKDIV_SCALING );
647 	}
648 
649 	return mclkdiv;
650 }
651 
652 /** Plusteks' poor-man MCLK calculation...
653  * at least we give the master clock divider and adjust the step size
654  * and integration time (for 14/16 bit modes)
655  */
656 static double
usb_GetMCLKDivider(Plustek_Device * dev,ScanParam * pParam)657 usb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam )
658 {
659 	double dMaxIntegrationTime;
660 	double dMaxMCLKDivider;
661 
662 	DCapsDef *sCaps = &dev->usbDev.Caps;
663 	HWDef    *hw    = &dev->usbDev.HwSetting;
664 	u_char   *regs  = dev->usbDev.a_bRegs;
665 
666 	DBG( _DBG_INFO, "usb_GetMCLKDivider()\n" );
667 
668 	if( dev->transferRate == 2000000 ) {
669 		int mclkdiv = usb_GetMCLKDiv(dev);
670 		pParam->dMCLK = (double)mclkdiv/MCLKDIV_SCALING;
671 	}
672 
673 	m_dMCLKDivider = pParam->dMCLK;
674 
675 	if (m_dHDPIDivider*m_dMCLKDivider >= 5.3/*6*/)
676 		m_bIntTimeAdjust = 0;
677 	else
678 		m_bIntTimeAdjust = ceil( 5.3/*6.0*/ / (m_dHDPIDivider*m_dMCLKDivider));
679 
680 	if( pParam->bCalibration == PARAM_Scan ) {
681 
682 		usb_GetMCLKDiv(dev);
683 
684 		/*  Compare Integration with USB speed to find the best ITA value */
685 		if( pParam->bBitDepth > 8 )	{
686 
687 			while( pParam->Size.dwPhyBytes >
688 			       (m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) *
689  			       (1 + m_bIntTimeAdjust)) {
690 				m_bIntTimeAdjust++;
691 			}
692 
693 			if( hw->motorModel == MODEL_HuaLien &&
694 				sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) {
695 				m_bIntTimeAdjust = bMaxITA;
696 			}
697 
698 			if(((hw->motorModel == MODEL_HP) && (sCaps->bCCD == kNECSLIM))/* ||
699 			 	( regs[0x26] & _ONE_CH_COLOR )*/) {
700 
701 				bMaxITA = (u_char)floor((m_dMCLKDivider + 1) / 2.0);
702 
703 				DBG( _DBG_INFO2, "* MaxITA (HP) = %u\n", bMaxITA );
704 				if( m_bIntTimeAdjust > bMaxITA ) {
705 					DBG( _DBG_INFO, "* ITA (%u) limited\n", m_bIntTimeAdjust );
706 					m_bIntTimeAdjust = bMaxITA;
707 				}
708 			}
709 		}
710 	}
711 	DBG( _DBG_INFO2, "* Integration Time Adjust = %u (HDPI=%.3f,MCLKD=%.3f)\n",
712 	                    m_bIntTimeAdjust, m_dHDPIDivider, m_dMCLKDivider );
713 
714 	regs[0x08] = (u_char)((m_dMCLKDivider - 1) * 2);
715 	regs[0x19] = m_bIntTimeAdjust;
716 
717 	if( m_bIntTimeAdjust != 0 ) {
718 
719 		m_wStepSize = (u_short)((u_long) m_wStepSize *
720 		                    (m_bIntTimeAdjust + 1) / m_bIntTimeAdjust);
721 		if( m_wStepSize < 2 )
722 			m_wStepSize = 2;
723 
724 		regs[0x46] = _HIBYTE(m_wStepSize);
725 		regs[0x47] = _LOBYTE(m_wStepSize);
726 
727 		DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
728 		                   m_wStepSize, regs[0x46], regs[0x47] );
729 	    usb_GetDPD( dev );
730 	}
731 
732 	/* Compute maximum MCLK divider base on maximum integration time for
733 	 * high lamp PWM, use equation 4
734 	 */
735 	dMaxIntegrationTime = hw->dIntegrationTimeHighLamp;
736 	dMaxMCLKDivider = (double)CRYSTAL_FREQ * dMaxIntegrationTime /
737 	                                    (1000 * 8 * m_bCM * m_wLineLength);
738 
739 	/* Determine lamp PWM setting */
740 	if( m_dMCLKDivider > dMaxMCLKDivider ) {
741 
742 		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleLow\n" );
743 		regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleLow );
744 		regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleLow );
745 
746 	} else {
747 
748 		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleHigh\n" );
749 		regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleHigh );
750 		regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleHigh );
751 	}
752 
753 	DBG( _DBG_INFO2, "* Current MCLK Divider = %f\n", m_dMCLKDivider );
754 	return m_dMCLKDivider;
755 }
756 
757 /** calculate the step size of each scan step
758  */
759 static void
usb_GetStepSize(Plustek_Device * dev,ScanParam * pParam)760 usb_GetStepSize( Plustek_Device *dev, ScanParam *pParam )
761 {
762 	HWDef  *hw  = &dev->usbDev.HwSetting;
763 	u_char *regs = dev->usbDev.a_bRegs;
764 
765 	/* Compute step size using equation 1 */
766 	if (m_bIntTimeAdjust != 0) {
767 		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
768 		              m_bLineRateColor * (m_bIntTimeAdjust + 1)) /
769 		              (4 * hw->wMotorDpi * m_bIntTimeAdjust));
770 	} else {
771 		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
772 		               m_bLineRateColor) / (4 * hw->wMotorDpi));
773 	}
774 
775 	if (m_wStepSize < 2)
776 		m_wStepSize = 2;
777 
778 	m_wStepSize = m_wStepSize * 298 / 297;
779 
780 	regs[0x46] = _HIBYTE( m_wStepSize );
781 	regs[0x47] = _LOBYTE( m_wStepSize );
782 
783 	DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
784 	                  m_wStepSize, regs[0x46], regs[0x47] );
785 }
786 
787 /**
788  */
789 static void
usb_GetLineLength(Plustek_Device * dev,ScanParam * param)790 usb_GetLineLength( Plustek_Device *dev, ScanParam *param )
791 {
792 /* [note]
793  *  The ITA in this moment is always 0, it will be changed later when we
794  *  calculate MCLK. This is very strange why this routine will not call
795  *  again to get all new value after ITA was changed? If this routine
796  *  never call again, maybe we remove all factor with ITA here.
797  */
798 	int tr;
799 	int tpspd;  /* turbo/preview mode speed reg 0a b2..3                 */
800 	int tpsel;  /* turbo/preview mode select reg 0a b0..1                */
801 	int gbnd;   /* guardband duration reg 0e b4..7                       */
802 	int dur;    /* pulse duration reg 0e b0..3                           */
803 	int ntr;    /* number of tr pulses reg 0d b7                         */
804 	int afeop;  /* scan mode, 0=pixel rate, 1=line rate,                 */
805 	            /* 4=1 channel mode a, 5=1 channel mode b, reg 26 b0..2  */
806 	int ctmode; /* CIS tr timing mode reg 19 b0..1                       */
807 	int tp;     /* tpspd or 1 if tpsel=0                                 */
808 	int b;      /* if ctmode=0, (ntr+1)*((2*gbnd)+dur+1), otherwise 1    */
809 	int tradj;  /* ITA                                                   */
810 	int en_tradj;
811 	u_short      le;
812 	HWDef       *hw    = &dev->usbDev.HwSetting;
813 	ClkMotorDef *motor = usb_GetMotorSet( hw->motorModel );
814 	u_char      *regs  = dev->usbDev.a_bRegs;
815 
816 	tpspd = (regs[0x0a] & 0x0c) >> 2;       /* turbo/preview mode speed  */
817 	tpsel = regs[0x0a] & 3;                 /* turbo/preview mode select */
818 
819 	gbnd = (regs[0x0e] & 0xf0) >> 4;        /* TR fi1 guardband duration */
820 	dur = (regs[0x0e] & 0xf);               /* TR pulse duration         */
821 
822 	ntr = regs[0x0d] / 128;                 /* number of tr pulses       */
823 
824 	afeop = regs[0x26] & 7;           /* afe op - 3 channel or 1 channel */
825 
826 	tradj = regs[0x19] & 0x7f;                /* integration time adjust */
827 	en_tradj = (tradj) ? 1 : 0;
828 
829 	ctmode = (regs[0x0b] >> 3) & 3;                /* cis tr timing mode */
830 
831 	m_bLineRateColor = 1;
832 	if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */
833 		m_bLineRateColor = 3;
834 
835 	/* according to turbo/preview mode to set value */
836 	if( tpsel == 0 ) {
837 		tp = 1;
838 	} else {
839 		tp = tpspd + 2;
840 		if( tp == 5 )
841 			tp++;
842 	}
843 
844 	b = 1;
845 	if( ctmode == 0 ) { /* CCD mode scanner*/
846 
847 		b  = (ntr + 1) * ((2 * gbnd) + dur + 1);
848 		b += (1 - ntr) * en_tradj;
849 	}
850 	if( ctmode == 2 )   /* CIS mode scanner */
851 	    b = 3;
852 
853 	/* it might be necessary to tweak this value, to keep the
854 	 * MCLK constant - see some sheet-fed devices
855 	 */
856 	le = hw->wLineEnd;
857 	if (motor->dpi_thresh != 0) {
858 		if( param->PhyDpi.y <= motor->dpi_thresh) {
859 			le = motor->lineend;
860 			DBG( _DBG_INFO2, "* Adjusting lineend: %u\n", le);
861 		}
862 		regs[0x20] = _HIBYTE( le );
863 		regs[0x21] = _LOBYTE( le );
864 	}
865 
866 	tr = m_bLineRateColor * (le + tp * (b + 3 - ntr));
867 
868 	if( tradj == 0 ) {
869 		if( ctmode == 0 )
870 			tr += m_bLineRateColor;
871 	} else {
872 
873 		int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix;
874 
875 		/* Line color or gray mode */
876 		if( afeop != 0 ) {
877 
878 			le_phi      = (tradj + 1) / 2 + 1 + 6;
879 			num_byteclk = ((le_phi + 8 * le + 8 * b + 4) /
880 						   (8 * tradj)) + 1;
881 			num_mclkf   = 8 * tradj * num_byteclk;
882 			tr_fast_pix = num_byteclk;
883 			extra_pix   = (num_mclkf - le_phi) % 8;
884 		}
885 		else /* 3 channel pixel rate color */
886 		{
887 			le_phi      = (tradj + 1) / 2 + 1 + 10 + 12;
888 			num_byteclk = ((le_phi + 3 * 8 * le + 3 * 8 * b + 3 * 4) /
889 						   (3 * 8 * tradj)) + 1;
890 			num_mclkf   = 3 * 8 * tradj * num_byteclk;
891 			tr_fast_pix = num_byteclk;
892 			extra_pix   = (num_mclkf - le_phi) % (3 * 8);
893 		}
894 
895 		tr = b + le + 4 + tr_fast_pix;
896 		if (extra_pix == 0)
897 			tr++;
898 		tr *= m_bLineRateColor;
899 	}
900 	m_wLineLength = tr / m_bLineRateColor;
901 
902 	DBG( _DBG_INFO2, "* LineLength=%d, LineRateColor=%u\n",
903 	                    m_wLineLength, m_bLineRateColor );
904 }
905 
906 /** usb_GetMotorParam
907  * registers 0x56, 0x57
908  */
909 static void
usb_GetMotorParam(Plustek_Device * dev,ScanParam * pParam)910 usb_GetMotorParam( Plustek_Device *dev, ScanParam *pParam )
911 {
912 	int          idx, i;
913 	ClkMotorDef *clk;
914 	MDef        *md;
915 	DCapsDef    *sCaps = &dev->usbDev.Caps;
916 	HWDef       *hw    = &dev->usbDev.HwSetting;
917 	u_char      *regs  = dev->usbDev.a_bRegs;
918 
919 	if (!_IS_PLUSTEKMOTOR(hw->motorModel)) {
920 
921 		clk = usb_GetMotorSet( hw->motorModel );
922 		md  = clk->motor_sets;
923 		idx = 0;
924 		for( i = 0; i < _MAX_CLK; i++ ) {
925 			if( pParam->PhyDpi.y <= dpi_ranges[i] )
926 				break;
927 			idx++;
928 		}
929 		if( idx >= _MAX_CLK )
930 			idx = _MAX_CLK - 1;
931 
932 		regs[0x56] = md[idx].pwm;
933 		regs[0x57] = md[idx].pwm_duty;
934 
935 		regs[0x43] = 0;
936 		regs[0x44] = 0;
937 
938 		if( md[idx].scan_lines_per_line > 1 ) {
939 
940 			if((pParam->bBitDepth > 8) &&
941 				(pParam->bDataType == SCANDATATYPE_Color)) {
942 
943 				regs[0x43] = 0xff;
944 				regs[0x44] = md[idx].scan_lines_per_line;
945 
946 				DBG( _DBG_INFO2, "* Line Skipping : 0x43=0x%02x, 0x44=0x%02x\n",
947 				                  regs[0x43], regs[0x44] );
948 			}
949 		}
950 	} else {
951 
952 		if( sCaps->OpticDpi.x == 1200 ) {
953 
954 			switch( hw->motorModel ) {
955 
956 			case MODEL_HuaLien:
957 			case MODEL_KaoHsiung:
958 			default:
959 				if(pParam->PhyDpi.x <= 200)
960 				{
961 					regs[0x56] = 1;
962 					regs[0x57] = 48;  /* 63; */
963 				}
964 				else if(pParam->PhyDpi.x <= 300)
965 				{
966 					regs[0x56] = 2;   /* 8;  */
967 					regs[0x57] = 48;  /* 56; */
968 				}
969 				else if(pParam->PhyDpi.x <= 400)
970 				{
971 					regs[0x56] = 8;
972 					regs[0x57] = 48;
973 				}
974 				else if(pParam->PhyDpi.x <= 600)
975 				{
976 					regs[0x56] = 2;   /* 10; */
977 					regs[0x57] = 48;  /* 56; */
978 				}
979 				else /* pParam->PhyDpi.x == 1200) */
980 				{
981 					regs[0x56] = 1;   /* 8;  */
982 					regs[0x57] = 48;  /* 56; */
983 				}
984 				break;
985         	}
986         } else {
987         	switch ( hw->motorModel ) {
988 
989         	case MODEL_Tokyo600:
990         		regs[0x56] = 16;
991         		regs[0x57] = 4;	/* 2; */
992         		break;
993         	case MODEL_HuaLien:
994         		{
995         			if(pParam->PhyDpi.x <= 200)
996         			{
997         				regs[0x56] = 64;	/* 24; */
998         				regs[0x57] = 4;	/* 16; */
999         			}
1000         			else if(pParam->PhyDpi.x <= 300)
1001         			{
1002         				regs[0x56] = 64;	/* 16; */
1003         				regs[0x57] = 4;	/* 16; */
1004         			}
1005         			else if(pParam->PhyDpi.x <= 400)
1006         			{
1007         				regs[0x56] = 64;	/* 16; */
1008         				regs[0x57] = 4;	/* 16; */
1009         			}
1010         			else /* if(pParam->PhyDpi.x <= 600) */
1011         			{
1012 /* HEINER: check ADF stuff... */
1013 #if 0
1014         				if(ScanInf.m_fADF)
1015         				{
1016         					regs[0x56] = 8;
1017         					regs[0x57] = 48;
1018         				}
1019         				else
1020 #endif
1021         				{
1022         					regs[0x56] = 64;	/* 2;  */
1023         					regs[0x57] = 4;	/* 48; */
1024         				}
1025         			}
1026         		}
1027         		break;
1028         	case MODEL_KaoHsiung:
1029         	default:
1030         		if(pParam->PhyDpi.x <= 200)
1031         		{
1032         			regs[0x56] = 24;
1033         			regs[0x57] = 16;
1034         		}
1035         		else if(pParam->PhyDpi.x <= 300)
1036         		{
1037         			regs[0x56] = 16;
1038         			regs[0x57] = 16;
1039         		}
1040         		else if(pParam->PhyDpi.x <= 400)
1041         		{
1042         			regs[0x56] = 16;
1043         			regs[0x57] = 16;
1044         		}
1045         		else /* if(pParam->PhyDpi.x <= 600) */
1046         		{
1047         			regs[0x56] = 2;
1048         			regs[0x57] = 48;
1049         		}
1050         		break;
1051         	}
1052         }
1053 	}
1054 
1055 	DBG( _DBG_INFO2, "* MOTOR-Settings: PWM=0x%02x, PWM_DUTY=0x%02x\n",
1056 	                 regs[0x56], regs[0x57] );
1057 }
1058 
1059 /**
1060  */
1061 static void
usb_GetPauseLimit(Plustek_Device * dev,ScanParam * pParam)1062 usb_GetPauseLimit( Plustek_Device *dev, ScanParam *pParam )
1063 {
1064 	int     coeffsize, scaler;
1065 	HWDef  *hw   = &dev->usbDev.HwSetting;
1066 	u_char *regs = dev->usbDev.a_bRegs;
1067 
1068 	scaler = 1;
1069 	if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1070 		if( pParam->bDataType == SCANDATATYPE_Color ) {
1071 			scaler = 3;
1072 		}
1073 	}
1074 
1075 	/* compute size of coefficient ram */
1076 	coeffsize = 4 + 16 + 16;	/* gamma and shading and offset */
1077 
1078 	/* if 16 bit, then not all is used */
1079 	if( regs[0x09] & 0x20 ) {
1080 		coeffsize = 16 + 16;	/* no gamma */
1081 	}
1082 	coeffsize *= (2*3); /* 3 colors and 2 bytes/word */
1083 
1084 
1085 	/* Get available buffer size in KB
1086 	 * for 512kb this will be 296
1087 	 * for 2Mb   this will be 1832
1088 	 */
1089 	m_dwPauseLimit = (u_long)(hw->wDRAMSize - (u_long)(coeffsize));
1090 	m_dwPauseLimit -= ((pParam->Size.dwPhyBytes*scaler) / 1024 + 1);
1091 
1092 	/* If not reversing, take into account the steps to reverse */
1093 	if( regs[0x50] == 0 )
1094 		m_dwPauseLimit -= ((regs[0x54] & 7) *
1095 		                  (pParam->Size.dwPhyBytes * scaler) + 1023) / 1024;
1096 
1097 	DBG( _DBG_INFO2, "* PL=%lu, coeffsize=%u, scaler=%u\n",
1098 	                  m_dwPauseLimit, coeffsize, scaler );
1099 
1100 	m_dwPauseLimit = usb_max( usb_min(m_dwPauseLimit,
1101 	                  (u_long)ceil(pParam->Size.dwTotalBytes / 1024.0)), 2);
1102 
1103 	regs[0x4e] = (u_char)floor((m_dwPauseLimit*512.0)/(2.0*hw->wDRAMSize));
1104 
1105 	if( regs[0x4e] > 1 ) {
1106 		regs[0x4e]--;
1107 		if(regs[0x4e] > 1)
1108 			regs[0x4e]--;
1109 	} else
1110 		regs[0x4e] = 1;
1111 
1112 	/* resume, when buffer is 2/8 kbytes full (512k/2M memory)
1113 	 */
1114 	regs[0x4f] = 1;
1115 
1116 	DBG( _DBG_INFO2, "* PauseLimit = %lu, [0x4e] = 0x%02x, [0x4f] = 0x%02x\n",
1117 	                  m_dwPauseLimit, regs[0x4e], regs[0x4f] );
1118 }
1119 
1120 /** usb_GetScanLinesAndSize
1121  */
1122 static void
usb_GetScanLinesAndSize(Plustek_Device * dev,ScanParam * pParam)1123 usb_GetScanLinesAndSize( Plustek_Device *dev, ScanParam *pParam )
1124 {
1125 	DCapsDef *sCaps = &dev->usbDev.Caps;
1126 
1127 	pParam->Size.dwPhyLines = (u_long)ceil((double) pParam->Size.dwLines *
1128 	                                     pParam->PhyDpi.y / pParam->UserDpi.y);
1129 
1130 	/* Calculate color offset */
1131 	if (pParam->bCalibration == PARAM_Scan && pParam->bChannels == 3) {
1132 
1133 		dev->scanning.bLineDistance = sCaps->bSensorDistance *
1134 		                                  pParam->PhyDpi.y / sCaps->OpticDpi.x;
1135 		pParam->Size.dwPhyLines += (dev->scanning.bLineDistance << 1);
1136 	}
1137 	else
1138 		dev->scanning.bLineDistance = 0;
1139 
1140 	pParam->Size.dwTotalBytes = pParam->Size.dwPhyBytes * pParam->Size.dwPhyLines;
1141 
1142 	DBG( _DBG_INFO, "* PhyBytes   = %lu\n", pParam->Size.dwPhyBytes );
1143 	DBG( _DBG_INFO, "* PhyLines   = %lu\n", pParam->Size.dwPhyLines );
1144 	DBG( _DBG_INFO, "* TotalBytes = %lu\n", pParam->Size.dwTotalBytes );
1145 }
1146 
1147 /** function to preset/reset the merlin registers
1148  */
1149 static SANE_Bool
usb_SetScanParameters(Plustek_Device * dev,ScanParam * pParam)1150 usb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam )
1151 {
1152 	static u_char reg8, reg38[6], reg48[2];
1153 
1154 	ScanDef   *scan    = &dev->scanning;
1155 	ScanParam *pdParam = &dev->scanning.sParam;
1156 	HWDef     *hw      = &dev->usbDev.HwSetting;
1157 	u_char    *regs    = dev->usbDev.a_bRegs;
1158 
1159 	m_pParam = pParam;
1160 
1161 	DBG( _DBG_INFO, "usb_SetScanParameters()\n" );
1162 
1163 	if( !usb_IsScannerReady(dev))
1164 		return SANE_FALSE;
1165 
1166 	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1167 /* HEINER: dSaveMoveSpeed is only used in func EjectPaper!!!
1168 		dSaveMoveSpeed = hw->dMaxMoveSpeed;
1169 */
1170 		hw->dMaxMoveSpeed = 1.0;
1171 		usb_MotorSelect( dev, SANE_TRUE );
1172 		usb_MotorOn( dev, SANE_TRUE );
1173 	}
1174 
1175 	/*
1176 	 * calculate the basic settings...
1177 	 */
1178 	pParam->PhyDpi.x = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1179 	pParam->PhyDpi.y = usb_SetAsicDpiY( dev, pParam->UserDpi.y );
1180 
1181 	usb_SetColorAndBits( dev, pParam );
1182 	usb_GetScanRect    ( dev, pParam );
1183 
1184 	usb_PresetStepSize( dev, pParam );
1185 
1186 	if( dev->caps.dwFlag & SFLAG_ADF ) {
1187 
1188 		if( pParam->bCalibration == PARAM_Scan ) {
1189 
1190 			if( pdParam->bSource == SOURCE_ADF ) {
1191 				regs[0x50] = 0;
1192 				regs[0x51] = 0x40;
1193 				if( pParam->PhyDpi.x <= 300)
1194 					regs[0x54] = (regs[0x54] & ~7) | 4;	/* 3; */
1195 				else
1196 					regs[0x54] = (regs[0x54] & ~7) | 5;	/* 4; */
1197 			} else {
1198 				regs[0x50] = hw->bStepsToReverse;
1199 				regs[0x51] = hw->bReg_0x51;
1200 				regs[0x54] &= ~7;
1201 			}
1202 		} else
1203 			regs[0x50] = 0;
1204 	} else {
1205 		if( pParam->bCalibration == PARAM_Scan )
1206 			regs[0x50] = hw->bStepsToReverse;
1207 		else
1208 			regs[0x50] = 0;
1209 	}
1210 
1211 	/* Assume we will not use ITA */
1212 	regs[0x19] = m_bIntTimeAdjust = 0;
1213 
1214 	/* Get variables from calculation algorithms */
1215 	if(!(pParam->bCalibration == PARAM_Scan &&
1216           pParam->bSource == SOURCE_ADF && dev->usbDev.fLastScanIsAdf )) {
1217 
1218 		DBG( _DBG_INFO2, "* Scan calculations...\n" );
1219 		usb_GetLineLength ( dev, pParam );
1220 		usb_GetStepSize   ( dev, pParam );
1221 		usb_GetDPD        ( dev );
1222 		usb_GetMCLKDivider( dev, pParam );
1223 		usb_GetMotorParam ( dev, pParam );
1224 	}
1225 
1226 	/* Compute fast feed step size, use equation 3 and equation 8 */
1227 	if( m_dMCLKDivider < 1.0)
1228 		m_dMCLKDivider = 1.0;
1229 
1230 	m_wFastFeedStepSize = (u_short)(CRYSTAL_FREQ /
1231 	                          (m_dMCLKDivider * 8 * m_bCM * hw->dMaxMoveSpeed *
1232 	                           4 * hw->wMotorDpi));
1233 	/* CIS special ;-) */
1234 	if((hw->bReg_0x26 & _ONE_CH_COLOR) && (m_bCM == 1)) {
1235 		DBG( _DBG_INFO2, "* CIS FFStep-Speedup\n" );
1236 		m_wFastFeedStepSize /= 3;
1237 	}
1238 
1239 	if( m_bIntTimeAdjust != 0 )
1240 		m_wFastFeedStepSize /= m_bIntTimeAdjust;
1241 
1242 	if(regs[0x0a])
1243 		m_wFastFeedStepSize *= ((regs[0x0a] >> 2) + 2);
1244 	regs[0x48] = _HIBYTE( m_wFastFeedStepSize );
1245 	regs[0x49] = _LOBYTE( m_wFastFeedStepSize );
1246 
1247 	DBG( _DBG_INFO2, "* FFStepSize = %u, [0x48] = 0x%02x, [0x49] = 0x%02x\n",
1248 	                       m_wFastFeedStepSize, regs[0x48], regs[0x49] );
1249 
1250 	/* Compute the number of lines to scan using actual Y resolution */
1251 	usb_GetScanLinesAndSize( dev, pParam );
1252 
1253 	/* Pause limit should be bounded by total bytes to read
1254 	 * so that the chassis will not move too far.
1255 	 */
1256 	usb_GetPauseLimit( dev, pParam );
1257 
1258 	/* For ADF .... */
1259 	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1260 
1261 		if( dev->usbDev.fLastScanIsAdf ) {
1262 
1263 			regs[0x08] = reg8;
1264 			memcpy( &regs[0x38], reg38, sizeof(reg38));
1265 			memcpy( &regs[0x48], reg48, sizeof(reg48));
1266 
1267 		} else {
1268 
1269 			reg8 = regs[0x08];
1270 			memcpy( reg38, &regs[0x38], sizeof(reg38));
1271 			memcpy( reg48, &regs[0x48], sizeof(reg48));
1272 		}
1273 		usb_MotorSelect( dev, SANE_TRUE );
1274 	}
1275 
1276 	/* Reset LM983x's state machine before setting register values */
1277 	if( !usbio_WriteReg( dev->fd, 0x18, 0x18 ))
1278 		return SANE_FALSE;
1279 
1280 	usleep(200 * 1000); /* Need to delay at least xxx microseconds */
1281 
1282 	if( !usbio_WriteReg( dev->fd, 0x07, 0x20 ))
1283 		return SANE_FALSE;
1284 
1285 	if( !usbio_WriteReg( dev->fd, 0x19, 6 ))
1286 		return SANE_FALSE;
1287 
1288 	regs[0x07] = 0;
1289 	regs[0x28] = 0;
1290 
1291 	/* set unused registers to 0 */
1292 	memset( &regs[0x03], 0, 3 );
1293 	memset( &regs[0x5f], 0, 0x7f-0x5f+1 );
1294 
1295 	if( !usb_IsSheetFedDevice(dev)) {
1296 		/* we limit the possible scansteps to avoid, that the sensors bumps
1297 		 * against the scanbed - not necessary for sheet-fed devices
1298 		 */
1299 		if(pParam->bCalibration==PARAM_Scan && pParam->bSource!=SOURCE_ADF) {
1300 
1301 			u_long  lines     = pParam->Size.dwPhyLines + scan->bLinesToSkip +
1302 			                                          scan->dwLinesDiscard + 5;
1303 			u_short scansteps = (u_short)ceil((double)lines*
1304 			                                 hw->wMotorDpi / pParam->PhyDpi.y);
1305 			DBG( _DBG_INFO, "* Scansteps=%u (%lu*%u/%u)\n", scansteps,  lines,
1306 			                hw->wMotorDpi, pParam->PhyDpi.y );
1307 			regs[0x4c] = _HIBYTE(scansteps);
1308 			regs[0x4d] = _LOBYTE(scansteps);
1309 		}
1310 	}
1311 
1312 	/* set the merlin registers */
1313 	_UIO(sanei_lm983x_write( dev->fd, 0x03, &regs[0x03], 3, SANE_TRUE));
1314 	_UIO(sanei_lm983x_write( dev->fd, 0x08, &regs[0x08], 0x7f - 0x08+1, SANE_TRUE));
1315 
1316 	usleep(100);
1317 
1318 	if( !usbio_WriteReg( dev->fd, 0x07, 0 ))
1319 		return SANE_FALSE;
1320 
1321 	DBG( _DBG_INFO, "usb_SetScanParameters() done.\n" );
1322 	return SANE_TRUE;
1323 }
1324 
1325 /**
1326  */
1327 static SANE_Bool
usb_ScanBegin(Plustek_Device * dev,SANE_Bool auto_park)1328 usb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park )
1329 {
1330 	u_char  value;
1331 	u_short inches;
1332 	HWDef       *hw   = &dev->usbDev.HwSetting;
1333 	DCapsDef    *sc   = &dev->usbDev.Caps;
1334 	u_char      *regs = dev->usbDev.a_bRegs;
1335 
1336 	DBG( _DBG_INFO, "usb_ScanBegin()\n" );
1337 
1338 	if( !usb_Wait4ScanSample( dev ))
1339 		return SANE_FALSE;
1340 
1341 	/* save the request for usb_ScanEnd () */
1342 	m_fAutoPark = auto_park;
1343 
1344 	/* Disable home sensor during scan, or the chassis cannot move */
1345 	value = ((m_pParam->bCalibration == PARAM_Scan &&
1346 	        m_pParam->bSource == SOURCE_ADF)? (regs[0x58] & ~7): 0);
1347 
1348 	if(!usbio_WriteReg( dev->fd, 0x58, value ))
1349 		return SANE_FALSE;
1350 
1351 	/* Check if scanner is ready for receiving command */
1352 	if( !usb_IsScannerReady(dev))
1353 		return SANE_FALSE;
1354 
1355 	/* Flush cache - only LM9831 (Source: National Semiconductors) */
1356 	if( _LM9831 == hw->chip ) {
1357 
1358 		for(;;) {
1359 
1360 			if( SANE_TRUE == cancelRead ) {
1361 				DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" );
1362 				return SANE_FALSE;
1363 			}
1364 
1365 			_UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData ));
1366 			if( m_bOldScanData ) {
1367 
1368 				u_long dwBytesToRead = m_bOldScanData * hw->wDRAMSize * 4;
1369 				u_char *pBuffer      = malloc( sizeof(u_char) * dwBytesToRead );
1370 
1371 				DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n",
1372 				                                dwBytesToRead, m_bOldScanData );
1373 
1374 				_UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer,
1375 				                                  dwBytesToRead, SANE_FALSE ));
1376 				free( pBuffer );
1377 
1378 			} else
1379 				break;
1380 		}
1381 	}
1382 
1383 	/* Download map & Shading data */
1384 	if(( m_pParam->bCalibration == PARAM_Scan && !usb_MapDownload( dev )) ||
1385 	    !usb_DownloadShadingData( dev, m_pParam->bCalibration )) {
1386 		return SANE_FALSE;
1387 	}
1388 
1389 	/* Move chassis and start to read image data */
1390 	if (!usbio_WriteReg( dev->fd, 0x07, 3 ))
1391 		return SANE_FALSE;
1392 
1393 	usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData );
1394 	m_bOldScanData = 0;                     /* No data at all  */
1395 
1396 	m_fStart = m_fFirst = SANE_TRUE;        /* Prepare to read */
1397 
1398 	DBG( _DBG_DREGS, "Register Dump before reading data:\n" );
1399 	dumpregs( dev->fd, NULL );
1400 
1401 	inches = (u_short)((m_pParam->Origin.y *300UL)/hw->wMotorDpi);
1402 	DBG( _DBG_INFO2, ">>> INCH=%u, DOY=%u\n", inches, sc->Normal.DataOrigin.y );
1403 	if( inches > sc->Normal.DataOrigin.y )
1404 		usb_WaitPos( dev, 150, SANE_FALSE );
1405 
1406 	DBG( _DBG_INFO, "usb_ScanBegin() done.\n" );
1407 	return SANE_TRUE;
1408 }
1409 
1410 /** usb_ScanEnd
1411  * stop all the processing stuff and reposition sensor back home
1412  */
1413 static SANE_Bool
usb_ScanEnd(Plustek_Device * dev)1414 usb_ScanEnd( Plustek_Device *dev )
1415 {
1416 	u_char value;
1417 
1418 	DBG( _DBG_INFO, "usbDev_ScanEnd(), start=%u, park=%u\n",
1419 	                                                   m_fStart, m_fAutoPark );
1420 	usbio_ReadReg( dev->fd, 0x07, &value );
1421 	if( value == 3 || value != 2 )
1422 		usbio_WriteReg( dev->fd, 0x07, 0 );
1423 
1424 	if( m_fStart ) {
1425 		m_fStart = SANE_FALSE;
1426 
1427 		if( m_fAutoPark )
1428 			usb_ModuleToHome( dev, SANE_FALSE );
1429 	}
1430 	else if( SANE_TRUE == cancelRead ) {
1431 
1432 		usb_ModuleToHome( dev, SANE_FALSE );
1433 	}
1434 	return SANE_TRUE;
1435 }
1436 
1437 /**
1438  */
1439 static SANE_Bool
usb_IsDataAvailableInDRAM(Plustek_Device * dev)1440 usb_IsDataAvailableInDRAM( Plustek_Device *dev )
1441 {
1442 	/* Compute polling timeout
1443 	 *	Height (Inches) / MaxScanSpeed (Inches/Second) = Seconds to move the
1444      *  module from top to bottom. Then convert the seconds to milliseconds
1445      *  by multiply 1000. We add extra 2 seconds to get some tolerance.
1446      */
1447 	u_char         a_bBand[3];
1448 	long           dwTicks;
1449     struct timeval t;
1450 	u_char         *regs = dev->usbDev.a_bRegs;
1451 
1452 	DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" );
1453 
1454 	gettimeofday( &t, NULL);
1455 	dwTicks = t.tv_sec + 30;
1456 
1457 	for(;;)	{
1458 
1459 		_UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE ));
1460 
1461 		gettimeofday( &t, NULL);
1462 	    if( t.tv_sec > dwTicks )
1463 			break;
1464 
1465 		if( usb_IsEscPressed()) {
1466 			DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n");
1467 			return SANE_FALSE;
1468 		}
1469 
1470 		/* It is not stable for read */
1471 		if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2]))
1472 			continue;
1473 
1474 		if( a_bBand[0] > m_bOldScanData ) {
1475 
1476 			if( m_pParam->bSource != SOURCE_Reflection )
1477 
1478 				usleep(1000*(30 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1479 			else
1480 				usleep(1000*(20 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1481 
1482 			DBG( _DBG_INFO, "Data is available\n" );
1483 			return SANE_TRUE;
1484 		}
1485 	}
1486 
1487 	DBG( _DBG_INFO, "NO Data available\n" );
1488 	return SANE_FALSE;
1489 }
1490 
1491 /**
1492  */
1493 static SANE_Bool
usb_ScanReadImage(Plustek_Device * dev,void * pBuf,u_long dwSize)1494 usb_ScanReadImage( Plustek_Device *dev, void *pBuf, u_long dwSize )
1495 {
1496 	u_char       *regs = dev->usbDev.a_bRegs;
1497 	SANE_Status   res;
1498 
1499 	DBG( _DBG_READ, "usb_ScanReadImage(%lu)\n", dwSize );
1500 
1501 	if( m_fFirst ) {
1502 
1503 		m_fFirst = SANE_FALSE;
1504 
1505 		/* Wait for data band ready */
1506 		if (!usb_IsDataAvailableInDRAM( dev )) {
1507 			DBG( _DBG_ERROR, "Nothing to read...\n" );
1508 			return SANE_FALSE;
1509 		}
1510 
1511 		/* restore the fast forward stepsize...*/
1512 		sanei_lm983x_write(dev->fd, 0x48, &regs[0x48], 2, SANE_TRUE);
1513 	}
1514 	res = sanei_lm983x_read(dev->fd, 0x00, (u_char *)pBuf, dwSize, SANE_FALSE);
1515 
1516 	/* check for pressed ESC button, as sanei_lm983x_read() may take some time
1517 	 */
1518 	if( usb_IsEscPressed()) {
1519 		DBG(_DBG_INFO,"usb_ScanReadImage() - Cancel detected...\n");
1520 		return SANE_FALSE;
1521 	}
1522 
1523 	DBG( _DBG_READ, "usb_ScanReadImage() done, result: %d\n", res );
1524 	if( SANE_STATUS_GOOD == res ) {
1525 		return SANE_TRUE;
1526 	}
1527 
1528 	DBG( _DBG_ERROR, "usb_ScanReadImage() failed\n" );
1529 	return SANE_FALSE;
1530 }
1531 
1532 /** calculate the number of pixels per line and lines out of a given
1533  * crop-area. The size of the area is given on a 300dpi base!
1534  */
1535 static void
usb_GetImageInfo(Plustek_Device * dev,ImgDef * pInfo,WinInfo * pSize)1536 usb_GetImageInfo( Plustek_Device *dev, ImgDef *pInfo, WinInfo *pSize )
1537 {
1538 	DBG( _DBG_INFO, "usb_GetImageInfo()\n" );
1539 
1540 	pSize->dwPixels = (u_long)pInfo->crArea.cx * pInfo->xyDpi.x / 300UL;
1541 	pSize->dwLines  = (u_long)pInfo->crArea.cy * pInfo->xyDpi.y / 300UL;
1542 
1543 	DBG( _DBG_INFO2,"Area: cx=%u, cy=%u\n",pInfo->crArea.cx,pInfo->crArea.cy);
1544 
1545 	switch( pInfo->wDataType ) {
1546 
1547 		case COLOR_TRUE48:
1548 			pSize->dwBytes = pSize->dwPixels * 6UL;
1549 			break;
1550 
1551 		case COLOR_TRUE24:
1552 			if( dev->scanning.fGrayFromColor > 7 ){
1553 				pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
1554 				pSize->dwPixels = pSize->dwBytes * 8;
1555 			} else {
1556 				pSize->dwBytes = pSize->dwPixels * 3UL;
1557 			}
1558 			break;
1559 
1560 		case COLOR_GRAY16:
1561 			pSize->dwBytes = pSize->dwPixels << 1;
1562 			break;
1563 
1564 		case COLOR_256GRAY:
1565 			pSize->dwBytes = pSize->dwPixels;
1566 			break;
1567 
1568 		default:
1569 			pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
1570 			pSize->dwPixels = pSize->dwBytes * 8;
1571 			break;
1572 	}
1573 }
1574 
1575 /**
1576  */
1577 static void
usb_SaveImageInfo(Plustek_Device * dev,ImgDef * pInfo)1578 usb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo )
1579 {
1580 	HWDef     *hw     = &dev->usbDev.HwSetting;
1581 	ScanParam *pParam = &dev->scanning.sParam;
1582 
1583 	DBG( _DBG_INFO, "usb_SaveImageInfo()\n" );
1584 
1585 	/* Dpi & Origins */
1586 	pParam->UserDpi  = pInfo->xyDpi;
1587 	pParam->Origin.x = pInfo->crArea.x;
1588 	pParam->Origin.y = pInfo->crArea.y;
1589 
1590 	/* Source & Bits */
1591 	pParam->bBitDepth = 8;
1592 
1593 	switch( pInfo->wDataType ) {
1594 
1595 		case COLOR_TRUE48:
1596 			pParam->bBitDepth = 16;
1597 			/* fall through... */
1598 
1599 		case COLOR_TRUE24:
1600 			pParam->bDataType = SCANDATATYPE_Color;
1601 
1602 			/* AFE operation: one or 3 channels ! */
1603 			if( hw->bReg_0x26 & _ONE_CH_COLOR )
1604 				pParam->bChannels = 1;
1605 			else
1606 				pParam->bChannels = 3;
1607 			break;
1608 
1609 		case COLOR_GRAY16:
1610 			pParam->bBitDepth = 16;
1611 			/* fall through... */
1612 
1613 		case COLOR_256GRAY:
1614 			pParam->bDataType = SCANDATATYPE_Gray;
1615 			pParam->bChannels = 1;
1616 			break;
1617 
1618 		default:
1619 			pParam->bBitDepth = 1;
1620 			pParam->bDataType = SCANDATATYPE_BW;
1621 			pParam->bChannels = 1;
1622 	}
1623 
1624 	DBG( _DBG_INFO, "* dwFlag = 0x%08lx\n", pInfo->dwFlag );
1625 
1626 	if( pInfo->dwFlag & SCANDEF_Transparency )
1627 		pParam->bSource = SOURCE_Transparency;
1628 	else if( pInfo->dwFlag & SCANDEF_Negative )
1629 		pParam->bSource = SOURCE_Negative;
1630 	else if( pInfo->dwFlag & SCANDEF_Adf )
1631 		pParam->bSource = SOURCE_ADF;
1632 	else
1633 		pParam->bSource = SOURCE_Reflection;
1634 
1635 	/* it seems, that we need to adjust the Origin.x when we have a
1636 	 * sheetfed device to avoid stripes in the resulting pictures
1637 	 */
1638 	if( usb_IsSheetFedDevice(dev)) {
1639 
1640 		int step, div, org, xdpi;
1641 
1642 		xdpi = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1643 
1644 		if ((xdpi * 2) <= 300)
1645 			div = 300;
1646 		else if ((xdpi * 2) <= 600)
1647 			div = 600;
1648 		else if ((xdpi * 2) <= 1200)
1649 			div = 1200;
1650 		else
1651 			div = 2400;
1652 
1653 		step = div / xdpi;
1654 		org  = pParam->Origin.x;
1655 
1656 		pParam->Origin.x = (pParam->Origin.x / step) * step;
1657 
1658 		if (org != pParam->Origin.x)
1659 			DBG(_DBG_INFO, "* Origin.x adjusted: %i -> %i\n",
1660 			               org, pParam->Origin.x);
1661 	}
1662 }
1663 
1664 /* END PLUSTEK-USBSCAN.C ....................................................*/
1665