1141cc406Sopenharmony_ci/*.............................................................................
2141cc406Sopenharmony_ci * Project : SANE library for Plustek flatbed scanners.
3141cc406Sopenharmony_ci *.............................................................................
4141cc406Sopenharmony_ci */
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci/** @file plustek-usbscan.c
7141cc406Sopenharmony_ci *  @brief Scanning...
8141cc406Sopenharmony_ci *
9141cc406Sopenharmony_ci * Based on sources acquired from Plustek Inc.<br>
10141cc406Sopenharmony_ci * Copyright (C) 2001-2013 Gerhard Jaeger <gerhard@gjaeger.de>
11141cc406Sopenharmony_ci *
12141cc406Sopenharmony_ci * History:
13141cc406Sopenharmony_ci * - 0.40 - starting version of the USB support
14141cc406Sopenharmony_ci * - 0.41 - minor fixes
15141cc406Sopenharmony_ci * - 0.42 - added some stuff for CIS devices
16141cc406Sopenharmony_ci * - 0.43 - no changes
17141cc406Sopenharmony_ci * - 0.44 - added CIS specific settings and calculations
18141cc406Sopenharmony_ci *        - removed usb_IsEscPressed
19141cc406Sopenharmony_ci * - 0.45 - fixed the special setting stuff for CanoScan
20141cc406Sopenharmony_ci *        - fixed pixel calculation for binary modes
21141cc406Sopenharmony_ci *        - fixed cancel hang problem
22141cc406Sopenharmony_ci *        - fixed CIS PhyBytes adjustment
23141cc406Sopenharmony_ci *        - removed CanoScan specific setting stuff
24141cc406Sopenharmony_ci * - 0.46 - fixed problem in usb_SetScanParameters()
25141cc406Sopenharmony_ci * - 0.47 - no changes
26141cc406Sopenharmony_ci * - 0.48 - minor fixes
27141cc406Sopenharmony_ci * - 0.49 - a_bRegs is now part of the device structure
28141cc406Sopenharmony_ci *        - using now PhyDpi.y as selector for the motor MCLK range
29141cc406Sopenharmony_ci *        - changed usb_MapDownload prototype
30141cc406Sopenharmony_ci * - 0.50 - cleanup
31141cc406Sopenharmony_ci * - 0.51 - added usb_get_res() and usb_GetPhyPixels()
32141cc406Sopenharmony_ci * - 0.52 - removed stuff, that will most probably never be used
33141cc406Sopenharmony_ci * .
34141cc406Sopenharmony_ci * <hr>
35141cc406Sopenharmony_ci * This file is part of the SANE package.
36141cc406Sopenharmony_ci *
37141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
38141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
39141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the
40141cc406Sopenharmony_ci * License, or (at your option) any later version.
41141cc406Sopenharmony_ci *
42141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
43141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
44141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
45141cc406Sopenharmony_ci * General Public License for more details.
46141cc406Sopenharmony_ci *
47141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License
48141cc406Sopenharmony_ci * along with this program.  If not, see <https://www.gnu.org/licenses/>.
49141cc406Sopenharmony_ci *
50141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for
51141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE.
52141cc406Sopenharmony_ci *
53141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files
54141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the
55141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public
56141cc406Sopenharmony_ci * License.  Your use of that executable is in no way restricted on
57141cc406Sopenharmony_ci * account of linking the SANE library code into it.
58141cc406Sopenharmony_ci *
59141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why
60141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public
61141cc406Sopenharmony_ci * License.
62141cc406Sopenharmony_ci *
63141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in
64141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that
65141cc406Sopenharmony_ci * those changes may be distributed with this exception intact.
66141cc406Sopenharmony_ci *
67141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice
68141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications.
69141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice.
70141cc406Sopenharmony_ci * <hr>
71141cc406Sopenharmony_ci */
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_ci#define DIVIDER 8
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci/** array used to get motor-settings and mclk-settings
76141cc406Sopenharmony_ci */
77141cc406Sopenharmony_cistatic int dpi_ranges[] = { 75,100,150,200,300,400,600,800,1200,2400 };
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_cistatic u_char     bMaxITA;
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_cistatic SANE_Bool  m_fAutoPark;
82141cc406Sopenharmony_cistatic SANE_Bool  m_fFirst;
83141cc406Sopenharmony_cistatic double     m_dHDPIDivider;
84141cc406Sopenharmony_cistatic double     m_dMCLKDivider;
85141cc406Sopenharmony_cistatic ScanParam *m_pParam;
86141cc406Sopenharmony_cistatic u_char     m_bLineRateColor;
87141cc406Sopenharmony_cistatic u_char     m_bCM;
88141cc406Sopenharmony_cistatic u_char	  m_bIntTimeAdjust;
89141cc406Sopenharmony_cistatic u_char	  m_bOldScanData;
90141cc406Sopenharmony_cistatic u_short    m_wFastFeedStepSize;
91141cc406Sopenharmony_cistatic u_short    m_wLineLength;
92141cc406Sopenharmony_cistatic u_short	  m_wStepSize;
93141cc406Sopenharmony_cistatic u_long     m_dwPauseLimit;
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_cistatic SANE_Bool  m_fStart = SANE_FALSE;
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci/* Prototype... */
98141cc406Sopenharmony_cistatic SANE_Bool usb_DownloadShadingData( Plustek_Device*, u_char );
99141cc406Sopenharmony_ci
100141cc406Sopenharmony_ci/** returns the min of the two values val1 and val2
101141cc406Sopenharmony_ci * @param val1 - first parameter
102141cc406Sopenharmony_ci * @param val2 - second parameter
103141cc406Sopenharmony_ci * @return val1 if val1 < val2, else val1
104141cc406Sopenharmony_ci */
105141cc406Sopenharmony_cistatic u_long
106141cc406Sopenharmony_ciusb_min( u_long val1, u_long val2 )
107141cc406Sopenharmony_ci{
108141cc406Sopenharmony_ci	if( val1 > val2 )
109141cc406Sopenharmony_ci		return val2;
110141cc406Sopenharmony_ci	return val1;
111141cc406Sopenharmony_ci}
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/** returns the max of the two values val1 and val2
114141cc406Sopenharmony_ci * @param val1 - first parameter
115141cc406Sopenharmony_ci * @param val2 - second parameter
116141cc406Sopenharmony_ci * @return val1 if val1 > val2, else val2
117141cc406Sopenharmony_ci */
118141cc406Sopenharmony_cistatic u_long
119141cc406Sopenharmony_ciusb_max( u_long val1, u_long val2 )
120141cc406Sopenharmony_ci{
121141cc406Sopenharmony_ci	if( val1 > val2 )
122141cc406Sopenharmony_ci		return val1;
123141cc406Sopenharmony_ci	return val2;
124141cc406Sopenharmony_ci}
125141cc406Sopenharmony_ci
126141cc406Sopenharmony_ci/** function to get the possible resolution for a specific base resolution,
127141cc406Sopenharmony_ci * according to the dividers a LM983x offers.
128141cc406Sopenharmony_ci * @param base - scanners optical resolution
129141cc406Sopenharmony_ci * @param idx  - which divider to use
130141cc406Sopenharmony_ci */
131141cc406Sopenharmony_cistatic u_short
132141cc406Sopenharmony_ciusb_get_res( u_short base, u_short idx )
133141cc406Sopenharmony_ci{
134141cc406Sopenharmony_ci	double div_list[DIVIDER] = { 12.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0 };
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci	if( idx == 0 || idx > DIVIDER )
137141cc406Sopenharmony_ci		return 0;
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci	return (u_short)((double)base/div_list[idx-1]);
140141cc406Sopenharmony_ci}
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci/** Set the horizontal DPI divider.
143141cc406Sopenharmony_ci * Affected registers:<br>
144141cc406Sopenharmony_ci * 0x09 - Horizontal DPI divider HDPI_DIV<br>
145141cc406Sopenharmony_ci *
146141cc406Sopenharmony_ci * @param dev  - pointer to our device structure,
147141cc406Sopenharmony_ci *               it should contain all we need
148141cc406Sopenharmony_ci * @param xdpi - user specified horizontal resolution
149141cc406Sopenharmony_ci * @return - the function returns the "normalized" horizontal resolution.
150141cc406Sopenharmony_ci */
151141cc406Sopenharmony_cistatic u_short
152141cc406Sopenharmony_ciusb_SetAsicDpiX( Plustek_Device *dev, u_short xdpi )
153141cc406Sopenharmony_ci{
154141cc406Sopenharmony_ci	u_short   res;
155141cc406Sopenharmony_ci	ScanDef  *scanning = &dev->scanning;
156141cc406Sopenharmony_ci	DCapsDef *scaps    = &dev->usbDev.Caps;
157141cc406Sopenharmony_ci	u_char   *regs     = dev->usbDev.a_bRegs;
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci	/* limit xdpi to lower value for certain devices...
160141cc406Sopenharmony_ci	 */
161141cc406Sopenharmony_ci	if( scaps->OpticDpi.x == 1200 &&
162141cc406Sopenharmony_ci		scanning->sParam.bDataType != SCANDATATYPE_Color &&
163141cc406Sopenharmony_ci		xdpi < 150 &&
164141cc406Sopenharmony_ci		scanning->sParam.bDataType == SCANDATATYPE_BW ) {
165141cc406Sopenharmony_ci		xdpi = 150;
166141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* LIMIT XDPI to %udpi\n", xdpi );
167141cc406Sopenharmony_ci	}
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci	m_dHDPIDivider = (double)scaps->OpticDpi.x / xdpi;
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci	if (m_dHDPIDivider < 1.5)
172141cc406Sopenharmony_ci	{
173141cc406Sopenharmony_ci		m_dHDPIDivider = 1.0;
174141cc406Sopenharmony_ci		regs[0x09]  = 0;
175141cc406Sopenharmony_ci	}
176141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 2.0)
177141cc406Sopenharmony_ci	{
178141cc406Sopenharmony_ci		m_dHDPIDivider = 1.5;
179141cc406Sopenharmony_ci		regs[0x09]  = 1;
180141cc406Sopenharmony_ci	}
181141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 3.0)
182141cc406Sopenharmony_ci	{
183141cc406Sopenharmony_ci		m_dHDPIDivider = 2.0;
184141cc406Sopenharmony_ci		regs[0x09]  = 2;
185141cc406Sopenharmony_ci	}
186141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 4.0)
187141cc406Sopenharmony_ci	{
188141cc406Sopenharmony_ci		m_dHDPIDivider = 3.0;
189141cc406Sopenharmony_ci		regs[0x09]  = 3;
190141cc406Sopenharmony_ci	}
191141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 6.0)
192141cc406Sopenharmony_ci	{
193141cc406Sopenharmony_ci		m_dHDPIDivider = 4.0;
194141cc406Sopenharmony_ci		regs[0x09]  = 4;
195141cc406Sopenharmony_ci	}
196141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 8.0)
197141cc406Sopenharmony_ci	{
198141cc406Sopenharmony_ci		m_dHDPIDivider = 6.0;
199141cc406Sopenharmony_ci		regs[0x09]  = 5;
200141cc406Sopenharmony_ci	}
201141cc406Sopenharmony_ci	else if (m_dHDPIDivider < 12.0)
202141cc406Sopenharmony_ci	{
203141cc406Sopenharmony_ci		m_dHDPIDivider = 8.0;
204141cc406Sopenharmony_ci		regs[0x09]  = 6;
205141cc406Sopenharmony_ci	}
206141cc406Sopenharmony_ci	else
207141cc406Sopenharmony_ci	{
208141cc406Sopenharmony_ci		m_dHDPIDivider = 12.0;
209141cc406Sopenharmony_ci		regs[0x09]  = 7;
210141cc406Sopenharmony_ci	}
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci	/* adjust, if any turbo/preview mode is set, should be 0 here... */
213141cc406Sopenharmony_ci	if( regs[0x0a] )
214141cc406Sopenharmony_ci		regs[0x09] -= ((regs[0x0a] >> 2) + 2);
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* HDPI: %.3f\n", m_dHDPIDivider );
217141cc406Sopenharmony_ci	res = (u_short)((double)scaps->OpticDpi.x / m_dHDPIDivider);
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* XDPI=%u, HDPI=%.3f\n", res, m_dHDPIDivider );
220141cc406Sopenharmony_ci	return res;
221141cc406Sopenharmony_ci}
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci/**
224141cc406Sopenharmony_ci * @param dev  - pointer to our device structure,
225141cc406Sopenharmony_ci *               it should contain all we need
226141cc406Sopenharmony_ci * @param ydpi - user specified vertical resolution
227141cc406Sopenharmony_ci * @return -
228141cc406Sopenharmony_ci */
229141cc406Sopenharmony_cistatic u_short
230141cc406Sopenharmony_ciusb_SetAsicDpiY( Plustek_Device *dev, u_short ydpi )
231141cc406Sopenharmony_ci{
232141cc406Sopenharmony_ci	ScanDef  *scanning = &dev->scanning;
233141cc406Sopenharmony_ci	DCapsDef *sCaps    = &dev->usbDev.Caps;
234141cc406Sopenharmony_ci	HWDef    *hw       = &dev->usbDev.HwSetting;
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci	u_short wMinDpi, wDpi;
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci	if(0 != sCaps->bSensorDistance )
239141cc406Sopenharmony_ci		wMinDpi = sCaps->OpticDpi.y / sCaps->bSensorDistance;
240141cc406Sopenharmony_ci	else
241141cc406Sopenharmony_ci		wMinDpi = 75;
242141cc406Sopenharmony_ci
243141cc406Sopenharmony_ci	/* Here we might have to check against the MinDpi value ! */
244141cc406Sopenharmony_ci	wDpi = (ydpi + wMinDpi - 1) / wMinDpi * wMinDpi;
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci	/*
247141cc406Sopenharmony_ci	 * HEINER: added '*2'
248141cc406Sopenharmony_ci	 */
249141cc406Sopenharmony_ci	if( wDpi > sCaps->OpticDpi.y * 2 )
250141cc406Sopenharmony_ci		wDpi = sCaps->OpticDpi.y * 2;
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci	if( (hw->motorModel == MODEL_Tokyo600) ||
253141cc406Sopenharmony_ci		!_IS_PLUSTEKMOTOR(hw->motorModel)) {
254141cc406Sopenharmony_ci		/* return wDpi; */
255141cc406Sopenharmony_ci	} else if( sCaps->wFlags & DEVCAPSFLAG_Adf && sCaps->OpticDpi.x == 600 ) {
256141cc406Sopenharmony_ci		/* for ADF scanner color mode 300 dpi big noise */
257141cc406Sopenharmony_ci		if( scanning->sParam.bDataType == SCANDATATYPE_Color &&
258141cc406Sopenharmony_ci			scanning->sParam.bBitDepth > 8 && wDpi < 300 ) {
259141cc406Sopenharmony_ci			wDpi = 300;
260141cc406Sopenharmony_ci		}
261141cc406Sopenharmony_ci	} else if( sCaps->OpticDpi.x == 1200 ) {
262141cc406Sopenharmony_ci		if( scanning->sParam.bDataType != SCANDATATYPE_Color && wDpi < 200) {
263141cc406Sopenharmony_ci			wDpi = 200;
264141cc406Sopenharmony_ci		}
265141cc406Sopenharmony_ci	}
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* YDPI=%u, MinDPIY=%u\n", wDpi, wMinDpi );
268141cc406Sopenharmony_ci	return wDpi;
269141cc406Sopenharmony_ci}
270141cc406Sopenharmony_ci
271141cc406Sopenharmony_ci/** set color mode and sensor configuration stuff, according to the data mode
272141cc406Sopenharmony_ci * Affected registers:<br>
273141cc406Sopenharmony_ci * 0x26 - 0x27 - Color Mode settings<br>
274141cc406Sopenharmony_ci * 0x0f - 0x18 - Sensor Configuration - directly from the HwDefs<br>
275141cc406Sopenharmony_ci * 0x09        - add Data Mode and Pixel Packing<br>
276141cc406Sopenharmony_ci *
277141cc406Sopenharmony_ci * @param dev    - pointer to our device structure,
278141cc406Sopenharmony_ci *                 it should contain all we need
279141cc406Sopenharmony_ci * @param pParam - pointer to the current scan parameters
280141cc406Sopenharmony_ci * @return - Nothing
281141cc406Sopenharmony_ci */
282141cc406Sopenharmony_cistatic void
283141cc406Sopenharmony_ciusb_SetColorAndBits( Plustek_Device *dev, ScanParam *pParam )
284141cc406Sopenharmony_ci{
285141cc406Sopenharmony_ci	HWDef    *hw   = &dev->usbDev.HwSetting;
286141cc406Sopenharmony_ci	u_char   *regs = dev->usbDev.a_bRegs;
287141cc406Sopenharmony_ci
288141cc406Sopenharmony_ci	/* Set pixel packing, data mode and AFE operation */
289141cc406Sopenharmony_ci	switch( pParam->bDataType ) {
290141cc406Sopenharmony_ci		case SCANDATATYPE_Color:
291141cc406Sopenharmony_ci			m_bCM = 3;
292141cc406Sopenharmony_ci			regs[0x26] = hw->bReg_0x26 & 0x7;
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci			/* if set to one channel color, we select the blue channel
295141cc406Sopenharmony_ci			 * as input source, this is the default, but I don't know
296141cc406Sopenharmony_ci			 * what happens, if we deselect this
297141cc406Sopenharmony_ci			 */
298141cc406Sopenharmony_ci			if( regs[0x26] & _ONE_CH_COLOR )
299141cc406Sopenharmony_ci				regs[0x26] |= (_BLUE_CH | 0x01);
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci			memcpy( &regs[0x0f], hw->bReg_0x0f_Color, 10 );
302141cc406Sopenharmony_ci			break;
303141cc406Sopenharmony_ci
304141cc406Sopenharmony_ci		case SCANDATATYPE_Gray:
305141cc406Sopenharmony_ci			m_bCM = 1;
306141cc406Sopenharmony_ci			regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
307141cc406Sopenharmony_ci			memcpy( &regs[0x0f], hw->bReg_0x0f_Mono, 10 );
308141cc406Sopenharmony_ci			break;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci		case SCANDATATYPE_BW:
311141cc406Sopenharmony_ci			m_bCM = 1;
312141cc406Sopenharmony_ci			regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
313141cc406Sopenharmony_ci			memcpy( &regs[0x0f], hw->bReg_0x0f_Mono, 10 );
314141cc406Sopenharmony_ci			break;
315141cc406Sopenharmony_ci	}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci	regs[0x27] = hw->bReg_0x27;
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci	if( pParam->bBitDepth > 8 ) {
320141cc406Sopenharmony_ci		regs[0x09] |= 0x20;         /* 14/16bit image data */
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci	} else if( pParam->bBitDepth == 8 ) {
323141cc406Sopenharmony_ci		regs[0x09] |= 0x18;        /* 8bits/per pixel */
324141cc406Sopenharmony_ci	}
325141cc406Sopenharmony_ci}
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci/**
328141cc406Sopenharmony_ci * Data output from NS983X should be times of 2-byte and every line
329141cc406Sopenharmony_ci * will append 2 status bytes
330141cc406Sopenharmony_ci */
331141cc406Sopenharmony_cistatic void
332141cc406Sopenharmony_ciusb_GetPhyPixels( Plustek_Device *dev, ScanParam *sp )
333141cc406Sopenharmony_ci{
334141cc406Sopenharmony_ci	sp->Size.dwValidPixels = sp->Size.dwPixels * sp->PhyDpi.x / sp->UserDpi.x;
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci	if (sp->bBitDepth == 1) {
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci		/* Pixels should be times of 16 */
339141cc406Sopenharmony_ci		sp->Size.dwPhyPixels =
340141cc406Sopenharmony_ci		            (sp->Size.dwValidPixels + 15UL) & 0xfffffff0UL;
341141cc406Sopenharmony_ci		sp->Size.dwPhyBytes = sp->Size.dwPhyPixels / 8UL + 2UL;
342141cc406Sopenharmony_ci
343141cc406Sopenharmony_ci	} else if (sp->bBitDepth == 8) {
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci		/* Pixels should be times of 2 */
346141cc406Sopenharmony_ci		sp->Size.dwPhyPixels = (sp->Size.dwValidPixels + 1UL) & 0xfffffffeUL;
347141cc406Sopenharmony_ci		sp->Size.dwPhyBytes  = sp->Size.dwPhyPixels * sp->bChannels + 2UL;
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci		/* need to be adjusted for CIS devices in color mode */
350141cc406Sopenharmony_ci		if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
351141cc406Sopenharmony_ci			sp->Size.dwPhyBytes *= 3;
352141cc406Sopenharmony_ci		}
353141cc406Sopenharmony_ci	}
354141cc406Sopenharmony_ci	else /* sp->bBitDepth == 16 */
355141cc406Sopenharmony_ci	{
356141cc406Sopenharmony_ci		sp->Size.dwPhyPixels = sp->Size.dwValidPixels;
357141cc406Sopenharmony_ci		sp->Size.dwPhyBytes  = sp->Size.dwPhyPixels * 2 * sp->bChannels + 2UL;
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci		/* need to be adjusted for CIS devices in color mode */
360141cc406Sopenharmony_ci		if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) {
361141cc406Sopenharmony_ci			sp->Size.dwPhyBytes *= 3;
362141cc406Sopenharmony_ci		}
363141cc406Sopenharmony_ci	}
364141cc406Sopenharmony_ci}
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci/** Calculate basic image settings like the number of physical bytes per line
367141cc406Sopenharmony_ci * etc...
368141cc406Sopenharmony_ci * Affected registers:<br>
369141cc406Sopenharmony_ci * 0x22/0x23 - Data Pixels Start<br>
370141cc406Sopenharmony_ci * 0x24/0x25 - Data Pixels End<br>
371141cc406Sopenharmony_ci * 0x4a/0x4b - Full Steps to Skip at Start of Scan
372141cc406Sopenharmony_ci *
373141cc406Sopenharmony_ci * @param dev    - pointer to our device structure,
374141cc406Sopenharmony_ci *                 it should contain all we need
375141cc406Sopenharmony_ci * @param pParam - pointer to the current scan parameters
376141cc406Sopenharmony_ci * @return - Nothing
377141cc406Sopenharmony_ci */
378141cc406Sopenharmony_cistatic void
379141cc406Sopenharmony_ciusb_GetScanRect( Plustek_Device *dev, ScanParam *sp )
380141cc406Sopenharmony_ci{
381141cc406Sopenharmony_ci	u_short   wDataPixelStart, wLineEnd;
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci	DCapsDef *sCaps = &dev->usbDev.Caps;
384141cc406Sopenharmony_ci	HWDef    *hw    = &dev->usbDev.HwSetting;
385141cc406Sopenharmony_ci	u_char   *regs  = dev->usbDev.a_bRegs;
386141cc406Sopenharmony_ci
387141cc406Sopenharmony_ci	/* Convert pixels to physical dpi based */
388141cc406Sopenharmony_ci	usb_GetPhyPixels( dev, sp );
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci	/* Compute data start pixel */
391141cc406Sopenharmony_ci#if 0
392141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */
393141cc406Sopenharmony_ci	if(sp->bCalibration != PARAM_Gain &&
394141cc406Sopenharmony_ci		sp->bCalibration != PARAM_Offset && ScanInf.m_fADF)
395141cc406Sopenharmony_ci		wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
396141cc406Sopenharmony_ci				(u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
397141cc406Sopenharmony_ci	else
398141cc406Sopenharmony_ci#endif
399141cc406Sopenharmony_ci		wDataPixelStart = (u_short)((u_long)sp->Origin.x *
400141cc406Sopenharmony_ci		                                            sCaps->OpticDpi.x / 300UL);
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci	/* during the calibration steps, we read the entire CCD data
403141cc406Sopenharmony_ci	 */
404141cc406Sopenharmony_ci	if((sp->bCalibration != PARAM_Gain)&&(sp->bCalibration != PARAM_Offset)) {
405141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */
406141cc406Sopenharmony_ci#if 0
407141cc406Sopenharmony_ci		if(ScanInf.m_fADF) {
408141cc406Sopenharmony_ci			wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
409141cc406Sopenharmony_ci			    (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5);
410141cc406Sopenharmony_ci		}
411141cc406Sopenharmony_ci#endif
412141cc406Sopenharmony_ci		wDataPixelStart += hw->wActivePixelsStart;
413141cc406Sopenharmony_ci	}
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci	wLineEnd = wDataPixelStart + (u_short)(m_dHDPIDivider *
416141cc406Sopenharmony_ci	                                               sp->Size.dwPhyPixels + 0.5);
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u\n",
419141cc406Sopenharmony_ci	                                               wDataPixelStart, wLineEnd );
420141cc406Sopenharmony_ci	if( wDataPixelStart & 1 ) {
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ci		wDataPixelStart++;
423141cc406Sopenharmony_ci		wLineEnd++;
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u (ADJ)\n",
426141cc406Sopenharmony_ci		                                           wDataPixelStart, wLineEnd );
427141cc406Sopenharmony_ci	}
428141cc406Sopenharmony_ci
429141cc406Sopenharmony_ci	regs[0x22] = _HIBYTE( wDataPixelStart );
430141cc406Sopenharmony_ci	regs[0x23] = _LOBYTE( wDataPixelStart );
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci	/* should match: wLineEnd-wDataPixelStart%(m_dHDPIDivider*2) = 0!! */
433141cc406Sopenharmony_ci	regs[0x24] = _HIBYTE( wLineEnd );
434141cc406Sopenharmony_ci	regs[0x25] = _LOBYTE( wLineEnd );
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci	DBG( _DBG_INFO2, ">> End-Start=%u, HDPI=%.2f\n",
437141cc406Sopenharmony_ci	                                 wLineEnd-wDataPixelStart, m_dHDPIDivider);
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci	/* Y origin */
440141cc406Sopenharmony_ci	if( sp->bCalibration == PARAM_Scan ) {
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci		if( hw->motorModel == MODEL_Tokyo600 ) {
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci			if(sp->PhyDpi.x <= 75)
445141cc406Sopenharmony_ci				sp->Origin.y += 20;
446141cc406Sopenharmony_ci			else if(sp->PhyDpi.x <= 100)
447141cc406Sopenharmony_ci			{
448141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Color)
449141cc406Sopenharmony_ci					sp->Origin.y += 0;
450141cc406Sopenharmony_ci				else
451141cc406Sopenharmony_ci					sp->Origin.y -= 6;
452141cc406Sopenharmony_ci			}
453141cc406Sopenharmony_ci			else if(sp->PhyDpi.x <= 150)
454141cc406Sopenharmony_ci			{
455141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Color)
456141cc406Sopenharmony_ci					sp->Origin.y -= 0;
457141cc406Sopenharmony_ci			}
458141cc406Sopenharmony_ci			else if(sp->PhyDpi.x <= 200)
459141cc406Sopenharmony_ci			{
460141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Color)
461141cc406Sopenharmony_ci					sp->Origin.y -= 10;
462141cc406Sopenharmony_ci				else
463141cc406Sopenharmony_ci					sp->Origin.y -= 4;
464141cc406Sopenharmony_ci			}
465141cc406Sopenharmony_ci			else if(sp->PhyDpi.x <= 300)
466141cc406Sopenharmony_ci			{
467141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Color)
468141cc406Sopenharmony_ci					sp->Origin.y += 16;
469141cc406Sopenharmony_ci				else
470141cc406Sopenharmony_ci					sp->Origin.y -= 18;
471141cc406Sopenharmony_ci			}
472141cc406Sopenharmony_ci			else if(sp->PhyDpi.x <= 400)
473141cc406Sopenharmony_ci			{
474141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Color)
475141cc406Sopenharmony_ci					sp->Origin.y += 15;
476141cc406Sopenharmony_ci				else if(sp->bDataType == SCANDATATYPE_BW)
477141cc406Sopenharmony_ci					sp->Origin.y += 4;
478141cc406Sopenharmony_ci			}
479141cc406Sopenharmony_ci			else /* if(sp->PhyDpi.x <= 600) */
480141cc406Sopenharmony_ci			{
481141cc406Sopenharmony_ci				if (sp->bDataType == SCANDATATYPE_Gray)
482141cc406Sopenharmony_ci					sp->Origin.y += 4;
483141cc406Sopenharmony_ci			}
484141cc406Sopenharmony_ci		}
485141cc406Sopenharmony_ci
486141cc406Sopenharmony_ci		/* Add gray mode offset (Green offset, we assume the CCD are
487141cc406Sopenharmony_ci		 * always be RGB or BGR order).
488141cc406Sopenharmony_ci		 */
489141cc406Sopenharmony_ci		if (sp->bDataType != SCANDATATYPE_Color)
490141cc406Sopenharmony_ci			sp->Origin.y += (u_long)(300UL *
491141cc406Sopenharmony_ci			           sCaps->bSensorDistance / sCaps->OpticDpi.y);
492141cc406Sopenharmony_ci	}
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci	sp->Origin.y=(u_short)((u_long)sp->Origin.y * hw->wMotorDpi/300UL);
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci	/* Something wrong, but I can not find it. */
497141cc406Sopenharmony_ci	if( hw->motorModel == MODEL_HuaLien && sCaps->OpticDpi.x == 600)
498141cc406Sopenharmony_ci		sp->Origin.y = sp->Origin.y * 297 / 298;
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci	DBG(_DBG_INFO2,"* Full Steps to Skip at Start = 0x%04x\n",
501141cc406Sopenharmony_ci	                sp->Origin.y);
502141cc406Sopenharmony_ci
503141cc406Sopenharmony_ci	regs[0x4a] = _HIBYTE( sp->Origin.y );
504141cc406Sopenharmony_ci	regs[0x4b] = _LOBYTE( sp->Origin.y );
505141cc406Sopenharmony_ci}
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci/** preset scan stepsize and fastfeed stepsize
508141cc406Sopenharmony_ci */
509141cc406Sopenharmony_cistatic void
510141cc406Sopenharmony_ciusb_PresetStepSize( Plustek_Device *dev, ScanParam *pParam )
511141cc406Sopenharmony_ci{
512141cc406Sopenharmony_ci	u_short ssize;
513141cc406Sopenharmony_ci	double  mclkdiv = pParam->dMCLK;
514141cc406Sopenharmony_ci	HWDef  *hw      = &dev->usbDev.HwSetting;
515141cc406Sopenharmony_ci	u_char *regs    = dev->usbDev.a_bRegs;
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci	ssize = (u_short)((double)CRYSTAL_FREQ / ( mclkdiv * 8.0 *
518141cc406Sopenharmony_ci            (double)m_bCM * hw->dMaxMotorSpeed * 4.0 * (double)hw->wMotorDpi));
519141cc406Sopenharmony_ci
520141cc406Sopenharmony_ci	regs[0x46] = _HIBYTE( ssize );
521141cc406Sopenharmony_ci	regs[0x47] = _LOBYTE( ssize );
522141cc406Sopenharmony_ci	regs[0x48] = _HIBYTE( ssize );
523141cc406Sopenharmony_ci	regs[0x49] = _LOBYTE( ssize );
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* StepSize(Preset) = %u (0x%04x)\n", ssize, ssize );
526141cc406Sopenharmony_ci}
527141cc406Sopenharmony_ci
528141cc406Sopenharmony_ci/** calculate default phase difference DPD
529141cc406Sopenharmony_ci */
530141cc406Sopenharmony_cistatic void
531141cc406Sopenharmony_ciusb_GetDPD( Plustek_Device *dev  )
532141cc406Sopenharmony_ci{
533141cc406Sopenharmony_ci	int    qtcnt;	/* quarter speed count count reg 51 b2..3 */
534141cc406Sopenharmony_ci	int    hfcnt;	/* half speed count reg 51 b0..1          */
535141cc406Sopenharmony_ci	int    strev;   /* steps to reverse reg 50                */
536141cc406Sopenharmony_ci	int    dpd;     /* calculated dpd reg 52:53               */
537141cc406Sopenharmony_ci	int    st;      /* step size reg 46:47                    */
538141cc406Sopenharmony_ci
539141cc406Sopenharmony_ci	HWDef  *hw    = &dev->usbDev.HwSetting;
540141cc406Sopenharmony_ci	u_char *regs  = dev->usbDev.a_bRegs;
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci	qtcnt = (regs[0x51] & 0x30) >> 4;  /* quarter speed count */
543141cc406Sopenharmony_ci	hfcnt = (regs[0x51] & 0xc0) >> 6;  /* half speed count    */
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci	if( _LM9831 == hw->chip )
546141cc406Sopenharmony_ci		strev = regs[0x50] & 0x3f;    /* steps to reverse */
547141cc406Sopenharmony_ci	else /* LM9832/3 */
548141cc406Sopenharmony_ci	{
549141cc406Sopenharmony_ci		if (qtcnt == 3)
550141cc406Sopenharmony_ci			qtcnt = 8;
551141cc406Sopenharmony_ci		if (hfcnt == 3)
552141cc406Sopenharmony_ci			hfcnt = 8;
553141cc406Sopenharmony_ci		strev = regs[0x50];           /* steps to reverse */
554141cc406Sopenharmony_ci	}
555141cc406Sopenharmony_ci
556141cc406Sopenharmony_ci	st = regs[0x46] * 256 + regs[0x47];     /* scan step size */
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci	if (m_wLineLength == 0)
559141cc406Sopenharmony_ci		dpd = 0;
560141cc406Sopenharmony_ci	else
561141cc406Sopenharmony_ci	{
562141cc406Sopenharmony_ci		dpd = (((qtcnt * 4) + (hfcnt * 2) + strev) * 4 * st) %
563141cc406Sopenharmony_ci		                            (m_wLineLength * m_bLineRateColor);
564141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* DPD =%u (0x%04x)\n", dpd, dpd );
565141cc406Sopenharmony_ci		dpd = m_wLineLength * m_bLineRateColor - dpd;
566141cc406Sopenharmony_ci	}
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* DPD =%u (0x%04x), step size=%u, steps2rev=%u\n",
569141cc406Sopenharmony_ci	                  dpd, dpd, st, strev);
570141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* llen=%u, lineRateColor=%u, qtcnt=%u, hfcnt=%u\n",
571141cc406Sopenharmony_ci	                  m_wLineLength, m_bLineRateColor, qtcnt, hfcnt );
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci	regs[0x51] |= (u_char)((dpd >> 16) & 0x03);
574141cc406Sopenharmony_ci	regs[0x52] = (u_char)(dpd >> 8);
575141cc406Sopenharmony_ci	regs[0x53] = (u_char)(dpd & 0xFF);
576141cc406Sopenharmony_ci}
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci#define MCLKDIV_SCALING 2
579141cc406Sopenharmony_ci#define _MIN(a,b) ((a) < (b) ? (a) : (b))
580141cc406Sopenharmony_ci#define _MAX(a,b) ((a) > (b) ? (a) : (b))
581141cc406Sopenharmony_ci
582141cc406Sopenharmony_ci/**
583141cc406Sopenharmony_ci */
584141cc406Sopenharmony_cistatic int
585141cc406Sopenharmony_ciusb_GetMCLKDiv( Plustek_Device *dev )
586141cc406Sopenharmony_ci{
587141cc406Sopenharmony_ci	int     j, pixelbits, pixelsperline, r;
588141cc406Sopenharmony_ci	int     minmclk, maxmclk, mclkdiv;
589141cc406Sopenharmony_ci	double  hdpi, min_int_time;
590141cc406Sopenharmony_ci	u_char *regs = dev->usbDev.a_bRegs;
591141cc406Sopenharmony_ci	HWDef  *hw   = &dev->usbDev.HwSetting;
592141cc406Sopenharmony_ci
593141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_GetMCLKDiv()\n" );
594141cc406Sopenharmony_ci
595141cc406Sopenharmony_ci	r = 8; /* line rate */
596141cc406Sopenharmony_ci	if ((regs[0x26] & 7) == 0)
597141cc406Sopenharmony_ci		r = 24; /* pixel rate */
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci	/* use high or low res min integration time */
600141cc406Sopenharmony_ci	min_int_time = ((regs[0x9]&7) > 2 ? hw->dMinIntegrationTimeLowres:
601141cc406Sopenharmony_ci	                                    hw->dMinIntegrationTimeHighres);
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci	minmclk = (int)ceil((double) MCLKDIV_SCALING * CRYSTAL_FREQ *
604141cc406Sopenharmony_ci	                       min_int_time /((double)1000. * r * m_wLineLength));
605141cc406Sopenharmony_ci	minmclk = _MAX(minmclk,MCLKDIV_SCALING);
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci	maxmclk = (int)(32.5*MCLKDIV_SCALING + .5);
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci	DBG(_DBG_INFO2,"- lower mclkdiv limit=%f\n",(double)minmclk/MCLKDIV_SCALING);
610141cc406Sopenharmony_ci	DBG(_DBG_INFO2,"- upper mclkdiv limit=%f\n",(double)maxmclk/MCLKDIV_SCALING);
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci	/* get the bits per pixel */
613141cc406Sopenharmony_ci	switch (regs[0x9] & 0x38) {
614141cc406Sopenharmony_ci		case 0:	    pixelbits=1; break;
615141cc406Sopenharmony_ci		case 0x8:   pixelbits=2; break;
616141cc406Sopenharmony_ci		case 0x10:  pixelbits=4; break;
617141cc406Sopenharmony_ci		case 0x18:  pixelbits=8; break;
618141cc406Sopenharmony_ci		default:	pixelbits=16;break;
619141cc406Sopenharmony_ci	}
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci	/* compute the horizontal dpi (pixels per inch) */
622141cc406Sopenharmony_ci	j    = regs[0x9] & 0x7;
623141cc406Sopenharmony_ci	hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1);
624141cc406Sopenharmony_ci
625141cc406Sopenharmony_ci	pixelsperline = (int)((256*regs[0x24]+regs[0x25]-256*regs[0x22]-regs[0x23])
626141cc406Sopenharmony_ci	                       *pixelbits/(hdpi * 8));
627141cc406Sopenharmony_ci	mclkdiv = (int)ceil((double)MCLKDIV_SCALING * pixelsperline * CRYSTAL_FREQ
628141cc406Sopenharmony_ci	                /((double) 8. * m_wLineLength * dev->transferRate));
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- hdpi          = %.3f\n", hdpi );
631141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- pixelbits     = %u\n", pixelbits );
632141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- pixelsperline = %u\n", pixelsperline );
633141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- linelen       = %u\n", m_wLineLength );
634141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- transferrate  = %lu\n", dev->transferRate );
635141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- MCLK Divider  = %u\n", mclkdiv/MCLKDIV_SCALING );
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci	mclkdiv = _MAX(mclkdiv,minmclk);
638141cc406Sopenharmony_ci	mclkdiv = _MIN(mclkdiv,maxmclk);
639141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "- Current MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING );
640141cc406Sopenharmony_ci
641141cc406Sopenharmony_ci	if( dev->transferRate == 2000000 ) {
642141cc406Sopenharmony_ci		while (mclkdiv * hdpi < 6.*MCLKDIV_SCALING) {
643141cc406Sopenharmony_ci			mclkdiv++;
644141cc406Sopenharmony_ci		}
645141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n",
646141cc406Sopenharmony_ci		     mclkdiv/MCLKDIV_SCALING );
647141cc406Sopenharmony_ci	}
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci	return mclkdiv;
650141cc406Sopenharmony_ci}
651141cc406Sopenharmony_ci
652141cc406Sopenharmony_ci/** Plusteks' poor-man MCLK calculation...
653141cc406Sopenharmony_ci * at least we give the master clock divider and adjust the step size
654141cc406Sopenharmony_ci * and integration time (for 14/16 bit modes)
655141cc406Sopenharmony_ci */
656141cc406Sopenharmony_cistatic double
657141cc406Sopenharmony_ciusb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam )
658141cc406Sopenharmony_ci{
659141cc406Sopenharmony_ci	double dMaxIntegrationTime;
660141cc406Sopenharmony_ci	double dMaxMCLKDivider;
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci	DCapsDef *sCaps = &dev->usbDev.Caps;
663141cc406Sopenharmony_ci	HWDef    *hw    = &dev->usbDev.HwSetting;
664141cc406Sopenharmony_ci	u_char   *regs  = dev->usbDev.a_bRegs;
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_GetMCLKDivider()\n" );
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_ci	if( dev->transferRate == 2000000 ) {
669141cc406Sopenharmony_ci		int mclkdiv = usb_GetMCLKDiv(dev);
670141cc406Sopenharmony_ci		pParam->dMCLK = (double)mclkdiv/MCLKDIV_SCALING;
671141cc406Sopenharmony_ci	}
672141cc406Sopenharmony_ci
673141cc406Sopenharmony_ci	m_dMCLKDivider = pParam->dMCLK;
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci	if (m_dHDPIDivider*m_dMCLKDivider >= 5.3/*6*/)
676141cc406Sopenharmony_ci		m_bIntTimeAdjust = 0;
677141cc406Sopenharmony_ci	else
678141cc406Sopenharmony_ci		m_bIntTimeAdjust = ceil( 5.3/*6.0*/ / (m_dHDPIDivider*m_dMCLKDivider));
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci	if( pParam->bCalibration == PARAM_Scan ) {
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci		usb_GetMCLKDiv(dev);
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci		/*  Compare Integration with USB speed to find the best ITA value */
685141cc406Sopenharmony_ci		if( pParam->bBitDepth > 8 )	{
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci			while( pParam->Size.dwPhyBytes >
688141cc406Sopenharmony_ci			       (m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) *
689141cc406Sopenharmony_ci 			       (1 + m_bIntTimeAdjust)) {
690141cc406Sopenharmony_ci				m_bIntTimeAdjust++;
691141cc406Sopenharmony_ci			}
692141cc406Sopenharmony_ci
693141cc406Sopenharmony_ci			if( hw->motorModel == MODEL_HuaLien &&
694141cc406Sopenharmony_ci				sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) {
695141cc406Sopenharmony_ci				m_bIntTimeAdjust = bMaxITA;
696141cc406Sopenharmony_ci			}
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci			if(((hw->motorModel == MODEL_HP) && (sCaps->bCCD == kNECSLIM))/* ||
699141cc406Sopenharmony_ci			 	( regs[0x26] & _ONE_CH_COLOR )*/) {
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci				bMaxITA = (u_char)floor((m_dMCLKDivider + 1) / 2.0);
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci				DBG( _DBG_INFO2, "* MaxITA (HP) = %u\n", bMaxITA );
704141cc406Sopenharmony_ci				if( m_bIntTimeAdjust > bMaxITA ) {
705141cc406Sopenharmony_ci					DBG( _DBG_INFO, "* ITA (%u) limited\n", m_bIntTimeAdjust );
706141cc406Sopenharmony_ci					m_bIntTimeAdjust = bMaxITA;
707141cc406Sopenharmony_ci				}
708141cc406Sopenharmony_ci			}
709141cc406Sopenharmony_ci		}
710141cc406Sopenharmony_ci	}
711141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* Integration Time Adjust = %u (HDPI=%.3f,MCLKD=%.3f)\n",
712141cc406Sopenharmony_ci	                    m_bIntTimeAdjust, m_dHDPIDivider, m_dMCLKDivider );
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci	regs[0x08] = (u_char)((m_dMCLKDivider - 1) * 2);
715141cc406Sopenharmony_ci	regs[0x19] = m_bIntTimeAdjust;
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci	if( m_bIntTimeAdjust != 0 ) {
718141cc406Sopenharmony_ci
719141cc406Sopenharmony_ci		m_wStepSize = (u_short)((u_long) m_wStepSize *
720141cc406Sopenharmony_ci		                    (m_bIntTimeAdjust + 1) / m_bIntTimeAdjust);
721141cc406Sopenharmony_ci		if( m_wStepSize < 2 )
722141cc406Sopenharmony_ci			m_wStepSize = 2;
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci		regs[0x46] = _HIBYTE(m_wStepSize);
725141cc406Sopenharmony_ci		regs[0x47] = _LOBYTE(m_wStepSize);
726141cc406Sopenharmony_ci
727141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
728141cc406Sopenharmony_ci		                   m_wStepSize, regs[0x46], regs[0x47] );
729141cc406Sopenharmony_ci	    usb_GetDPD( dev );
730141cc406Sopenharmony_ci	}
731141cc406Sopenharmony_ci
732141cc406Sopenharmony_ci	/* Compute maximum MCLK divider base on maximum integration time for
733141cc406Sopenharmony_ci	 * high lamp PWM, use equation 4
734141cc406Sopenharmony_ci	 */
735141cc406Sopenharmony_ci	dMaxIntegrationTime = hw->dIntegrationTimeHighLamp;
736141cc406Sopenharmony_ci	dMaxMCLKDivider = (double)CRYSTAL_FREQ * dMaxIntegrationTime /
737141cc406Sopenharmony_ci	                                    (1000 * 8 * m_bCM * m_wLineLength);
738141cc406Sopenharmony_ci
739141cc406Sopenharmony_ci	/* Determine lamp PWM setting */
740141cc406Sopenharmony_ci	if( m_dMCLKDivider > dMaxMCLKDivider ) {
741141cc406Sopenharmony_ci
742141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleLow\n" );
743141cc406Sopenharmony_ci		regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleLow );
744141cc406Sopenharmony_ci		regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleLow );
745141cc406Sopenharmony_ci
746141cc406Sopenharmony_ci	} else {
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleHigh\n" );
749141cc406Sopenharmony_ci		regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleHigh );
750141cc406Sopenharmony_ci		regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleHigh );
751141cc406Sopenharmony_ci	}
752141cc406Sopenharmony_ci
753141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* Current MCLK Divider = %f\n", m_dMCLKDivider );
754141cc406Sopenharmony_ci	return m_dMCLKDivider;
755141cc406Sopenharmony_ci}
756141cc406Sopenharmony_ci
757141cc406Sopenharmony_ci/** calculate the step size of each scan step
758141cc406Sopenharmony_ci */
759141cc406Sopenharmony_cistatic void
760141cc406Sopenharmony_ciusb_GetStepSize( Plustek_Device *dev, ScanParam *pParam )
761141cc406Sopenharmony_ci{
762141cc406Sopenharmony_ci	HWDef  *hw  = &dev->usbDev.HwSetting;
763141cc406Sopenharmony_ci	u_char *regs = dev->usbDev.a_bRegs;
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci	/* Compute step size using equation 1 */
766141cc406Sopenharmony_ci	if (m_bIntTimeAdjust != 0) {
767141cc406Sopenharmony_ci		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
768141cc406Sopenharmony_ci		              m_bLineRateColor * (m_bIntTimeAdjust + 1)) /
769141cc406Sopenharmony_ci		              (4 * hw->wMotorDpi * m_bIntTimeAdjust));
770141cc406Sopenharmony_ci	} else {
771141cc406Sopenharmony_ci		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
772141cc406Sopenharmony_ci		               m_bLineRateColor) / (4 * hw->wMotorDpi));
773141cc406Sopenharmony_ci	}
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci	if (m_wStepSize < 2)
776141cc406Sopenharmony_ci		m_wStepSize = 2;
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci	m_wStepSize = m_wStepSize * 298 / 297;
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci	regs[0x46] = _HIBYTE( m_wStepSize );
781141cc406Sopenharmony_ci	regs[0x47] = _LOBYTE( m_wStepSize );
782141cc406Sopenharmony_ci
783141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
784141cc406Sopenharmony_ci	                  m_wStepSize, regs[0x46], regs[0x47] );
785141cc406Sopenharmony_ci}
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_ci/**
788141cc406Sopenharmony_ci */
789141cc406Sopenharmony_cistatic void
790141cc406Sopenharmony_ciusb_GetLineLength( Plustek_Device *dev, ScanParam *param )
791141cc406Sopenharmony_ci{
792141cc406Sopenharmony_ci/* [note]
793141cc406Sopenharmony_ci *  The ITA in this moment is always 0, it will be changed later when we
794141cc406Sopenharmony_ci *  calculate MCLK. This is very strange why this routine will not call
795141cc406Sopenharmony_ci *  again to get all new value after ITA was changed? If this routine
796141cc406Sopenharmony_ci *  never call again, maybe we remove all factor with ITA here.
797141cc406Sopenharmony_ci */
798141cc406Sopenharmony_ci	int tr;
799141cc406Sopenharmony_ci	int tpspd;  /* turbo/preview mode speed reg 0a b2..3                 */
800141cc406Sopenharmony_ci	int tpsel;  /* turbo/preview mode select reg 0a b0..1                */
801141cc406Sopenharmony_ci	int gbnd;   /* guardband duration reg 0e b4..7                       */
802141cc406Sopenharmony_ci	int dur;    /* pulse duration reg 0e b0..3                           */
803141cc406Sopenharmony_ci	int ntr;    /* number of tr pulses reg 0d b7                         */
804141cc406Sopenharmony_ci	int afeop;  /* scan mode, 0=pixel rate, 1=line rate,                 */
805141cc406Sopenharmony_ci	            /* 4=1 channel mode a, 5=1 channel mode b, reg 26 b0..2  */
806141cc406Sopenharmony_ci	int ctmode; /* CIS tr timing mode reg 19 b0..1                       */
807141cc406Sopenharmony_ci	int tp;     /* tpspd or 1 if tpsel=0                                 */
808141cc406Sopenharmony_ci	int b;      /* if ctmode=0, (ntr+1)*((2*gbnd)+dur+1), otherwise 1    */
809141cc406Sopenharmony_ci	int tradj;  /* ITA                                                   */
810141cc406Sopenharmony_ci	int en_tradj;
811141cc406Sopenharmony_ci	u_short      le;
812141cc406Sopenharmony_ci	HWDef       *hw    = &dev->usbDev.HwSetting;
813141cc406Sopenharmony_ci	ClkMotorDef *motor = usb_GetMotorSet( hw->motorModel );
814141cc406Sopenharmony_ci	u_char      *regs  = dev->usbDev.a_bRegs;
815141cc406Sopenharmony_ci
816141cc406Sopenharmony_ci	tpspd = (regs[0x0a] & 0x0c) >> 2;       /* turbo/preview mode speed  */
817141cc406Sopenharmony_ci	tpsel = regs[0x0a] & 3;                 /* turbo/preview mode select */
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci	gbnd = (regs[0x0e] & 0xf0) >> 4;        /* TR fi1 guardband duration */
820141cc406Sopenharmony_ci	dur = (regs[0x0e] & 0xf);               /* TR pulse duration         */
821141cc406Sopenharmony_ci
822141cc406Sopenharmony_ci	ntr = regs[0x0d] / 128;                 /* number of tr pulses       */
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci	afeop = regs[0x26] & 7;           /* afe op - 3 channel or 1 channel */
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci	tradj = regs[0x19] & 0x7f;                /* integration time adjust */
827141cc406Sopenharmony_ci	en_tradj = (tradj) ? 1 : 0;
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci	ctmode = (regs[0x0b] >> 3) & 3;                /* cis tr timing mode */
830141cc406Sopenharmony_ci
831141cc406Sopenharmony_ci	m_bLineRateColor = 1;
832141cc406Sopenharmony_ci	if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */
833141cc406Sopenharmony_ci		m_bLineRateColor = 3;
834141cc406Sopenharmony_ci
835141cc406Sopenharmony_ci	/* according to turbo/preview mode to set value */
836141cc406Sopenharmony_ci	if( tpsel == 0 ) {
837141cc406Sopenharmony_ci		tp = 1;
838141cc406Sopenharmony_ci	} else {
839141cc406Sopenharmony_ci		tp = tpspd + 2;
840141cc406Sopenharmony_ci		if( tp == 5 )
841141cc406Sopenharmony_ci			tp++;
842141cc406Sopenharmony_ci	}
843141cc406Sopenharmony_ci
844141cc406Sopenharmony_ci	b = 1;
845141cc406Sopenharmony_ci	if( ctmode == 0 ) { /* CCD mode scanner*/
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci		b  = (ntr + 1) * ((2 * gbnd) + dur + 1);
848141cc406Sopenharmony_ci		b += (1 - ntr) * en_tradj;
849141cc406Sopenharmony_ci	}
850141cc406Sopenharmony_ci	if( ctmode == 2 )   /* CIS mode scanner */
851141cc406Sopenharmony_ci	    b = 3;
852141cc406Sopenharmony_ci
853141cc406Sopenharmony_ci	/* it might be necessary to tweak this value, to keep the
854141cc406Sopenharmony_ci	 * MCLK constant - see some sheet-fed devices
855141cc406Sopenharmony_ci	 */
856141cc406Sopenharmony_ci	le = hw->wLineEnd;
857141cc406Sopenharmony_ci	if (motor->dpi_thresh != 0) {
858141cc406Sopenharmony_ci		if( param->PhyDpi.y <= motor->dpi_thresh) {
859141cc406Sopenharmony_ci			le = motor->lineend;
860141cc406Sopenharmony_ci			DBG( _DBG_INFO2, "* Adjusting lineend: %u\n", le);
861141cc406Sopenharmony_ci		}
862141cc406Sopenharmony_ci		regs[0x20] = _HIBYTE( le );
863141cc406Sopenharmony_ci		regs[0x21] = _LOBYTE( le );
864141cc406Sopenharmony_ci	}
865141cc406Sopenharmony_ci
866141cc406Sopenharmony_ci	tr = m_bLineRateColor * (le + tp * (b + 3 - ntr));
867141cc406Sopenharmony_ci
868141cc406Sopenharmony_ci	if( tradj == 0 ) {
869141cc406Sopenharmony_ci		if( ctmode == 0 )
870141cc406Sopenharmony_ci			tr += m_bLineRateColor;
871141cc406Sopenharmony_ci	} else {
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci		int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix;
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci		/* Line color or gray mode */
876141cc406Sopenharmony_ci		if( afeop != 0 ) {
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci			le_phi      = (tradj + 1) / 2 + 1 + 6;
879141cc406Sopenharmony_ci			num_byteclk = ((le_phi + 8 * le + 8 * b + 4) /
880141cc406Sopenharmony_ci						   (8 * tradj)) + 1;
881141cc406Sopenharmony_ci			num_mclkf   = 8 * tradj * num_byteclk;
882141cc406Sopenharmony_ci			tr_fast_pix = num_byteclk;
883141cc406Sopenharmony_ci			extra_pix   = (num_mclkf - le_phi) % 8;
884141cc406Sopenharmony_ci		}
885141cc406Sopenharmony_ci		else /* 3 channel pixel rate color */
886141cc406Sopenharmony_ci		{
887141cc406Sopenharmony_ci			le_phi      = (tradj + 1) / 2 + 1 + 10 + 12;
888141cc406Sopenharmony_ci			num_byteclk = ((le_phi + 3 * 8 * le + 3 * 8 * b + 3 * 4) /
889141cc406Sopenharmony_ci						   (3 * 8 * tradj)) + 1;
890141cc406Sopenharmony_ci			num_mclkf   = 3 * 8 * tradj * num_byteclk;
891141cc406Sopenharmony_ci			tr_fast_pix = num_byteclk;
892141cc406Sopenharmony_ci			extra_pix   = (num_mclkf - le_phi) % (3 * 8);
893141cc406Sopenharmony_ci		}
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci		tr = b + le + 4 + tr_fast_pix;
896141cc406Sopenharmony_ci		if (extra_pix == 0)
897141cc406Sopenharmony_ci			tr++;
898141cc406Sopenharmony_ci		tr *= m_bLineRateColor;
899141cc406Sopenharmony_ci	}
900141cc406Sopenharmony_ci	m_wLineLength = tr / m_bLineRateColor;
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* LineLength=%d, LineRateColor=%u\n",
903141cc406Sopenharmony_ci	                    m_wLineLength, m_bLineRateColor );
904141cc406Sopenharmony_ci}
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci/** usb_GetMotorParam
907141cc406Sopenharmony_ci * registers 0x56, 0x57
908141cc406Sopenharmony_ci */
909141cc406Sopenharmony_cistatic void
910141cc406Sopenharmony_ciusb_GetMotorParam( Plustek_Device *dev, ScanParam *pParam )
911141cc406Sopenharmony_ci{
912141cc406Sopenharmony_ci	int          idx, i;
913141cc406Sopenharmony_ci	ClkMotorDef *clk;
914141cc406Sopenharmony_ci	MDef        *md;
915141cc406Sopenharmony_ci	DCapsDef    *sCaps = &dev->usbDev.Caps;
916141cc406Sopenharmony_ci	HWDef       *hw    = &dev->usbDev.HwSetting;
917141cc406Sopenharmony_ci	u_char      *regs  = dev->usbDev.a_bRegs;
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci	if (!_IS_PLUSTEKMOTOR(hw->motorModel)) {
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci		clk = usb_GetMotorSet( hw->motorModel );
922141cc406Sopenharmony_ci		md  = clk->motor_sets;
923141cc406Sopenharmony_ci		idx = 0;
924141cc406Sopenharmony_ci		for( i = 0; i < _MAX_CLK; i++ ) {
925141cc406Sopenharmony_ci			if( pParam->PhyDpi.y <= dpi_ranges[i] )
926141cc406Sopenharmony_ci				break;
927141cc406Sopenharmony_ci			idx++;
928141cc406Sopenharmony_ci		}
929141cc406Sopenharmony_ci		if( idx >= _MAX_CLK )
930141cc406Sopenharmony_ci			idx = _MAX_CLK - 1;
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_ci		regs[0x56] = md[idx].pwm;
933141cc406Sopenharmony_ci		regs[0x57] = md[idx].pwm_duty;
934141cc406Sopenharmony_ci
935141cc406Sopenharmony_ci		regs[0x43] = 0;
936141cc406Sopenharmony_ci		regs[0x44] = 0;
937141cc406Sopenharmony_ci
938141cc406Sopenharmony_ci		if( md[idx].scan_lines_per_line > 1 ) {
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci			if((pParam->bBitDepth > 8) &&
941141cc406Sopenharmony_ci				(pParam->bDataType == SCANDATATYPE_Color)) {
942141cc406Sopenharmony_ci
943141cc406Sopenharmony_ci				regs[0x43] = 0xff;
944141cc406Sopenharmony_ci				regs[0x44] = md[idx].scan_lines_per_line;
945141cc406Sopenharmony_ci
946141cc406Sopenharmony_ci				DBG( _DBG_INFO2, "* Line Skipping : 0x43=0x%02x, 0x44=0x%02x\n",
947141cc406Sopenharmony_ci				                  regs[0x43], regs[0x44] );
948141cc406Sopenharmony_ci			}
949141cc406Sopenharmony_ci		}
950141cc406Sopenharmony_ci	} else {
951141cc406Sopenharmony_ci
952141cc406Sopenharmony_ci		if( sCaps->OpticDpi.x == 1200 ) {
953141cc406Sopenharmony_ci
954141cc406Sopenharmony_ci			switch( hw->motorModel ) {
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci			case MODEL_HuaLien:
957141cc406Sopenharmony_ci			case MODEL_KaoHsiung:
958141cc406Sopenharmony_ci			default:
959141cc406Sopenharmony_ci				if(pParam->PhyDpi.x <= 200)
960141cc406Sopenharmony_ci				{
961141cc406Sopenharmony_ci					regs[0x56] = 1;
962141cc406Sopenharmony_ci					regs[0x57] = 48;  /* 63; */
963141cc406Sopenharmony_ci				}
964141cc406Sopenharmony_ci				else if(pParam->PhyDpi.x <= 300)
965141cc406Sopenharmony_ci				{
966141cc406Sopenharmony_ci					regs[0x56] = 2;   /* 8;  */
967141cc406Sopenharmony_ci					regs[0x57] = 48;  /* 56; */
968141cc406Sopenharmony_ci				}
969141cc406Sopenharmony_ci				else if(pParam->PhyDpi.x <= 400)
970141cc406Sopenharmony_ci				{
971141cc406Sopenharmony_ci					regs[0x56] = 8;
972141cc406Sopenharmony_ci					regs[0x57] = 48;
973141cc406Sopenharmony_ci				}
974141cc406Sopenharmony_ci				else if(pParam->PhyDpi.x <= 600)
975141cc406Sopenharmony_ci				{
976141cc406Sopenharmony_ci					regs[0x56] = 2;   /* 10; */
977141cc406Sopenharmony_ci					regs[0x57] = 48;  /* 56; */
978141cc406Sopenharmony_ci				}
979141cc406Sopenharmony_ci				else /* pParam->PhyDpi.x == 1200) */
980141cc406Sopenharmony_ci				{
981141cc406Sopenharmony_ci					regs[0x56] = 1;   /* 8;  */
982141cc406Sopenharmony_ci					regs[0x57] = 48;  /* 56; */
983141cc406Sopenharmony_ci				}
984141cc406Sopenharmony_ci				break;
985141cc406Sopenharmony_ci        	}
986141cc406Sopenharmony_ci        } else {
987141cc406Sopenharmony_ci        	switch ( hw->motorModel ) {
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci        	case MODEL_Tokyo600:
990141cc406Sopenharmony_ci        		regs[0x56] = 16;
991141cc406Sopenharmony_ci        		regs[0x57] = 4;	/* 2; */
992141cc406Sopenharmony_ci        		break;
993141cc406Sopenharmony_ci        	case MODEL_HuaLien:
994141cc406Sopenharmony_ci        		{
995141cc406Sopenharmony_ci        			if(pParam->PhyDpi.x <= 200)
996141cc406Sopenharmony_ci        			{
997141cc406Sopenharmony_ci        				regs[0x56] = 64;	/* 24; */
998141cc406Sopenharmony_ci        				regs[0x57] = 4;	/* 16; */
999141cc406Sopenharmony_ci        			}
1000141cc406Sopenharmony_ci        			else if(pParam->PhyDpi.x <= 300)
1001141cc406Sopenharmony_ci        			{
1002141cc406Sopenharmony_ci        				regs[0x56] = 64;	/* 16; */
1003141cc406Sopenharmony_ci        				regs[0x57] = 4;	/* 16; */
1004141cc406Sopenharmony_ci        			}
1005141cc406Sopenharmony_ci        			else if(pParam->PhyDpi.x <= 400)
1006141cc406Sopenharmony_ci        			{
1007141cc406Sopenharmony_ci        				regs[0x56] = 64;	/* 16; */
1008141cc406Sopenharmony_ci        				regs[0x57] = 4;	/* 16; */
1009141cc406Sopenharmony_ci        			}
1010141cc406Sopenharmony_ci        			else /* if(pParam->PhyDpi.x <= 600) */
1011141cc406Sopenharmony_ci        			{
1012141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */
1013141cc406Sopenharmony_ci#if 0
1014141cc406Sopenharmony_ci        				if(ScanInf.m_fADF)
1015141cc406Sopenharmony_ci        				{
1016141cc406Sopenharmony_ci        					regs[0x56] = 8;
1017141cc406Sopenharmony_ci        					regs[0x57] = 48;
1018141cc406Sopenharmony_ci        				}
1019141cc406Sopenharmony_ci        				else
1020141cc406Sopenharmony_ci#endif
1021141cc406Sopenharmony_ci        				{
1022141cc406Sopenharmony_ci        					regs[0x56] = 64;	/* 2;  */
1023141cc406Sopenharmony_ci        					regs[0x57] = 4;	/* 48; */
1024141cc406Sopenharmony_ci        				}
1025141cc406Sopenharmony_ci        			}
1026141cc406Sopenharmony_ci        		}
1027141cc406Sopenharmony_ci        		break;
1028141cc406Sopenharmony_ci        	case MODEL_KaoHsiung:
1029141cc406Sopenharmony_ci        	default:
1030141cc406Sopenharmony_ci        		if(pParam->PhyDpi.x <= 200)
1031141cc406Sopenharmony_ci        		{
1032141cc406Sopenharmony_ci        			regs[0x56] = 24;
1033141cc406Sopenharmony_ci        			regs[0x57] = 16;
1034141cc406Sopenharmony_ci        		}
1035141cc406Sopenharmony_ci        		else if(pParam->PhyDpi.x <= 300)
1036141cc406Sopenharmony_ci        		{
1037141cc406Sopenharmony_ci        			regs[0x56] = 16;
1038141cc406Sopenharmony_ci        			regs[0x57] = 16;
1039141cc406Sopenharmony_ci        		}
1040141cc406Sopenharmony_ci        		else if(pParam->PhyDpi.x <= 400)
1041141cc406Sopenharmony_ci        		{
1042141cc406Sopenharmony_ci        			regs[0x56] = 16;
1043141cc406Sopenharmony_ci        			regs[0x57] = 16;
1044141cc406Sopenharmony_ci        		}
1045141cc406Sopenharmony_ci        		else /* if(pParam->PhyDpi.x <= 600) */
1046141cc406Sopenharmony_ci        		{
1047141cc406Sopenharmony_ci        			regs[0x56] = 2;
1048141cc406Sopenharmony_ci        			regs[0x57] = 48;
1049141cc406Sopenharmony_ci        		}
1050141cc406Sopenharmony_ci        		break;
1051141cc406Sopenharmony_ci        	}
1052141cc406Sopenharmony_ci        }
1053141cc406Sopenharmony_ci	}
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* MOTOR-Settings: PWM=0x%02x, PWM_DUTY=0x%02x\n",
1056141cc406Sopenharmony_ci	                 regs[0x56], regs[0x57] );
1057141cc406Sopenharmony_ci}
1058141cc406Sopenharmony_ci
1059141cc406Sopenharmony_ci/**
1060141cc406Sopenharmony_ci */
1061141cc406Sopenharmony_cistatic void
1062141cc406Sopenharmony_ciusb_GetPauseLimit( Plustek_Device *dev, ScanParam *pParam )
1063141cc406Sopenharmony_ci{
1064141cc406Sopenharmony_ci	int     coeffsize, scaler;
1065141cc406Sopenharmony_ci	HWDef  *hw   = &dev->usbDev.HwSetting;
1066141cc406Sopenharmony_ci	u_char *regs = dev->usbDev.a_bRegs;
1067141cc406Sopenharmony_ci
1068141cc406Sopenharmony_ci	scaler = 1;
1069141cc406Sopenharmony_ci	if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1070141cc406Sopenharmony_ci		if( pParam->bDataType == SCANDATATYPE_Color ) {
1071141cc406Sopenharmony_ci			scaler = 3;
1072141cc406Sopenharmony_ci		}
1073141cc406Sopenharmony_ci	}
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci	/* compute size of coefficient ram */
1076141cc406Sopenharmony_ci	coeffsize = 4 + 16 + 16;	/* gamma and shading and offset */
1077141cc406Sopenharmony_ci
1078141cc406Sopenharmony_ci	/* if 16 bit, then not all is used */
1079141cc406Sopenharmony_ci	if( regs[0x09] & 0x20 ) {
1080141cc406Sopenharmony_ci		coeffsize = 16 + 16;	/* no gamma */
1081141cc406Sopenharmony_ci	}
1082141cc406Sopenharmony_ci	coeffsize *= (2*3); /* 3 colors and 2 bytes/word */
1083141cc406Sopenharmony_ci
1084141cc406Sopenharmony_ci
1085141cc406Sopenharmony_ci	/* Get available buffer size in KB
1086141cc406Sopenharmony_ci	 * for 512kb this will be 296
1087141cc406Sopenharmony_ci	 * for 2Mb   this will be 1832
1088141cc406Sopenharmony_ci	 */
1089141cc406Sopenharmony_ci	m_dwPauseLimit = (u_long)(hw->wDRAMSize - (u_long)(coeffsize));
1090141cc406Sopenharmony_ci	m_dwPauseLimit -= ((pParam->Size.dwPhyBytes*scaler) / 1024 + 1);
1091141cc406Sopenharmony_ci
1092141cc406Sopenharmony_ci	/* If not reversing, take into account the steps to reverse */
1093141cc406Sopenharmony_ci	if( regs[0x50] == 0 )
1094141cc406Sopenharmony_ci		m_dwPauseLimit -= ((regs[0x54] & 7) *
1095141cc406Sopenharmony_ci		                  (pParam->Size.dwPhyBytes * scaler) + 1023) / 1024;
1096141cc406Sopenharmony_ci
1097141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* PL=%lu, coeffsize=%u, scaler=%u\n",
1098141cc406Sopenharmony_ci	                  m_dwPauseLimit, coeffsize, scaler );
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci	m_dwPauseLimit = usb_max( usb_min(m_dwPauseLimit,
1101141cc406Sopenharmony_ci	                  (u_long)ceil(pParam->Size.dwTotalBytes / 1024.0)), 2);
1102141cc406Sopenharmony_ci
1103141cc406Sopenharmony_ci	regs[0x4e] = (u_char)floor((m_dwPauseLimit*512.0)/(2.0*hw->wDRAMSize));
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci	if( regs[0x4e] > 1 ) {
1106141cc406Sopenharmony_ci		regs[0x4e]--;
1107141cc406Sopenharmony_ci		if(regs[0x4e] > 1)
1108141cc406Sopenharmony_ci			regs[0x4e]--;
1109141cc406Sopenharmony_ci	} else
1110141cc406Sopenharmony_ci		regs[0x4e] = 1;
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci	/* resume, when buffer is 2/8 kbytes full (512k/2M memory)
1113141cc406Sopenharmony_ci	 */
1114141cc406Sopenharmony_ci	regs[0x4f] = 1;
1115141cc406Sopenharmony_ci
1116141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* PauseLimit = %lu, [0x4e] = 0x%02x, [0x4f] = 0x%02x\n",
1117141cc406Sopenharmony_ci	                  m_dwPauseLimit, regs[0x4e], regs[0x4f] );
1118141cc406Sopenharmony_ci}
1119141cc406Sopenharmony_ci
1120141cc406Sopenharmony_ci/** usb_GetScanLinesAndSize
1121141cc406Sopenharmony_ci */
1122141cc406Sopenharmony_cistatic void
1123141cc406Sopenharmony_ciusb_GetScanLinesAndSize( Plustek_Device *dev, ScanParam *pParam )
1124141cc406Sopenharmony_ci{
1125141cc406Sopenharmony_ci	DCapsDef *sCaps = &dev->usbDev.Caps;
1126141cc406Sopenharmony_ci
1127141cc406Sopenharmony_ci	pParam->Size.dwPhyLines = (u_long)ceil((double) pParam->Size.dwLines *
1128141cc406Sopenharmony_ci	                                     pParam->PhyDpi.y / pParam->UserDpi.y);
1129141cc406Sopenharmony_ci
1130141cc406Sopenharmony_ci	/* Calculate color offset */
1131141cc406Sopenharmony_ci	if (pParam->bCalibration == PARAM_Scan && pParam->bChannels == 3) {
1132141cc406Sopenharmony_ci
1133141cc406Sopenharmony_ci		dev->scanning.bLineDistance = sCaps->bSensorDistance *
1134141cc406Sopenharmony_ci		                                  pParam->PhyDpi.y / sCaps->OpticDpi.x;
1135141cc406Sopenharmony_ci		pParam->Size.dwPhyLines += (dev->scanning.bLineDistance << 1);
1136141cc406Sopenharmony_ci	}
1137141cc406Sopenharmony_ci	else
1138141cc406Sopenharmony_ci		dev->scanning.bLineDistance = 0;
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci	pParam->Size.dwTotalBytes = pParam->Size.dwPhyBytes * pParam->Size.dwPhyLines;
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci	DBG( _DBG_INFO, "* PhyBytes   = %lu\n", pParam->Size.dwPhyBytes );
1143141cc406Sopenharmony_ci	DBG( _DBG_INFO, "* PhyLines   = %lu\n", pParam->Size.dwPhyLines );
1144141cc406Sopenharmony_ci	DBG( _DBG_INFO, "* TotalBytes = %lu\n", pParam->Size.dwTotalBytes );
1145141cc406Sopenharmony_ci}
1146141cc406Sopenharmony_ci
1147141cc406Sopenharmony_ci/** function to preset/reset the merlin registers
1148141cc406Sopenharmony_ci */
1149141cc406Sopenharmony_cistatic SANE_Bool
1150141cc406Sopenharmony_ciusb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam )
1151141cc406Sopenharmony_ci{
1152141cc406Sopenharmony_ci	static u_char reg8, reg38[6], reg48[2];
1153141cc406Sopenharmony_ci
1154141cc406Sopenharmony_ci	ScanDef   *scan    = &dev->scanning;
1155141cc406Sopenharmony_ci	ScanParam *pdParam = &dev->scanning.sParam;
1156141cc406Sopenharmony_ci	HWDef     *hw      = &dev->usbDev.HwSetting;
1157141cc406Sopenharmony_ci	u_char    *regs    = dev->usbDev.a_bRegs;
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_ci	m_pParam = pParam;
1160141cc406Sopenharmony_ci
1161141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_SetScanParameters()\n" );
1162141cc406Sopenharmony_ci
1163141cc406Sopenharmony_ci	if( !usb_IsScannerReady(dev))
1164141cc406Sopenharmony_ci		return SANE_FALSE;
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1167141cc406Sopenharmony_ci/* HEINER: dSaveMoveSpeed is only used in func EjectPaper!!!
1168141cc406Sopenharmony_ci		dSaveMoveSpeed = hw->dMaxMoveSpeed;
1169141cc406Sopenharmony_ci*/
1170141cc406Sopenharmony_ci		hw->dMaxMoveSpeed = 1.0;
1171141cc406Sopenharmony_ci		usb_MotorSelect( dev, SANE_TRUE );
1172141cc406Sopenharmony_ci		usb_MotorOn( dev, SANE_TRUE );
1173141cc406Sopenharmony_ci	}
1174141cc406Sopenharmony_ci
1175141cc406Sopenharmony_ci	/*
1176141cc406Sopenharmony_ci	 * calculate the basic settings...
1177141cc406Sopenharmony_ci	 */
1178141cc406Sopenharmony_ci	pParam->PhyDpi.x = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1179141cc406Sopenharmony_ci	pParam->PhyDpi.y = usb_SetAsicDpiY( dev, pParam->UserDpi.y );
1180141cc406Sopenharmony_ci
1181141cc406Sopenharmony_ci	usb_SetColorAndBits( dev, pParam );
1182141cc406Sopenharmony_ci	usb_GetScanRect    ( dev, pParam );
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci	usb_PresetStepSize( dev, pParam );
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci	if( dev->caps.dwFlag & SFLAG_ADF ) {
1187141cc406Sopenharmony_ci
1188141cc406Sopenharmony_ci		if( pParam->bCalibration == PARAM_Scan ) {
1189141cc406Sopenharmony_ci
1190141cc406Sopenharmony_ci			if( pdParam->bSource == SOURCE_ADF ) {
1191141cc406Sopenharmony_ci				regs[0x50] = 0;
1192141cc406Sopenharmony_ci				regs[0x51] = 0x40;
1193141cc406Sopenharmony_ci				if( pParam->PhyDpi.x <= 300)
1194141cc406Sopenharmony_ci					regs[0x54] = (regs[0x54] & ~7) | 4;	/* 3; */
1195141cc406Sopenharmony_ci				else
1196141cc406Sopenharmony_ci					regs[0x54] = (regs[0x54] & ~7) | 5;	/* 4; */
1197141cc406Sopenharmony_ci			} else {
1198141cc406Sopenharmony_ci				regs[0x50] = hw->bStepsToReverse;
1199141cc406Sopenharmony_ci				regs[0x51] = hw->bReg_0x51;
1200141cc406Sopenharmony_ci				regs[0x54] &= ~7;
1201141cc406Sopenharmony_ci			}
1202141cc406Sopenharmony_ci		} else
1203141cc406Sopenharmony_ci			regs[0x50] = 0;
1204141cc406Sopenharmony_ci	} else {
1205141cc406Sopenharmony_ci		if( pParam->bCalibration == PARAM_Scan )
1206141cc406Sopenharmony_ci			regs[0x50] = hw->bStepsToReverse;
1207141cc406Sopenharmony_ci		else
1208141cc406Sopenharmony_ci			regs[0x50] = 0;
1209141cc406Sopenharmony_ci	}
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci	/* Assume we will not use ITA */
1212141cc406Sopenharmony_ci	regs[0x19] = m_bIntTimeAdjust = 0;
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci	/* Get variables from calculation algorithms */
1215141cc406Sopenharmony_ci	if(!(pParam->bCalibration == PARAM_Scan &&
1216141cc406Sopenharmony_ci          pParam->bSource == SOURCE_ADF && dev->usbDev.fLastScanIsAdf )) {
1217141cc406Sopenharmony_ci
1218141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* Scan calculations...\n" );
1219141cc406Sopenharmony_ci		usb_GetLineLength ( dev, pParam );
1220141cc406Sopenharmony_ci		usb_GetStepSize   ( dev, pParam );
1221141cc406Sopenharmony_ci		usb_GetDPD        ( dev );
1222141cc406Sopenharmony_ci		usb_GetMCLKDivider( dev, pParam );
1223141cc406Sopenharmony_ci		usb_GetMotorParam ( dev, pParam );
1224141cc406Sopenharmony_ci	}
1225141cc406Sopenharmony_ci
1226141cc406Sopenharmony_ci	/* Compute fast feed step size, use equation 3 and equation 8 */
1227141cc406Sopenharmony_ci	if( m_dMCLKDivider < 1.0)
1228141cc406Sopenharmony_ci		m_dMCLKDivider = 1.0;
1229141cc406Sopenharmony_ci
1230141cc406Sopenharmony_ci	m_wFastFeedStepSize = (u_short)(CRYSTAL_FREQ /
1231141cc406Sopenharmony_ci	                          (m_dMCLKDivider * 8 * m_bCM * hw->dMaxMoveSpeed *
1232141cc406Sopenharmony_ci	                           4 * hw->wMotorDpi));
1233141cc406Sopenharmony_ci	/* CIS special ;-) */
1234141cc406Sopenharmony_ci	if((hw->bReg_0x26 & _ONE_CH_COLOR) && (m_bCM == 1)) {
1235141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "* CIS FFStep-Speedup\n" );
1236141cc406Sopenharmony_ci		m_wFastFeedStepSize /= 3;
1237141cc406Sopenharmony_ci	}
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci	if( m_bIntTimeAdjust != 0 )
1240141cc406Sopenharmony_ci		m_wFastFeedStepSize /= m_bIntTimeAdjust;
1241141cc406Sopenharmony_ci
1242141cc406Sopenharmony_ci	if(regs[0x0a])
1243141cc406Sopenharmony_ci		m_wFastFeedStepSize *= ((regs[0x0a] >> 2) + 2);
1244141cc406Sopenharmony_ci	regs[0x48] = _HIBYTE( m_wFastFeedStepSize );
1245141cc406Sopenharmony_ci	regs[0x49] = _LOBYTE( m_wFastFeedStepSize );
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci	DBG( _DBG_INFO2, "* FFStepSize = %u, [0x48] = 0x%02x, [0x49] = 0x%02x\n",
1248141cc406Sopenharmony_ci	                       m_wFastFeedStepSize, regs[0x48], regs[0x49] );
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci	/* Compute the number of lines to scan using actual Y resolution */
1251141cc406Sopenharmony_ci	usb_GetScanLinesAndSize( dev, pParam );
1252141cc406Sopenharmony_ci
1253141cc406Sopenharmony_ci	/* Pause limit should be bounded by total bytes to read
1254141cc406Sopenharmony_ci	 * so that the chassis will not move too far.
1255141cc406Sopenharmony_ci	 */
1256141cc406Sopenharmony_ci	usb_GetPauseLimit( dev, pParam );
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci	/* For ADF .... */
1259141cc406Sopenharmony_ci	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci		if( dev->usbDev.fLastScanIsAdf ) {
1262141cc406Sopenharmony_ci
1263141cc406Sopenharmony_ci			regs[0x08] = reg8;
1264141cc406Sopenharmony_ci			memcpy( &regs[0x38], reg38, sizeof(reg38));
1265141cc406Sopenharmony_ci			memcpy( &regs[0x48], reg48, sizeof(reg48));
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci		} else {
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci			reg8 = regs[0x08];
1270141cc406Sopenharmony_ci			memcpy( reg38, &regs[0x38], sizeof(reg38));
1271141cc406Sopenharmony_ci			memcpy( reg48, &regs[0x48], sizeof(reg48));
1272141cc406Sopenharmony_ci		}
1273141cc406Sopenharmony_ci		usb_MotorSelect( dev, SANE_TRUE );
1274141cc406Sopenharmony_ci	}
1275141cc406Sopenharmony_ci
1276141cc406Sopenharmony_ci	/* Reset LM983x's state machine before setting register values */
1277141cc406Sopenharmony_ci	if( !usbio_WriteReg( dev->fd, 0x18, 0x18 ))
1278141cc406Sopenharmony_ci		return SANE_FALSE;
1279141cc406Sopenharmony_ci
1280141cc406Sopenharmony_ci	usleep(200 * 1000); /* Need to delay at least xxx microseconds */
1281141cc406Sopenharmony_ci
1282141cc406Sopenharmony_ci	if( !usbio_WriteReg( dev->fd, 0x07, 0x20 ))
1283141cc406Sopenharmony_ci		return SANE_FALSE;
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_ci	if( !usbio_WriteReg( dev->fd, 0x19, 6 ))
1286141cc406Sopenharmony_ci		return SANE_FALSE;
1287141cc406Sopenharmony_ci
1288141cc406Sopenharmony_ci	regs[0x07] = 0;
1289141cc406Sopenharmony_ci	regs[0x28] = 0;
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci	/* set unused registers to 0 */
1292141cc406Sopenharmony_ci	memset( &regs[0x03], 0, 3 );
1293141cc406Sopenharmony_ci	memset( &regs[0x5f], 0, 0x7f-0x5f+1 );
1294141cc406Sopenharmony_ci
1295141cc406Sopenharmony_ci	if( !usb_IsSheetFedDevice(dev)) {
1296141cc406Sopenharmony_ci		/* we limit the possible scansteps to avoid, that the sensors bumps
1297141cc406Sopenharmony_ci		 * against the scanbed - not necessary for sheet-fed devices
1298141cc406Sopenharmony_ci		 */
1299141cc406Sopenharmony_ci		if(pParam->bCalibration==PARAM_Scan && pParam->bSource!=SOURCE_ADF) {
1300141cc406Sopenharmony_ci
1301141cc406Sopenharmony_ci			u_long  lines     = pParam->Size.dwPhyLines + scan->bLinesToSkip +
1302141cc406Sopenharmony_ci			                                          scan->dwLinesDiscard + 5;
1303141cc406Sopenharmony_ci			u_short scansteps = (u_short)ceil((double)lines*
1304141cc406Sopenharmony_ci			                                 hw->wMotorDpi / pParam->PhyDpi.y);
1305141cc406Sopenharmony_ci			DBG( _DBG_INFO, "* Scansteps=%u (%lu*%u/%u)\n", scansteps,  lines,
1306141cc406Sopenharmony_ci			                hw->wMotorDpi, pParam->PhyDpi.y );
1307141cc406Sopenharmony_ci			regs[0x4c] = _HIBYTE(scansteps);
1308141cc406Sopenharmony_ci			regs[0x4d] = _LOBYTE(scansteps);
1309141cc406Sopenharmony_ci		}
1310141cc406Sopenharmony_ci	}
1311141cc406Sopenharmony_ci
1312141cc406Sopenharmony_ci	/* set the merlin registers */
1313141cc406Sopenharmony_ci	_UIO(sanei_lm983x_write( dev->fd, 0x03, &regs[0x03], 3, SANE_TRUE));
1314141cc406Sopenharmony_ci	_UIO(sanei_lm983x_write( dev->fd, 0x08, &regs[0x08], 0x7f - 0x08+1, SANE_TRUE));
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci	usleep(100);
1317141cc406Sopenharmony_ci
1318141cc406Sopenharmony_ci	if( !usbio_WriteReg( dev->fd, 0x07, 0 ))
1319141cc406Sopenharmony_ci		return SANE_FALSE;
1320141cc406Sopenharmony_ci
1321141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_SetScanParameters() done.\n" );
1322141cc406Sopenharmony_ci	return SANE_TRUE;
1323141cc406Sopenharmony_ci}
1324141cc406Sopenharmony_ci
1325141cc406Sopenharmony_ci/**
1326141cc406Sopenharmony_ci */
1327141cc406Sopenharmony_cistatic SANE_Bool
1328141cc406Sopenharmony_ciusb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park )
1329141cc406Sopenharmony_ci{
1330141cc406Sopenharmony_ci	u_char  value;
1331141cc406Sopenharmony_ci	u_short inches;
1332141cc406Sopenharmony_ci	HWDef       *hw   = &dev->usbDev.HwSetting;
1333141cc406Sopenharmony_ci	DCapsDef    *sc   = &dev->usbDev.Caps;
1334141cc406Sopenharmony_ci	u_char      *regs = dev->usbDev.a_bRegs;
1335141cc406Sopenharmony_ci
1336141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_ScanBegin()\n" );
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci	if( !usb_Wait4ScanSample( dev ))
1339141cc406Sopenharmony_ci		return SANE_FALSE;
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci	/* save the request for usb_ScanEnd () */
1342141cc406Sopenharmony_ci	m_fAutoPark = auto_park;
1343141cc406Sopenharmony_ci
1344141cc406Sopenharmony_ci	/* Disable home sensor during scan, or the chassis cannot move */
1345141cc406Sopenharmony_ci	value = ((m_pParam->bCalibration == PARAM_Scan &&
1346141cc406Sopenharmony_ci	        m_pParam->bSource == SOURCE_ADF)? (regs[0x58] & ~7): 0);
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci	if(!usbio_WriteReg( dev->fd, 0x58, value ))
1349141cc406Sopenharmony_ci		return SANE_FALSE;
1350141cc406Sopenharmony_ci
1351141cc406Sopenharmony_ci	/* Check if scanner is ready for receiving command */
1352141cc406Sopenharmony_ci	if( !usb_IsScannerReady(dev))
1353141cc406Sopenharmony_ci		return SANE_FALSE;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci	/* Flush cache - only LM9831 (Source: National Semiconductors) */
1356141cc406Sopenharmony_ci	if( _LM9831 == hw->chip ) {
1357141cc406Sopenharmony_ci
1358141cc406Sopenharmony_ci		for(;;) {
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci			if( SANE_TRUE == cancelRead ) {
1361141cc406Sopenharmony_ci				DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" );
1362141cc406Sopenharmony_ci				return SANE_FALSE;
1363141cc406Sopenharmony_ci			}
1364141cc406Sopenharmony_ci
1365141cc406Sopenharmony_ci			_UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData ));
1366141cc406Sopenharmony_ci			if( m_bOldScanData ) {
1367141cc406Sopenharmony_ci
1368141cc406Sopenharmony_ci				u_long dwBytesToRead = m_bOldScanData * hw->wDRAMSize * 4;
1369141cc406Sopenharmony_ci				u_char *pBuffer      = malloc( sizeof(u_char) * dwBytesToRead );
1370141cc406Sopenharmony_ci
1371141cc406Sopenharmony_ci				DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n",
1372141cc406Sopenharmony_ci				                                dwBytesToRead, m_bOldScanData );
1373141cc406Sopenharmony_ci
1374141cc406Sopenharmony_ci				_UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer,
1375141cc406Sopenharmony_ci				                                  dwBytesToRead, SANE_FALSE ));
1376141cc406Sopenharmony_ci				free( pBuffer );
1377141cc406Sopenharmony_ci
1378141cc406Sopenharmony_ci			} else
1379141cc406Sopenharmony_ci				break;
1380141cc406Sopenharmony_ci		}
1381141cc406Sopenharmony_ci	}
1382141cc406Sopenharmony_ci
1383141cc406Sopenharmony_ci	/* Download map & Shading data */
1384141cc406Sopenharmony_ci	if(( m_pParam->bCalibration == PARAM_Scan && !usb_MapDownload( dev )) ||
1385141cc406Sopenharmony_ci	    !usb_DownloadShadingData( dev, m_pParam->bCalibration )) {
1386141cc406Sopenharmony_ci		return SANE_FALSE;
1387141cc406Sopenharmony_ci	}
1388141cc406Sopenharmony_ci
1389141cc406Sopenharmony_ci	/* Move chassis and start to read image data */
1390141cc406Sopenharmony_ci	if (!usbio_WriteReg( dev->fd, 0x07, 3 ))
1391141cc406Sopenharmony_ci		return SANE_FALSE;
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci	usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData );
1394141cc406Sopenharmony_ci	m_bOldScanData = 0;                     /* No data at all  */
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_ci	m_fStart = m_fFirst = SANE_TRUE;        /* Prepare to read */
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci	DBG( _DBG_DREGS, "Register Dump before reading data:\n" );
1399141cc406Sopenharmony_ci	dumpregs( dev->fd, NULL );
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ci	inches = (u_short)((m_pParam->Origin.y *300UL)/hw->wMotorDpi);
1402141cc406Sopenharmony_ci	DBG( _DBG_INFO2, ">>> INCH=%u, DOY=%u\n", inches, sc->Normal.DataOrigin.y );
1403141cc406Sopenharmony_ci	if( inches > sc->Normal.DataOrigin.y )
1404141cc406Sopenharmony_ci		usb_WaitPos( dev, 150, SANE_FALSE );
1405141cc406Sopenharmony_ci
1406141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_ScanBegin() done.\n" );
1407141cc406Sopenharmony_ci	return SANE_TRUE;
1408141cc406Sopenharmony_ci}
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci/** usb_ScanEnd
1411141cc406Sopenharmony_ci * stop all the processing stuff and reposition sensor back home
1412141cc406Sopenharmony_ci */
1413141cc406Sopenharmony_cistatic SANE_Bool
1414141cc406Sopenharmony_ciusb_ScanEnd( Plustek_Device *dev )
1415141cc406Sopenharmony_ci{
1416141cc406Sopenharmony_ci	u_char value;
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_ScanEnd(), start=%u, park=%u\n",
1419141cc406Sopenharmony_ci	                                                   m_fStart, m_fAutoPark );
1420141cc406Sopenharmony_ci	usbio_ReadReg( dev->fd, 0x07, &value );
1421141cc406Sopenharmony_ci	if( value == 3 || value != 2 )
1422141cc406Sopenharmony_ci		usbio_WriteReg( dev->fd, 0x07, 0 );
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_ci	if( m_fStart ) {
1425141cc406Sopenharmony_ci		m_fStart = SANE_FALSE;
1426141cc406Sopenharmony_ci
1427141cc406Sopenharmony_ci		if( m_fAutoPark )
1428141cc406Sopenharmony_ci			usb_ModuleToHome( dev, SANE_FALSE );
1429141cc406Sopenharmony_ci	}
1430141cc406Sopenharmony_ci	else if( SANE_TRUE == cancelRead ) {
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci		usb_ModuleToHome( dev, SANE_FALSE );
1433141cc406Sopenharmony_ci	}
1434141cc406Sopenharmony_ci	return SANE_TRUE;
1435141cc406Sopenharmony_ci}
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci/**
1438141cc406Sopenharmony_ci */
1439141cc406Sopenharmony_cistatic SANE_Bool
1440141cc406Sopenharmony_ciusb_IsDataAvailableInDRAM( Plustek_Device *dev )
1441141cc406Sopenharmony_ci{
1442141cc406Sopenharmony_ci	/* Compute polling timeout
1443141cc406Sopenharmony_ci	 *	Height (Inches) / MaxScanSpeed (Inches/Second) = Seconds to move the
1444141cc406Sopenharmony_ci     *  module from top to bottom. Then convert the seconds to milliseconds
1445141cc406Sopenharmony_ci     *  by multiply 1000. We add extra 2 seconds to get some tolerance.
1446141cc406Sopenharmony_ci     */
1447141cc406Sopenharmony_ci	u_char         a_bBand[3];
1448141cc406Sopenharmony_ci	long           dwTicks;
1449141cc406Sopenharmony_ci    struct timeval t;
1450141cc406Sopenharmony_ci	u_char         *regs = dev->usbDev.a_bRegs;
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" );
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ci	gettimeofday( &t, NULL);
1455141cc406Sopenharmony_ci	dwTicks = t.tv_sec + 30;
1456141cc406Sopenharmony_ci
1457141cc406Sopenharmony_ci	for(;;)	{
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci		_UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE ));
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci		gettimeofday( &t, NULL);
1462141cc406Sopenharmony_ci	    if( t.tv_sec > dwTicks )
1463141cc406Sopenharmony_ci			break;
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci		if( usb_IsEscPressed()) {
1466141cc406Sopenharmony_ci			DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n");
1467141cc406Sopenharmony_ci			return SANE_FALSE;
1468141cc406Sopenharmony_ci		}
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci		/* It is not stable for read */
1471141cc406Sopenharmony_ci		if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2]))
1472141cc406Sopenharmony_ci			continue;
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci		if( a_bBand[0] > m_bOldScanData ) {
1475141cc406Sopenharmony_ci
1476141cc406Sopenharmony_ci			if( m_pParam->bSource != SOURCE_Reflection )
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci				usleep(1000*(30 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1479141cc406Sopenharmony_ci			else
1480141cc406Sopenharmony_ci				usleep(1000*(20 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
1481141cc406Sopenharmony_ci
1482141cc406Sopenharmony_ci			DBG( _DBG_INFO, "Data is available\n" );
1483141cc406Sopenharmony_ci			return SANE_TRUE;
1484141cc406Sopenharmony_ci		}
1485141cc406Sopenharmony_ci	}
1486141cc406Sopenharmony_ci
1487141cc406Sopenharmony_ci	DBG( _DBG_INFO, "NO Data available\n" );
1488141cc406Sopenharmony_ci	return SANE_FALSE;
1489141cc406Sopenharmony_ci}
1490141cc406Sopenharmony_ci
1491141cc406Sopenharmony_ci/**
1492141cc406Sopenharmony_ci */
1493141cc406Sopenharmony_cistatic SANE_Bool
1494141cc406Sopenharmony_ciusb_ScanReadImage( Plustek_Device *dev, void *pBuf, u_long dwSize )
1495141cc406Sopenharmony_ci{
1496141cc406Sopenharmony_ci	u_char       *regs = dev->usbDev.a_bRegs;
1497141cc406Sopenharmony_ci	SANE_Status   res;
1498141cc406Sopenharmony_ci
1499141cc406Sopenharmony_ci	DBG( _DBG_READ, "usb_ScanReadImage(%lu)\n", dwSize );
1500141cc406Sopenharmony_ci
1501141cc406Sopenharmony_ci	if( m_fFirst ) {
1502141cc406Sopenharmony_ci
1503141cc406Sopenharmony_ci		m_fFirst = SANE_FALSE;
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci		/* Wait for data band ready */
1506141cc406Sopenharmony_ci		if (!usb_IsDataAvailableInDRAM( dev )) {
1507141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "Nothing to read...\n" );
1508141cc406Sopenharmony_ci			return SANE_FALSE;
1509141cc406Sopenharmony_ci		}
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci		/* restore the fast forward stepsize...*/
1512141cc406Sopenharmony_ci		sanei_lm983x_write(dev->fd, 0x48, &regs[0x48], 2, SANE_TRUE);
1513141cc406Sopenharmony_ci	}
1514141cc406Sopenharmony_ci	res = sanei_lm983x_read(dev->fd, 0x00, (u_char *)pBuf, dwSize, SANE_FALSE);
1515141cc406Sopenharmony_ci
1516141cc406Sopenharmony_ci	/* check for pressed ESC button, as sanei_lm983x_read() may take some time
1517141cc406Sopenharmony_ci	 */
1518141cc406Sopenharmony_ci	if( usb_IsEscPressed()) {
1519141cc406Sopenharmony_ci		DBG(_DBG_INFO,"usb_ScanReadImage() - Cancel detected...\n");
1520141cc406Sopenharmony_ci		return SANE_FALSE;
1521141cc406Sopenharmony_ci	}
1522141cc406Sopenharmony_ci
1523141cc406Sopenharmony_ci	DBG( _DBG_READ, "usb_ScanReadImage() done, result: %d\n", res );
1524141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD == res ) {
1525141cc406Sopenharmony_ci		return SANE_TRUE;
1526141cc406Sopenharmony_ci	}
1527141cc406Sopenharmony_ci
1528141cc406Sopenharmony_ci	DBG( _DBG_ERROR, "usb_ScanReadImage() failed\n" );
1529141cc406Sopenharmony_ci	return SANE_FALSE;
1530141cc406Sopenharmony_ci}
1531141cc406Sopenharmony_ci
1532141cc406Sopenharmony_ci/** calculate the number of pixels per line and lines out of a given
1533141cc406Sopenharmony_ci * crop-area. The size of the area is given on a 300dpi base!
1534141cc406Sopenharmony_ci */
1535141cc406Sopenharmony_cistatic void
1536141cc406Sopenharmony_ciusb_GetImageInfo( Plustek_Device *dev, ImgDef *pInfo, WinInfo *pSize )
1537141cc406Sopenharmony_ci{
1538141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_GetImageInfo()\n" );
1539141cc406Sopenharmony_ci
1540141cc406Sopenharmony_ci	pSize->dwPixels = (u_long)pInfo->crArea.cx * pInfo->xyDpi.x / 300UL;
1541141cc406Sopenharmony_ci	pSize->dwLines  = (u_long)pInfo->crArea.cy * pInfo->xyDpi.y / 300UL;
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci	DBG( _DBG_INFO2,"Area: cx=%u, cy=%u\n",pInfo->crArea.cx,pInfo->crArea.cy);
1544141cc406Sopenharmony_ci
1545141cc406Sopenharmony_ci	switch( pInfo->wDataType ) {
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci		case COLOR_TRUE48:
1548141cc406Sopenharmony_ci			pSize->dwBytes = pSize->dwPixels * 6UL;
1549141cc406Sopenharmony_ci			break;
1550141cc406Sopenharmony_ci
1551141cc406Sopenharmony_ci		case COLOR_TRUE24:
1552141cc406Sopenharmony_ci			if( dev->scanning.fGrayFromColor > 7 ){
1553141cc406Sopenharmony_ci				pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
1554141cc406Sopenharmony_ci				pSize->dwPixels = pSize->dwBytes * 8;
1555141cc406Sopenharmony_ci			} else {
1556141cc406Sopenharmony_ci				pSize->dwBytes = pSize->dwPixels * 3UL;
1557141cc406Sopenharmony_ci			}
1558141cc406Sopenharmony_ci			break;
1559141cc406Sopenharmony_ci
1560141cc406Sopenharmony_ci		case COLOR_GRAY16:
1561141cc406Sopenharmony_ci			pSize->dwBytes = pSize->dwPixels << 1;
1562141cc406Sopenharmony_ci			break;
1563141cc406Sopenharmony_ci
1564141cc406Sopenharmony_ci		case COLOR_256GRAY:
1565141cc406Sopenharmony_ci			pSize->dwBytes = pSize->dwPixels;
1566141cc406Sopenharmony_ci			break;
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci		default:
1569141cc406Sopenharmony_ci			pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
1570141cc406Sopenharmony_ci			pSize->dwPixels = pSize->dwBytes * 8;
1571141cc406Sopenharmony_ci			break;
1572141cc406Sopenharmony_ci	}
1573141cc406Sopenharmony_ci}
1574141cc406Sopenharmony_ci
1575141cc406Sopenharmony_ci/**
1576141cc406Sopenharmony_ci */
1577141cc406Sopenharmony_cistatic void
1578141cc406Sopenharmony_ciusb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo )
1579141cc406Sopenharmony_ci{
1580141cc406Sopenharmony_ci	HWDef     *hw     = &dev->usbDev.HwSetting;
1581141cc406Sopenharmony_ci	ScanParam *pParam = &dev->scanning.sParam;
1582141cc406Sopenharmony_ci
1583141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_SaveImageInfo()\n" );
1584141cc406Sopenharmony_ci
1585141cc406Sopenharmony_ci	/* Dpi & Origins */
1586141cc406Sopenharmony_ci	pParam->UserDpi  = pInfo->xyDpi;
1587141cc406Sopenharmony_ci	pParam->Origin.x = pInfo->crArea.x;
1588141cc406Sopenharmony_ci	pParam->Origin.y = pInfo->crArea.y;
1589141cc406Sopenharmony_ci
1590141cc406Sopenharmony_ci	/* Source & Bits */
1591141cc406Sopenharmony_ci	pParam->bBitDepth = 8;
1592141cc406Sopenharmony_ci
1593141cc406Sopenharmony_ci	switch( pInfo->wDataType ) {
1594141cc406Sopenharmony_ci
1595141cc406Sopenharmony_ci		case COLOR_TRUE48:
1596141cc406Sopenharmony_ci			pParam->bBitDepth = 16;
1597141cc406Sopenharmony_ci			/* fall through... */
1598141cc406Sopenharmony_ci
1599141cc406Sopenharmony_ci		case COLOR_TRUE24:
1600141cc406Sopenharmony_ci			pParam->bDataType = SCANDATATYPE_Color;
1601141cc406Sopenharmony_ci
1602141cc406Sopenharmony_ci			/* AFE operation: one or 3 channels ! */
1603141cc406Sopenharmony_ci			if( hw->bReg_0x26 & _ONE_CH_COLOR )
1604141cc406Sopenharmony_ci				pParam->bChannels = 1;
1605141cc406Sopenharmony_ci			else
1606141cc406Sopenharmony_ci				pParam->bChannels = 3;
1607141cc406Sopenharmony_ci			break;
1608141cc406Sopenharmony_ci
1609141cc406Sopenharmony_ci		case COLOR_GRAY16:
1610141cc406Sopenharmony_ci			pParam->bBitDepth = 16;
1611141cc406Sopenharmony_ci			/* fall through... */
1612141cc406Sopenharmony_ci
1613141cc406Sopenharmony_ci		case COLOR_256GRAY:
1614141cc406Sopenharmony_ci			pParam->bDataType = SCANDATATYPE_Gray;
1615141cc406Sopenharmony_ci			pParam->bChannels = 1;
1616141cc406Sopenharmony_ci			break;
1617141cc406Sopenharmony_ci
1618141cc406Sopenharmony_ci		default:
1619141cc406Sopenharmony_ci			pParam->bBitDepth = 1;
1620141cc406Sopenharmony_ci			pParam->bDataType = SCANDATATYPE_BW;
1621141cc406Sopenharmony_ci			pParam->bChannels = 1;
1622141cc406Sopenharmony_ci	}
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_ci	DBG( _DBG_INFO, "* dwFlag = 0x%08lx\n", pInfo->dwFlag );
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci	if( pInfo->dwFlag & SCANDEF_Transparency )
1627141cc406Sopenharmony_ci		pParam->bSource = SOURCE_Transparency;
1628141cc406Sopenharmony_ci	else if( pInfo->dwFlag & SCANDEF_Negative )
1629141cc406Sopenharmony_ci		pParam->bSource = SOURCE_Negative;
1630141cc406Sopenharmony_ci	else if( pInfo->dwFlag & SCANDEF_Adf )
1631141cc406Sopenharmony_ci		pParam->bSource = SOURCE_ADF;
1632141cc406Sopenharmony_ci	else
1633141cc406Sopenharmony_ci		pParam->bSource = SOURCE_Reflection;
1634141cc406Sopenharmony_ci
1635141cc406Sopenharmony_ci	/* it seems, that we need to adjust the Origin.x when we have a
1636141cc406Sopenharmony_ci	 * sheetfed device to avoid stripes in the resulting pictures
1637141cc406Sopenharmony_ci	 */
1638141cc406Sopenharmony_ci	if( usb_IsSheetFedDevice(dev)) {
1639141cc406Sopenharmony_ci
1640141cc406Sopenharmony_ci		int step, div, org, xdpi;
1641141cc406Sopenharmony_ci
1642141cc406Sopenharmony_ci		xdpi = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
1643141cc406Sopenharmony_ci
1644141cc406Sopenharmony_ci		if ((xdpi * 2) <= 300)
1645141cc406Sopenharmony_ci			div = 300;
1646141cc406Sopenharmony_ci		else if ((xdpi * 2) <= 600)
1647141cc406Sopenharmony_ci			div = 600;
1648141cc406Sopenharmony_ci		else if ((xdpi * 2) <= 1200)
1649141cc406Sopenharmony_ci			div = 1200;
1650141cc406Sopenharmony_ci		else
1651141cc406Sopenharmony_ci			div = 2400;
1652141cc406Sopenharmony_ci
1653141cc406Sopenharmony_ci		step = div / xdpi;
1654141cc406Sopenharmony_ci		org  = pParam->Origin.x;
1655141cc406Sopenharmony_ci
1656141cc406Sopenharmony_ci		pParam->Origin.x = (pParam->Origin.x / step) * step;
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci		if (org != pParam->Origin.x)
1659141cc406Sopenharmony_ci			DBG(_DBG_INFO, "* Origin.x adjusted: %i -> %i\n",
1660141cc406Sopenharmony_ci			               org, pParam->Origin.x);
1661141cc406Sopenharmony_ci	}
1662141cc406Sopenharmony_ci}
1663141cc406Sopenharmony_ci
1664141cc406Sopenharmony_ci/* END PLUSTEK-USBSCAN.C ....................................................*/
1665