1141cc406Sopenharmony_ci/*.............................................................................
2141cc406Sopenharmony_ci * Project : SANE library for Plustek flatbed scanners.
3141cc406Sopenharmony_ci *.............................................................................
4141cc406Sopenharmony_ci */
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci/** @file plustek-usb.c
7141cc406Sopenharmony_ci *  @brief The interface functions to the USB driver stuff.
8141cc406Sopenharmony_ci *
9141cc406Sopenharmony_ci * Based on sources acquired from Plustek Inc.<br>
10141cc406Sopenharmony_ci * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de>
11141cc406Sopenharmony_ci *
12141cc406Sopenharmony_ci * History:
13141cc406Sopenharmony_ci * - 0.40 - starting version of the USB support
14141cc406Sopenharmony_ci * - 0.41 - removed CHECK
15141cc406Sopenharmony_ci *        - added Canon to the manufacturer list
16141cc406Sopenharmony_ci * - 0.42 - added warmup stuff
17141cc406Sopenharmony_ci *        - added setmap function
18141cc406Sopenharmony_ci *        - changed detection stuff, so we first check whether
19141cc406Sopenharmony_ci *        - the vendor and product Ids match with the ones in our list
20141cc406Sopenharmony_ci * - 0.43 - cleanup
21141cc406Sopenharmony_ci * - 0.44 - changes to integration CIS based devices
22141cc406Sopenharmony_ci * - 0.45 - added skipFine assignment
23141cc406Sopenharmony_ci *        - added auto device name detection if only product and vendor id<br>
24141cc406Sopenharmony_ci *          has been specified
25141cc406Sopenharmony_ci *        - made 16-bit gray mode work
26141cc406Sopenharmony_ci *        - added special handling for Genius devices
27141cc406Sopenharmony_ci *        - added TPA autodetection for EPSON Photo
28141cc406Sopenharmony_ci *        - fixed bug that causes warmup each time autodetected<br>
29141cc406Sopenharmony_ci *          TPA on EPSON is used
30141cc406Sopenharmony_ci *        - removed Genius from PCB-Id check
31141cc406Sopenharmony_ci *        - added Compaq to the list
32141cc406Sopenharmony_ci *        - removed the scaler stuff for CIS devices
33141cc406Sopenharmony_ci *        - removed homeing stuff from readline function
34141cc406Sopenharmony_ci *        - fixed flag setting in usbDev_startScan()
35141cc406Sopenharmony_ci * - 0.46 - added additional branch to support alternate calibration
36141cc406Sopenharmony_ci * - 0.47 - added special handling with 0x400 vendor ID and model override
37141cc406Sopenharmony_ci *        - removed PATH_MAX
38141cc406Sopenharmony_ci *        - change usbDev_stopScan and usbDev_open prototype
39141cc406Sopenharmony_ci *        - cleanup
40141cc406Sopenharmony_ci * - 0.48 - added function usb_CheckAndCopyAdjs()
41141cc406Sopenharmony_ci * - 0.49 - changed autodetection
42141cc406Sopenharmony_ci *        - added support for LiDE25 (pid 0x2220)
43141cc406Sopenharmony_ci * - 0.50 - minor fix for startup reset
44141cc406Sopenharmony_ci *          removed unnecessary calls to usbio_ResetLM983x()
45141cc406Sopenharmony_ci *          1200DPI CIS devices don't use GrayFromColor any longer
46141cc406Sopenharmony_ci * - 0.51 - added Syscan to the vendor list
47141cc406Sopenharmony_ci *        - added SCANFLAG_Calibration handling
48141cc406Sopenharmony_ci * - 0.52 - added _WAF_LOFF_ON_START and _WAF_INC_DARKTGT
49141cc406Sopenharmony_ci *          handling in usbDev_startScan()
50141cc406Sopenharmony_ci *          added Visioneer
51141cc406Sopenharmony_ci * .
52141cc406Sopenharmony_ci * <hr>
53141cc406Sopenharmony_ci * This file is part of the SANE package.
54141cc406Sopenharmony_ci *
55141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
56141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
57141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the
58141cc406Sopenharmony_ci * License, or (at your option) any later version.
59141cc406Sopenharmony_ci *
60141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
61141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
62141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
63141cc406Sopenharmony_ci * General Public License for more details.
64141cc406Sopenharmony_ci *
65141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License
66141cc406Sopenharmony_ci * along with this program.  If not, see <https://www.gnu.org/licenses/>.
67141cc406Sopenharmony_ci *
68141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for
69141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE.
70141cc406Sopenharmony_ci *
71141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files
72141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the
73141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public
74141cc406Sopenharmony_ci * License.  Your use of that executable is in no way restricted on
75141cc406Sopenharmony_ci * account of linking the SANE library code into it.
76141cc406Sopenharmony_ci *
77141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why
78141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public
79141cc406Sopenharmony_ci * License.
80141cc406Sopenharmony_ci *
81141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in
82141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that
83141cc406Sopenharmony_ci * those changes may be distributed with this exception intact.
84141cc406Sopenharmony_ci *
85141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice
86141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications.
87141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice.
88141cc406Sopenharmony_ci * <hr>
89141cc406Sopenharmony_ci */
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci/** useful for description tables
92141cc406Sopenharmony_ci */
93141cc406Sopenharmony_citypedef struct {
94141cc406Sopenharmony_ci	int   id;
95141cc406Sopenharmony_ci	char *desc;
96141cc406Sopenharmony_ci	char *desc_alt;
97141cc406Sopenharmony_ci} TabDef, *pTabDef;
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci/** to allow different vendors...
100141cc406Sopenharmony_ci */
101141cc406Sopenharmony_cistatic TabDef usbVendors[] = {
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci	{ 0x07B3, "Plustek",         NULL     },
104141cc406Sopenharmony_ci	{ 0x0400, "NSC",             "Mustek" },
105141cc406Sopenharmony_ci	{ 0x0458, "KYE/Genius",      NULL     },
106141cc406Sopenharmony_ci	{ 0x03F0, "Hewlett-Packard", NULL     },
107141cc406Sopenharmony_ci	{ 0x04B8, "Epson",           NULL     },
108141cc406Sopenharmony_ci	{ 0x04A7, "Visioneer",       NULL     },
109141cc406Sopenharmony_ci	{ 0x04A9, "Canon",           NULL     },
110141cc406Sopenharmony_ci	{ 0x1606, "UMAX",            NULL     },
111141cc406Sopenharmony_ci	{ 0x049F, "Compaq",          NULL     },
112141cc406Sopenharmony_ci	{ 0x0A82, "Syscan",          NULL     },
113141cc406Sopenharmony_ci	{ 0x0A53, "PandP Co., Ltd.", NULL     },
114141cc406Sopenharmony_ci	{ 0xFFFF, NULL,              NULL     }
115141cc406Sopenharmony_ci};
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci/** we use at least 8 megs for scanning... */
118141cc406Sopenharmony_ci#define _SCANBUF_SIZE (8 * 1024 * 1024)
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_ci/********************** the USB scanner interface ****************************/
121141cc406Sopenharmony_ci
122141cc406Sopenharmony_ci/** remove the slash out of the model-name to obtain a valid filename
123141cc406Sopenharmony_ci */
124141cc406Sopenharmony_cistatic SANE_Bool usb_normFileName( char *fname, char* buffer, u_long max_len )
125141cc406Sopenharmony_ci{
126141cc406Sopenharmony_ci	char *src, *dst;
127141cc406Sopenharmony_ci
128141cc406Sopenharmony_ci	if( NULL == fname )
129141cc406Sopenharmony_ci		return SANE_FALSE;
130141cc406Sopenharmony_ci
131141cc406Sopenharmony_ci	if( strlen( fname ) >= max_len )
132141cc406Sopenharmony_ci		return SANE_FALSE;
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci	src = fname;
135141cc406Sopenharmony_ci	dst = buffer;
136141cc406Sopenharmony_ci	while( *src != '\0' ) {
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci		if((*src == '/') || isspace(*src) || ispunct(*src))
139141cc406Sopenharmony_ci			*dst = '_';
140141cc406Sopenharmony_ci		else
141141cc406Sopenharmony_ci			*dst = *src;
142141cc406Sopenharmony_ci
143141cc406Sopenharmony_ci		dst++;
144141cc406Sopenharmony_ci		src++;
145141cc406Sopenharmony_ci	}
146141cc406Sopenharmony_ci	*dst = '\0';
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci	return SANE_TRUE;
149141cc406Sopenharmony_ci}
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci/** do some range checking and copy the adjustment values from the
152141cc406Sopenharmony_ci * frontend to our internal structures, so that the backend can take
153141cc406Sopenharmony_ci * care of them.
154141cc406Sopenharmony_ci */
155141cc406Sopenharmony_cistatic void usb_CheckAndCopyAdjs( Plustek_Device *dev )
156141cc406Sopenharmony_ci{
157141cc406Sopenharmony_ci	if( dev->adj.lampOff >= 0 )
158141cc406Sopenharmony_ci		dev->usbDev.dwLampOnPeriod = dev->adj.lampOff;
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci	if( dev->adj.lampOffOnEnd >= 0 )
161141cc406Sopenharmony_ci		dev->usbDev.bLampOffOnEnd = dev->adj.lampOffOnEnd;
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci	if( dev->adj.skipCalibration > 0 )
164141cc406Sopenharmony_ci		dev->usbDev.Caps.workaroundFlag |= _WAF_BYPASS_CALIBRATION;
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci	if( dev->adj.skipFine > 0 )
167141cc406Sopenharmony_ci		dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_FINE;
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci	if( dev->adj.skipFineWhite > 0 )
170141cc406Sopenharmony_ci		dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_WHITEFINE;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci	if( dev->adj.incDarkTgt > 0 )
173141cc406Sopenharmony_ci		dev->usbDev.Caps.workaroundFlag |= _WAF_INC_DARKTGT;
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci	if( dev->adj.skipDarkStrip > 0 )
176141cc406Sopenharmony_ci		dev->usbDev.Caps.Normal.DarkShadOrgY = -1;
177141cc406Sopenharmony_ci
178141cc406Sopenharmony_ci	if( dev->adj.invertNegatives > 0 )
179141cc406Sopenharmony_ci		dev->usbDev.Caps.workaroundFlag |= _WAF_INV_NEGATIVE_MAP;
180141cc406Sopenharmony_ci}
181141cc406Sopenharmony_ci
182141cc406Sopenharmony_ci/**
183141cc406Sopenharmony_ci * assign the values to the structures used by the currently found scanner
184141cc406Sopenharmony_ci */
185141cc406Sopenharmony_cistatic void
186141cc406Sopenharmony_ciusb_initDev( Plustek_Device *dev, int idx, int handle, int vendor )
187141cc406Sopenharmony_ci{
188141cc406Sopenharmony_ci	char     *ptr;
189141cc406Sopenharmony_ci	char      tmp_str1[PATH_MAX];
190141cc406Sopenharmony_ci	char      tmp_str2[PATH_MAX];
191141cc406Sopenharmony_ci	int       i;
192141cc406Sopenharmony_ci	ScanParam sParam;
193141cc406Sopenharmony_ci	u_short   tmp = 0;
194141cc406Sopenharmony_ci	int       ret = 0;
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usb_initDev(%d,0x%04x,%i)\n",
197141cc406Sopenharmony_ci	                idx, vendor, dev->initialized );
198141cc406Sopenharmony_ci	/* save capability flags... */
199141cc406Sopenharmony_ci	if( dev->initialized >= 0 ) {
200141cc406Sopenharmony_ci		tmp = DEVCAPSFLAG_TPA;
201141cc406Sopenharmony_ci	}
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci	/* copy the original values... */
204141cc406Sopenharmony_ci	memcpy( &dev->usbDev.Caps, Settings[idx].pDevCaps, sizeof(DCapsDef));
205141cc406Sopenharmony_ci	memcpy( &dev->usbDev.HwSetting, Settings[idx].pHwDef, sizeof(HWDef));
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci	/* restore capability flags... */
208141cc406Sopenharmony_ci	if( dev->initialized >= 0 ) {
209141cc406Sopenharmony_ci		dev->usbDev.Caps.wFlags |= tmp;
210141cc406Sopenharmony_ci	}
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci	usb_CheckAndCopyAdjs( dev );
213141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Device WAF  : 0x%08lx\n", dev->usbDev.Caps.workaroundFlag );
214141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Transferrate: %lu Bytes/s\n", dev->transferRate );
215141cc406Sopenharmony_ci
216141cc406Sopenharmony_ci	/* adjust data origin
217141cc406Sopenharmony_ci	 */
218141cc406Sopenharmony_ci	dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x;
219141cc406Sopenharmony_ci	dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y;
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci	dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x;
222141cc406Sopenharmony_ci	dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y;
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci	dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x;
225141cc406Sopenharmony_ci	dev->usbDev.Caps.Normal.DataOrigin.y -= dev->adj.pos.y;
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci	/** adjust shading position
228141cc406Sopenharmony_ci	 */
229141cc406Sopenharmony_ci	if( dev->adj.posShadingY >= 0 )
230141cc406Sopenharmony_ci		dev->usbDev.Caps.Normal.ShadingOriginY   = dev->adj.posShadingY;
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci	if( dev->adj.tpaShadingY >= 0 )
233141cc406Sopenharmony_ci		dev->usbDev.Caps.Positive.ShadingOriginY = dev->adj.tpaShadingY;
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci	if( dev->adj.negShadingY >= 0 )
236141cc406Sopenharmony_ci		dev->usbDev.Caps.Negative.ShadingOriginY = dev->adj.negShadingY;
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci	/* adjust the gamma settings... */
239141cc406Sopenharmony_ci	if( dev->adj.rgamma == 1.0 )
240141cc406Sopenharmony_ci		dev->adj.rgamma = dev->usbDev.HwSetting.gamma;
241141cc406Sopenharmony_ci	if( dev->adj.ggamma == 1.0 )
242141cc406Sopenharmony_ci		dev->adj.ggamma = dev->usbDev.HwSetting.gamma;
243141cc406Sopenharmony_ci	if( dev->adj.bgamma == 1.0 )
244141cc406Sopenharmony_ci		dev->adj.bgamma = dev->usbDev.HwSetting.gamma;
245141cc406Sopenharmony_ci	if( dev->adj.graygamma == 1.0 )
246141cc406Sopenharmony_ci		dev->adj.graygamma = dev->usbDev.HwSetting.gamma;
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci	/* the following you normally get from the registry...
249141cc406Sopenharmony_ci	 */
250141cc406Sopenharmony_ci	bMaxITA = 0;     /* Maximum integration time adjust */
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci	dev->usbDev.ModelStr = Settings[idx].pModelString;
253141cc406Sopenharmony_ci
254141cc406Sopenharmony_ci	dev->fd = handle;
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci	if( dev->initialized < 0 ) {
257141cc406Sopenharmony_ci		if( usb_HasTPA( dev ))
258141cc406Sopenharmony_ci			dev->usbDev.Caps.wFlags |= DEVCAPSFLAG_TPA;
259141cc406Sopenharmony_ci	}
260141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Device Flags: 0x%08x\n", dev->usbDev.Caps.wFlags );
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci	/* well now we patch the vendor string...
263141cc406Sopenharmony_ci	 * if not found, the default vendor will be Plustek
264141cc406Sopenharmony_ci	 */
265141cc406Sopenharmony_ci	for( i = 0; usbVendors[i].desc != NULL; i++ ) {
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci		if( usbVendors[i].id == vendor ) {
268141cc406Sopenharmony_ci			dev->sane.vendor = usbVendors[i].desc;
269141cc406Sopenharmony_ci			if (dev->usbDev.Caps.workaroundFlag & _WAF_USE_ALT_DESC )
270141cc406Sopenharmony_ci				if (usbVendors[i].desc_alt )
271141cc406Sopenharmony_ci					dev->sane.vendor = usbVendors[i].desc_alt;
272141cc406Sopenharmony_ci			DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor );
273141cc406Sopenharmony_ci			break;
274141cc406Sopenharmony_ci		}
275141cc406Sopenharmony_ci	}
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci	dev->usbDev.dwTicksLampOn = 0;
278141cc406Sopenharmony_ci	dev->usbDev.currentLamp   = usb_GetLampStatus( dev );
279141cc406Sopenharmony_ci	usb_ResetRegisters( dev );
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci	if( dev->initialized >= 0 )
282141cc406Sopenharmony_ci		return;
283141cc406Sopenharmony_ci
284141cc406Sopenharmony_ci	usb_IsScannerReady( dev );
285141cc406Sopenharmony_ci
286141cc406Sopenharmony_ci	sParam.bBitDepth     = 8;
287141cc406Sopenharmony_ci	sParam.bCalibration  = PARAM_Scan;
288141cc406Sopenharmony_ci	sParam.bChannels     = 3;
289141cc406Sopenharmony_ci	sParam.bDataType     = SCANDATATYPE_Color;
290141cc406Sopenharmony_ci	sParam.bSource       = SOURCE_Reflection;
291141cc406Sopenharmony_ci	sParam.Origin.x      = 0;
292141cc406Sopenharmony_ci	sParam.Origin.y      = 0;
293141cc406Sopenharmony_ci	sParam.UserDpi.x     = 150;
294141cc406Sopenharmony_ci	sParam.UserDpi.y     = 150;
295141cc406Sopenharmony_ci	sParam.dMCLK         = 4;
296141cc406Sopenharmony_ci	sParam.Size.dwPixels = 0;
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci	/* create calibration-filename */
299141cc406Sopenharmony_ci	sprintf( tmp_str2, "%s-%s",
300141cc406Sopenharmony_ci	         dev->sane.vendor, dev->usbDev.ModelStr );
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci	if( !usb_normFileName( tmp_str2, tmp_str1, PATH_MAX )) {
303141cc406Sopenharmony_ci		strcpy( tmp_str1, "plustek-default" );
304141cc406Sopenharmony_ci	}
305141cc406Sopenharmony_ci
306141cc406Sopenharmony_ci	ptr = getenv ("HOME");
307141cc406Sopenharmony_ci	ret = ( NULL == ptr )?
308141cc406Sopenharmony_ci		snprintf( tmp_str2, sizeof(tmp_str2), "/tmp/%s", tmp_str1 ):
309141cc406Sopenharmony_ci		snprintf( tmp_str2, sizeof(tmp_str2), "%s/.sane/%s", ptr, tmp_str1 );
310141cc406Sopenharmony_ci
311141cc406Sopenharmony_ci	if ((ret < 0) || (ret > (int)sizeof(tmp_str2))) {
312141cc406Sopenharmony_ci		DBG( _DBG_WARNING,
313141cc406Sopenharmony_ci		     "Failed to generate calibration file path. Default substituted.\n" );
314141cc406Sopenharmony_ci		snprintf(tmp_str2, sizeof(tmp_str2), "/tmp/plustek-default");
315141cc406Sopenharmony_ci	}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci	dev->calFile = strdup( tmp_str2 );
318141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Calibration file-names set to:\n" );
319141cc406Sopenharmony_ci	DBG( _DBG_INFO, ">%s-coarse.cal<\n", dev->calFile );
320141cc406Sopenharmony_ci	DBG( _DBG_INFO, ">%s-fine.cal<\n", dev->calFile );
321141cc406Sopenharmony_ci
322141cc406Sopenharmony_ci	/* initialize the ASIC registers */
323141cc406Sopenharmony_ci	usb_SetScanParameters( dev, &sParam );
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci	/* check and move sensor to its home position */
326141cc406Sopenharmony_ci	usb_ModuleToHome( dev, SANE_FALSE );
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci	/* set the global flag, that we are initialized so far */
329141cc406Sopenharmony_ci	dev->initialized = idx;
330141cc406Sopenharmony_ci}
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci/**
333141cc406Sopenharmony_ci * will be used for retrieving a Plustek device
334141cc406Sopenharmony_ci */
335141cc406Sopenharmony_cistatic int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev )
336141cc406Sopenharmony_ci{
337141cc406Sopenharmony_ci	char   tmp[50];
338141cc406Sopenharmony_ci	char   pcbStr[10];
339141cc406Sopenharmony_ci	u_char reg59[3], reg59s[3], pcbID;
340141cc406Sopenharmony_ci	int    i, result;
341141cc406Sopenharmony_ci
342141cc406Sopenharmony_ci	/*
343141cc406Sopenharmony_ci	 * Plustek uses the misc IO 12 to get the PCB ID
344141cc406Sopenharmony_ci	 * (PCB = printed circuit board), so it's possible to have one
345141cc406Sopenharmony_ci	 * product ID and up to 7 different devices...
346141cc406Sopenharmony_ci	 */
347141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Trying to get the pcbID of a Plustek device...\n" );
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci	/* get the PCB-ID */
350141cc406Sopenharmony_ci	result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
351141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != result ) {
352141cc406Sopenharmony_ci		sanei_usb_close( handle );
353141cc406Sopenharmony_ci		return -1;
354141cc406Sopenharmony_ci	}
355141cc406Sopenharmony_ci
356141cc406Sopenharmony_ci	reg59[0] = 0x22;	/* PIO1: Input, PIO2: Input         */
357141cc406Sopenharmony_ci	reg59[1] = 0x02;	/* PIO3: Input, PIO4: Output as low */
358141cc406Sopenharmony_ci	reg59[2] = 0x03;
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_ci	result = sanei_lm983x_write( handle, 0x59,  reg59, 3, SANE_TRUE );
361141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != result ) {
362141cc406Sopenharmony_ci		sanei_usb_close( handle );
363141cc406Sopenharmony_ci		return -1;
364141cc406Sopenharmony_ci	}
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci	result = sanei_lm983x_read ( handle, 0x02, &pcbID, 1, SANE_TRUE );
367141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != result ) {
368141cc406Sopenharmony_ci		sanei_usb_close( handle );
369141cc406Sopenharmony_ci		return -1;
370141cc406Sopenharmony_ci	}
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci	pcbID = (u_char)((pcbID >> 2) & 0x07);
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci	result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
375141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != result ) {
376141cc406Sopenharmony_ci		sanei_usb_close( handle );
377141cc406Sopenharmony_ci		return -1;
378141cc406Sopenharmony_ci	}
379141cc406Sopenharmony_ci
380141cc406Sopenharmony_ci	DBG( _DBG_INFO, "pcbID=0x%02x\n", pcbID );
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci	/* now roam through the setting list... */
383141cc406Sopenharmony_ci	strncpy( tmp, dev->usbId, 13 );
384141cc406Sopenharmony_ci	tmp[13] = '\0';
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci	sprintf( pcbStr, "-%u", pcbID );
387141cc406Sopenharmony_ci	strcat ( tmp, pcbStr );
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Checking for device >%s<\n", tmp );
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci		if( 0 == strcmp( Settings[i].pIDString, tmp )) {
394141cc406Sopenharmony_ci			DBG(_DBG_INFO, "Device description for >%s< found.\n", tmp );
395141cc406Sopenharmony_ci			usb_initDev( dev, i, handle, dev->usbDev.vendor );
396141cc406Sopenharmony_ci			return handle;
397141cc406Sopenharmony_ci		}
398141cc406Sopenharmony_ci	}
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci	return -1;
401141cc406Sopenharmony_ci}
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci/**
404141cc406Sopenharmony_ci * will be called upon sane_exit
405141cc406Sopenharmony_ci */
406141cc406Sopenharmony_cistatic void usbDev_shutdown( Plustek_Device *dev  )
407141cc406Sopenharmony_ci{
408141cc406Sopenharmony_ci	SANE_Int handle;
409141cc406Sopenharmony_ci
410141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n",
411141cc406Sopenharmony_ci	                dev->fd, dev->sane.name );
412141cc406Sopenharmony_ci	if( NULL == dev->usbDev.ModelStr ) {
413141cc406Sopenharmony_ci		DBG( _DBG_INFO, "Function ignored!\n" );
414141cc406Sopenharmony_ci		return;
415141cc406Sopenharmony_ci	}
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) {
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci		dev->fd = handle;
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci		DBG( _DBG_INFO, "Waiting for scanner-ready...\n" );
422141cc406Sopenharmony_ci		usb_IsScannerReady( dev );
423141cc406Sopenharmony_ci
424141cc406Sopenharmony_ci		if( 0 != dev->usbDev.bLampOffOnEnd ) {
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci			DBG( _DBG_INFO, "Switching lamp off...\n" );
427141cc406Sopenharmony_ci			usb_LampOn( dev, SANE_FALSE, SANE_FALSE );
428141cc406Sopenharmony_ci		}
429141cc406Sopenharmony_ci		dev->fd = -1;
430141cc406Sopenharmony_ci		sanei_usb_close( handle );
431141cc406Sopenharmony_ci	}
432141cc406Sopenharmony_ci	usb_StopLampTimer( dev );
433141cc406Sopenharmony_ci}
434141cc406Sopenharmony_ci
435141cc406Sopenharmony_ci/**
436141cc406Sopenharmony_ci * This function checks whether a device, described by a given
437141cc406Sopenharmony_ci * string(vendor and product ID), is support by this backend or not
438141cc406Sopenharmony_ci *
439141cc406Sopenharmony_ci * @param usbIdStr - string consisting out of product and vendor ID
440141cc406Sopenharmony_ci *                   format: "0xVVVVx0xPPPP" VVVV = Vendor ID, PPP = Product ID
441141cc406Sopenharmony_ci * @returns; SANE_TRUE if supported, SANE_FALSE if not
442141cc406Sopenharmony_ci */
443141cc406Sopenharmony_cistatic SANE_Bool usb_IsDeviceInList( char *usbIdStr )
444141cc406Sopenharmony_ci{
445141cc406Sopenharmony_ci	int i;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
448141cc406Sopenharmony_ci
449141cc406Sopenharmony_ci		if( 0 == strncmp( Settings[i].pIDString, usbIdStr, 13 ))
450141cc406Sopenharmony_ci			return SANE_TRUE;
451141cc406Sopenharmony_ci	}
452141cc406Sopenharmony_ci	return SANE_FALSE;
453141cc406Sopenharmony_ci}
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci/** get last valid entry of a list
456141cc406Sopenharmony_ci */
457141cc406Sopenharmony_cistatic DevList*
458141cc406Sopenharmony_cigetLast( DevList *l )
459141cc406Sopenharmony_ci{
460141cc406Sopenharmony_ci	if( l == NULL )
461141cc406Sopenharmony_ci		return NULL;
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci	while( l->next != NULL )
464141cc406Sopenharmony_ci		l = l->next;
465141cc406Sopenharmony_ci	return l;
466141cc406Sopenharmony_ci}
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci/** add a new entry to our internal device list, when a device is detected
469141cc406Sopenharmony_ci */
470141cc406Sopenharmony_cistatic SANE_Status usb_attach( SANE_String_Const dev_name )
471141cc406Sopenharmony_ci{
472141cc406Sopenharmony_ci	int      len;
473141cc406Sopenharmony_ci	DevList *tmp, *last;
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci	/* get some memory for the entry... */
476141cc406Sopenharmony_ci	len = sizeof(DevList) + strlen(dev_name) + 1;
477141cc406Sopenharmony_ci	tmp = (DevList*)malloc(len);
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_ci	/* initialize and set the values */
480141cc406Sopenharmony_ci	memset(tmp, 0, len );
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci	/* the device name is part of our structure space */
483141cc406Sopenharmony_ci	tmp->dev_name = &((char*)tmp)[sizeof(DevList)];
484141cc406Sopenharmony_ci	strcpy( tmp->dev_name, dev_name );
485141cc406Sopenharmony_ci	tmp->attached = SANE_FALSE;
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci	/* root set ? */
488141cc406Sopenharmony_ci	if( usbDevs == NULL ) {
489141cc406Sopenharmony_ci		usbDevs = tmp;
490141cc406Sopenharmony_ci	} else {
491141cc406Sopenharmony_ci		last = getLast(usbDevs); /* append... */
492141cc406Sopenharmony_ci		last->next = tmp;
493141cc406Sopenharmony_ci	}
494141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
495141cc406Sopenharmony_ci}
496141cc406Sopenharmony_ci
497141cc406Sopenharmony_ci/**
498141cc406Sopenharmony_ci */
499141cc406Sopenharmony_cistatic void
500141cc406Sopenharmony_ciusbGetList( DevList **devs )
501141cc406Sopenharmony_ci{
502141cc406Sopenharmony_ci	int        i;
503141cc406Sopenharmony_ci	SANE_Bool  il;
504141cc406Sopenharmony_ci	SANE_Word  v, p;
505141cc406Sopenharmony_ci	DevList   *tmp;
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Retrieving all supported and conntected devices\n" );
508141cc406Sopenharmony_ci	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
509141cc406Sopenharmony_ci
510141cc406Sopenharmony_ci		v = strtol( &(Settings[i].pIDString)[0], 0, 0 );
511141cc406Sopenharmony_ci		p = strtol( &(Settings[i].pIDString)[7], 0, 0 );
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci		/* check if this vendor- and product-ID has already been added, needed
514141cc406Sopenharmony_ci		 * for Plustek devices - here one product-ID is used for more than one
515141cc406Sopenharmony_ci		 * device type...
516141cc406Sopenharmony_ci		 */
517141cc406Sopenharmony_ci		il = SANE_FALSE;
518141cc406Sopenharmony_ci		for( tmp = *devs; tmp ; tmp = tmp->next ) {
519141cc406Sopenharmony_ci			if( tmp->device_id == p && tmp->vendor_id == v ) {
520141cc406Sopenharmony_ci				il = SANE_TRUE;
521141cc406Sopenharmony_ci				break;
522141cc406Sopenharmony_ci			}
523141cc406Sopenharmony_ci		}
524141cc406Sopenharmony_ci		if( il ) {
525141cc406Sopenharmony_ci			DBG( _DBG_INFO2, "Already in list: 0x%04x-0x%04x\n", v, p );
526141cc406Sopenharmony_ci			continue;
527141cc406Sopenharmony_ci		}
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci		/* get the last entry... */
530141cc406Sopenharmony_ci		tmp = getLast(*devs);
531141cc406Sopenharmony_ci		DBG( _DBG_INFO2, "Checking for 0x%04x-0x%04x\n", v, p );
532141cc406Sopenharmony_ci		sanei_usb_find_devices( v, p, usb_attach );
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci		if( getLast(*devs) != tmp ) {
535141cc406Sopenharmony_ci
536141cc406Sopenharmony_ci			if( tmp == NULL )
537141cc406Sopenharmony_ci				tmp = *devs;
538141cc406Sopenharmony_ci			else
539141cc406Sopenharmony_ci				tmp = tmp->next;
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci			while( tmp != NULL ) {
542141cc406Sopenharmony_ci				tmp->vendor_id = v;
543141cc406Sopenharmony_ci				tmp->device_id = p;
544141cc406Sopenharmony_ci				tmp = tmp->next;
545141cc406Sopenharmony_ci			}
546141cc406Sopenharmony_ci		}
547141cc406Sopenharmony_ci	}
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Available and supported devices:\n" );
550141cc406Sopenharmony_ci	if( *devs == NULL )
551141cc406Sopenharmony_ci		DBG( _DBG_INFO, "NONE.\n" );
552141cc406Sopenharmony_ci
553141cc406Sopenharmony_ci	for( tmp = *devs; tmp; tmp = tmp->next ) {
554141cc406Sopenharmony_ci		DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n",
555141cc406Sopenharmony_ci			tmp->dev_name, tmp->vendor_id, tmp->device_id );
556141cc406Sopenharmony_ci	}
557141cc406Sopenharmony_ci}
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci/**
560141cc406Sopenharmony_ci */
561141cc406Sopenharmony_cistatic int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock )
562141cc406Sopenharmony_ci{
563141cc406Sopenharmony_ci	char        dn[512];
564141cc406Sopenharmony_ci	char        devStr[50];
565141cc406Sopenharmony_ci	int         result;
566141cc406Sopenharmony_ci	int         i;
567141cc406Sopenharmony_ci	int         lc;
568141cc406Sopenharmony_ci	SANE_Int    handle;
569141cc406Sopenharmony_ci	SANE_Byte   version;
570141cc406Sopenharmony_ci	SANE_Word   vendor, product;
571141cc406Sopenharmony_ci	SANE_Bool   was_empty;
572141cc406Sopenharmony_ci	SANE_Status status;
573141cc406Sopenharmony_ci	DevList    *tmp;
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n",
576141cc406Sopenharmony_ci	    dev->name, dev->usbId, (void*)devs );
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci	/* preset our internal usb device structure */
579141cc406Sopenharmony_ci	memset( &dev->usbDev, 0, sizeof(DeviceDef));
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci	/* devs is NULL, when called from sane_start */
582141cc406Sopenharmony_ci	if( devs ) {
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_ci		dn[0] = '\0';
585141cc406Sopenharmony_ci		if( !strcmp( dev->name, "auto" )) {
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci			/* use the first "unattached"... */
588141cc406Sopenharmony_ci			for( tmp = devs; tmp; tmp = tmp->next ) {
589141cc406Sopenharmony_ci				if( !tmp->attached ) {
590141cc406Sopenharmony_ci					tmp->attached = SANE_TRUE;
591141cc406Sopenharmony_ci					strcpy( dn, tmp->dev_name );
592141cc406Sopenharmony_ci					break;
593141cc406Sopenharmony_ci				}
594141cc406Sopenharmony_ci			}
595141cc406Sopenharmony_ci		} else {
596141cc406Sopenharmony_ci
597141cc406Sopenharmony_ci			vendor  = strtol( &dev->usbId[0], 0, 0 );
598141cc406Sopenharmony_ci			product = strtol( &dev->usbId[7], 0, 0 );
599141cc406Sopenharmony_ci
600141cc406Sopenharmony_ci			/* check the first match... */
601141cc406Sopenharmony_ci			for( tmp = devs; tmp; tmp = tmp->next ) {
602141cc406Sopenharmony_ci				if( tmp->vendor_id == vendor && tmp->device_id == product ) {
603141cc406Sopenharmony_ci					if( !tmp->attached ) {
604141cc406Sopenharmony_ci						tmp->attached = SANE_TRUE;
605141cc406Sopenharmony_ci						strcpy( dn, tmp->dev_name );
606141cc406Sopenharmony_ci						break;
607141cc406Sopenharmony_ci					}
608141cc406Sopenharmony_ci				}
609141cc406Sopenharmony_ci			}
610141cc406Sopenharmony_ci		}
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci		if( !dn[0] ) {
613141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "No supported device found!\n" );
614141cc406Sopenharmony_ci			return -1;
615141cc406Sopenharmony_ci		}
616141cc406Sopenharmony_ci
617141cc406Sopenharmony_ci		status = sanei_access_lock( dn, 5 );
618141cc406Sopenharmony_ci		if( SANE_STATUS_GOOD != status ) {
619141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
620141cc406Sopenharmony_ci			return -1;
621141cc406Sopenharmony_ci		}
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci		status = sanei_usb_open( dn, &handle );
624141cc406Sopenharmony_ci		if( SANE_STATUS_GOOD != status ) {
625141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
626141cc406Sopenharmony_ci			     strerror(errno), errno);
627141cc406Sopenharmony_ci			sanei_access_unlock( dev->sane.name );
628141cc406Sopenharmony_ci			return -1;
629141cc406Sopenharmony_ci		}
630141cc406Sopenharmony_ci
631141cc406Sopenharmony_ci		/* replace the old devname, so we are able to have multiple
632141cc406Sopenharmony_ci		 * auto-detected devices
633141cc406Sopenharmony_ci		 */
634141cc406Sopenharmony_ci		free( dev->name );
635141cc406Sopenharmony_ci		dev->name      = strdup(dn);
636141cc406Sopenharmony_ci		dev->sane.name = dev->name;
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci	} else {
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci		status = sanei_access_lock( dev->sane.name, 5 );
641141cc406Sopenharmony_ci		if( SANE_STATUS_GOOD != status ) {
642141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
643141cc406Sopenharmony_ci			return -1;
644141cc406Sopenharmony_ci		}
645141cc406Sopenharmony_ci
646141cc406Sopenharmony_ci		status = sanei_usb_open( dev->name, &handle );
647141cc406Sopenharmony_ci		if( SANE_STATUS_GOOD != status ) {
648141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
649141cc406Sopenharmony_ci			     strerror(errno), errno);
650141cc406Sopenharmony_ci			sanei_access_unlock( dev->sane.name );
651141cc406Sopenharmony_ci			return -1;
652141cc406Sopenharmony_ci		}
653141cc406Sopenharmony_ci	}
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci	was_empty = SANE_FALSE;
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci	result = sanei_usb_get_vendor_product( handle, &vendor, &product );
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD == result ) {
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci		sprintf( devStr, "0x%04X-0x%04X", vendor, product );
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci		DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product);
664141cc406Sopenharmony_ci
665141cc406Sopenharmony_ci		if( dev->usbId[0] != '\0' ) {
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci			if( 0 != strcmp( dev->usbId, devStr )) {
668141cc406Sopenharmony_ci				DBG( _DBG_ERROR, "Specified Vendor and Product ID "
669141cc406Sopenharmony_ci								 "doesn't match with the ones\n"
670141cc406Sopenharmony_ci								 "in the config file\n" );
671141cc406Sopenharmony_ci				sanei_access_unlock( dev->sane.name );
672141cc406Sopenharmony_ci				sanei_usb_close( handle );
673141cc406Sopenharmony_ci				return -1;
674141cc406Sopenharmony_ci			}
675141cc406Sopenharmony_ci		} else {
676141cc406Sopenharmony_ci			sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product );
677141cc406Sopenharmony_ci			was_empty = SANE_TRUE;
678141cc406Sopenharmony_ci		}
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci	} else {
681141cc406Sopenharmony_ci
682141cc406Sopenharmony_ci		DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" );
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci		/* if the ioctl stuff is not supported by the kernel and we have
685141cc406Sopenharmony_ci		 * nothing specified, we have to give up...
686141cc406Sopenharmony_ci		 */
687141cc406Sopenharmony_ci		if( dev->usbId[0] == '\0' ) {
688141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, "
689141cc406Sopenharmony_ci							 "please specify in config file.\n" );
690141cc406Sopenharmony_ci			sanei_access_unlock( dev->sane.name );
691141cc406Sopenharmony_ci			sanei_usb_close( handle );
692141cc406Sopenharmony_ci	        return -1;
693141cc406Sopenharmony_ci		}
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci		vendor  = strtol( &dev->usbId[0], 0, 0 );
696141cc406Sopenharmony_ci		product = strtol( &dev->usbId[7], 0, 0 );
697141cc406Sopenharmony_ci		DBG( _DBG_INFO, "... using the specified: "
698141cc406Sopenharmony_ci		                "0x%04X-0x%04X\n", vendor, product );
699141cc406Sopenharmony_ci	}
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci	/* before accessing the scanner, check if supported!
702141cc406Sopenharmony_ci	 */
703141cc406Sopenharmony_ci	if( !usb_IsDeviceInList( dev->usbId )) {
704141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId );
705141cc406Sopenharmony_ci		sanei_access_unlock( dev->sane.name );
706141cc406Sopenharmony_ci		sanei_usb_close( handle );
707141cc406Sopenharmony_ci		return -1;
708141cc406Sopenharmony_ci	}
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci	status = usbio_DetectLM983x( handle, &version );
711141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != status ) {
712141cc406Sopenharmony_ci		sanei_usb_close( handle );
713141cc406Sopenharmony_ci		sanei_access_unlock( dev->sane.name );
714141cc406Sopenharmony_ci		return -1;
715141cc406Sopenharmony_ci	}
716141cc406Sopenharmony_ci
717141cc406Sopenharmony_ci	if ((version < 3) || (version > 4)) {
718141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "This is not a LM9831 or LM9832 chip based scanner.\n" );
719141cc406Sopenharmony_ci		sanei_usb_close( handle );
720141cc406Sopenharmony_ci		sanei_access_unlock( dev->sane.name );
721141cc406Sopenharmony_ci		return -1;
722141cc406Sopenharmony_ci	}
723141cc406Sopenharmony_ci
724141cc406Sopenharmony_ci	/* need to set the handle and the detected chiptype... */
725141cc406Sopenharmony_ci	dev->fd = handle;
726141cc406Sopenharmony_ci	dev->usbDev.HwSetting.chip = (version==3 ? _LM9831:_LM9832);
727141cc406Sopenharmony_ci	usbio_ResetLM983x( dev );
728141cc406Sopenharmony_ci	dev->fd = -1;
729141cc406Sopenharmony_ci
730141cc406Sopenharmony_ci	dev->usbDev.vendor  = vendor;
731141cc406Sopenharmony_ci	dev->usbDev.product = product;
732141cc406Sopenharmony_ci
733141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Detected vendor & product ID: "
734141cc406Sopenharmony_ci		                "0x%04X-0x%04X\n", vendor, product );
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci	/*
737141cc406Sopenharmony_ci	 * Plustek uses the misc IO 1/2 to get the PCB ID
738141cc406Sopenharmony_ci	 * (PCB = printed circuit board), so it's possible to have one
739141cc406Sopenharmony_ci	 * product ID and up to 7 different devices...
740141cc406Sopenharmony_ci	 */
741141cc406Sopenharmony_ci	if( 0x07B3 == vendor ) {
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci		handle = usb_CheckForPlustekDevice( handle, dev );
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci		if( was_empty )
746141cc406Sopenharmony_ci			dev->usbId[0] = '\0';
747141cc406Sopenharmony_ci
748141cc406Sopenharmony_ci		if( handle >= 0 ) {
749141cc406Sopenharmony_ci			if( !keep_lock )
750141cc406Sopenharmony_ci				sanei_access_unlock( dev->sane.name );
751141cc406Sopenharmony_ci			return handle;
752141cc406Sopenharmony_ci		}
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci	} else {
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci		/* now roam through the setting list... */
757141cc406Sopenharmony_ci		lc = 13;
758141cc406Sopenharmony_ci		strncpy( devStr, dev->usbId, lc );
759141cc406Sopenharmony_ci		devStr[lc] = '\0';
760141cc406Sopenharmony_ci
761141cc406Sopenharmony_ci		if( 0x400 == vendor ) {
762141cc406Sopenharmony_ci			if((dev->adj.mov < 0) || (dev->adj.mov > 1)) {
763141cc406Sopenharmony_ci				DBG(_DBG_INFO, "BearPaw MOV out of range: %d\n", dev->adj.mov);
764141cc406Sopenharmony_ci				dev->adj.mov = 0;
765141cc406Sopenharmony_ci			}
766141cc406Sopenharmony_ci			sprintf( devStr, "%s-%d", dev->usbId, dev->adj.mov );
767141cc406Sopenharmony_ci			lc = strlen(devStr);
768141cc406Sopenharmony_ci			DBG( _DBG_INFO, "BearPaw device: %s (%d)\n", devStr, lc );
769141cc406Sopenharmony_ci		}
770141cc406Sopenharmony_ci
771141cc406Sopenharmony_ci		if( was_empty )
772141cc406Sopenharmony_ci			dev->usbId[0] = '\0';
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci		/* if we don't use the PCD ID extension...
775141cc406Sopenharmony_ci		 */
776141cc406Sopenharmony_ci		for( i = 0; NULL != Settings[i].pIDString; i++ ) {
777141cc406Sopenharmony_ci
778141cc406Sopenharmony_ci			if( 0 == strncmp( Settings[i].pIDString, devStr, lc )) {
779141cc406Sopenharmony_ci				DBG( _DBG_INFO, "Device description for >%s< found.\n", devStr );
780141cc406Sopenharmony_ci				usb_initDev( dev, i, handle, vendor );
781141cc406Sopenharmony_ci				if( !keep_lock )
782141cc406Sopenharmony_ci					sanei_access_unlock( dev->sane.name );
783141cc406Sopenharmony_ci			    return handle;
784141cc406Sopenharmony_ci			}
785141cc406Sopenharmony_ci		}
786141cc406Sopenharmony_ci	}
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci	sanei_access_unlock( dev->sane.name );
789141cc406Sopenharmony_ci	sanei_usb_close( handle );
790141cc406Sopenharmony_ci	DBG( _DBG_ERROR, "No matching device found >%s<\n", devStr );
791141cc406Sopenharmony_ci	return -1;
792141cc406Sopenharmony_ci}
793141cc406Sopenharmony_ci
794141cc406Sopenharmony_ci/**
795141cc406Sopenharmony_ci */
796141cc406Sopenharmony_cistatic int usbDev_close( Plustek_Device *dev )
797141cc406Sopenharmony_ci{
798141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_close()\n" );
799141cc406Sopenharmony_ci	sanei_usb_close( dev->fd );
800141cc406Sopenharmony_ci	dev->fd = -1;
801141cc406Sopenharmony_ci	return 0;
802141cc406Sopenharmony_ci}
803141cc406Sopenharmony_ci
804141cc406Sopenharmony_ci/** convert the stuff
805141cc406Sopenharmony_ci */
806141cc406Sopenharmony_cistatic int usbDev_getCaps( Plustek_Device *dev )
807141cc406Sopenharmony_ci{
808141cc406Sopenharmony_ci	DCapsDef *scaps = &dev->usbDev.Caps;
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_getCaps()\n" );
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_ci	dev->caps.dwFlag = 0;
813141cc406Sopenharmony_ci
814141cc406Sopenharmony_ci	if(((DEVCAPSFLAG_Positive & scaps->wFlags)  &&
815141cc406Sopenharmony_ci	    (DEVCAPSFLAG_Negative & scaps->wFlags)) ||
816141cc406Sopenharmony_ci		(DEVCAPSFLAG_TPA      & scaps->wFlags)) {
817141cc406Sopenharmony_ci		dev->caps.dwFlag |= SFLAG_TPA;
818141cc406Sopenharmony_ci	}
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_ci	dev->caps.wMaxExtentX = scaps->Normal.Size.x;
821141cc406Sopenharmony_ci	dev->caps.wMaxExtentY = scaps->Normal.Size.y;
822141cc406Sopenharmony_ci	return 0;
823141cc406Sopenharmony_ci}
824141cc406Sopenharmony_ci
825141cc406Sopenharmony_ci/** usbDev_getCropInfo
826141cc406Sopenharmony_ci * function to set the image relevant stuff
827141cc406Sopenharmony_ci */
828141cc406Sopenharmony_cistatic int usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci )
829141cc406Sopenharmony_ci{
830141cc406Sopenharmony_ci	WinInfo size;
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_getCropInfo()\n" );
833141cc406Sopenharmony_ci
834141cc406Sopenharmony_ci	usb_GetImageInfo( dev, &ci->ImgDef, &size );
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci	ci->dwPixelsPerLine = size.dwPixels;
837141cc406Sopenharmony_ci	ci->dwLinesPerArea  = size.dwLines;
838141cc406Sopenharmony_ci	ci->dwBytesPerLine  = size.dwBytes;
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci	if( ci->ImgDef.dwFlag & SCANFLAG_DWORDBoundary )
841141cc406Sopenharmony_ci		ci->dwBytesPerLine = (ci->dwBytesPerLine + 3UL) & 0xfffffffcUL;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci	DBG( _DBG_INFO, "PPL = %lu\n",  ci->dwPixelsPerLine );
844141cc406Sopenharmony_ci	DBG( _DBG_INFO, "LPA = %lu\n",  ci->dwLinesPerArea );
845141cc406Sopenharmony_ci	DBG( _DBG_INFO, "BPL = %lu\n",  ci->dwBytesPerLine );
846141cc406Sopenharmony_ci
847141cc406Sopenharmony_ci	return 0;
848141cc406Sopenharmony_ci}
849141cc406Sopenharmony_ci
850141cc406Sopenharmony_ci/**
851141cc406Sopenharmony_ci */
852141cc406Sopenharmony_cistatic int usbDev_setMap( Plustek_Device *dev, SANE_Word *map,
853141cc406Sopenharmony_ci                          SANE_Word length, SANE_Word channel )
854141cc406Sopenharmony_ci{
855141cc406Sopenharmony_ci	SANE_Word i, idx;
856141cc406Sopenharmony_ci
857141cc406Sopenharmony_ci	DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n",channel,(unsigned long)map);
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci	_VAR_NOT_USED( dev );
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci	if( channel == _MAP_MASTER ) {
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci		for( i = 0; i < length; i++ ) {
864141cc406Sopenharmony_ci			a_bMap[i]            = (SANE_Byte)map[i];
865141cc406Sopenharmony_ci			a_bMap[length +i]    = (SANE_Byte)map[i];
866141cc406Sopenharmony_ci			a_bMap[(length*2)+i] = (SANE_Byte)map[i];
867141cc406Sopenharmony_ci		}
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_ci	} else {
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci		idx = 0;
872141cc406Sopenharmony_ci		if( channel == _MAP_GREEN )
873141cc406Sopenharmony_ci			idx = 1;
874141cc406Sopenharmony_ci		if( channel == _MAP_BLUE )
875141cc406Sopenharmony_ci			idx = 2;
876141cc406Sopenharmony_ci
877141cc406Sopenharmony_ci		for( i = 0; i < length; i++ ) {
878141cc406Sopenharmony_ci			a_bMap[(length * idx)+i] = (SANE_Byte)map[i];
879141cc406Sopenharmony_ci		}
880141cc406Sopenharmony_ci	}
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci	return 0;
883141cc406Sopenharmony_ci}
884141cc406Sopenharmony_ci
885141cc406Sopenharmony_ci/**
886141cc406Sopenharmony_ci */
887141cc406Sopenharmony_cistatic int
888141cc406Sopenharmony_ciusbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si )
889141cc406Sopenharmony_ci{
890141cc406Sopenharmony_ci	ScanDef  *scan  = &dev->scanning;
891141cc406Sopenharmony_ci	DCapsDef *caps = &dev->usbDev.Caps;
892141cc406Sopenharmony_ci
893141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_setScanEnv()\n" );
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci	/* clear all the stuff */
896141cc406Sopenharmony_ci	memset( scan, 0, sizeof(ScanDef));
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci	if((si->ImgDef.dwFlag & SCANDEF_Adf) &&
899141cc406Sopenharmony_ci	   (si->ImgDef.dwFlag & SCANDEF_ContinuousScan)) {
900141cc406Sopenharmony_ci		scan->sParam.dMCLK = dMCLK_ADF;
901141cc406Sopenharmony_ci	}
902141cc406Sopenharmony_ci
903141cc406Sopenharmony_ci    /* Save necessary information */
904141cc406Sopenharmony_ci	scan->fGrayFromColor = 0;
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci	/* for some devices and settings, we tweak the physical settings
907141cc406Sopenharmony_ci	 * how to get the image - but not in calibration mode
908141cc406Sopenharmony_ci	 */
909141cc406Sopenharmony_ci	if((si->ImgDef.dwFlag & SCANFLAG_Calibration) == 0) {
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci		if( si->ImgDef.wDataType == COLOR_256GRAY ) {
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci			if( !(si->ImgDef.dwFlag & SCANDEF_Adf) && !usb_IsCISDevice(dev) &&
914141cc406Sopenharmony_ci			   (caps->OpticDpi.x == 1200 && si->ImgDef.xyDpi.x <= 300)) {
915141cc406Sopenharmony_ci				scan->fGrayFromColor = 2;
916141cc406Sopenharmony_ci				si->ImgDef.wDataType = COLOR_TRUE24;
917141cc406Sopenharmony_ci				DBG( _DBG_INFO, "* Gray from color set!\n" );
918141cc406Sopenharmony_ci			}
919141cc406Sopenharmony_ci
920141cc406Sopenharmony_ci			if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
921141cc406Sopenharmony_ci				DBG( _DBG_INFO, "* Gray(8-bit) from color set!\n" );
922141cc406Sopenharmony_ci				scan->fGrayFromColor = 2;
923141cc406Sopenharmony_ci				si->ImgDef.wDataType = COLOR_TRUE24;
924141cc406Sopenharmony_ci			}
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci		} else if ( si->ImgDef.wDataType == COLOR_GRAY16 ) {
927141cc406Sopenharmony_ci			if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
928141cc406Sopenharmony_ci				DBG( _DBG_INFO, "* Gray(16-bit) from color set!\n" );
929141cc406Sopenharmony_ci				scan->fGrayFromColor = 2;
930141cc406Sopenharmony_ci				si->ImgDef.wDataType = COLOR_TRUE48;
931141cc406Sopenharmony_ci			}
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci		} else if ( si->ImgDef.wDataType == COLOR_BW ) {
934141cc406Sopenharmony_ci			if( caps->workaroundFlag & _WAF_BIN_FROM_COLOR ) {
935141cc406Sopenharmony_ci				DBG( _DBG_INFO, "* Binary from color set!\n" );
936141cc406Sopenharmony_ci				scan->fGrayFromColor = 10;
937141cc406Sopenharmony_ci				si->ImgDef.wDataType = COLOR_TRUE24;
938141cc406Sopenharmony_ci			}
939141cc406Sopenharmony_ci		}
940141cc406Sopenharmony_ci	}
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci	usb_SaveImageInfo( dev, &si->ImgDef );
943141cc406Sopenharmony_ci	usb_GetImageInfo ( dev, &si->ImgDef, &scan->sParam.Size );
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci	/* mask the flags */
946141cc406Sopenharmony_ci	scan->dwFlag = si->ImgDef.dwFlag &
947141cc406Sopenharmony_ci	              (SCANFLAG_bgr | SCANFLAG_BottomUp | SCANFLAG_Calibration |
948141cc406Sopenharmony_ci	               SCANFLAG_DWORDBoundary | SCANFLAG_RightAlign |
949141cc406Sopenharmony_ci	               SCANFLAG_StillModule | SCANDEF_Adf | SCANDEF_ContinuousScan);
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci	if( !(SCANDEF_QualityScan & si->ImgDef.dwFlag)) {
952141cc406Sopenharmony_ci		DBG( _DBG_INFO, "* Preview Mode set!\n" );
953141cc406Sopenharmony_ci	} else {
954141cc406Sopenharmony_ci		DBG( _DBG_INFO, "* Preview Mode NOT set!\n" );
955141cc406Sopenharmony_ci		scan->dwFlag |= SCANDEF_QualityScan;
956141cc406Sopenharmony_ci	}
957141cc406Sopenharmony_ci
958141cc406Sopenharmony_ci	scan->sParam.brightness  = si->siBrightness;
959141cc406Sopenharmony_ci	scan->sParam.contrast    = si->siContrast;
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci	if( scan->sParam.bBitDepth <= 8 )
962141cc406Sopenharmony_ci		scan->dwFlag &= ~SCANFLAG_RightAlign;
963141cc406Sopenharmony_ci
964141cc406Sopenharmony_ci	if( scan->dwFlag & SCANFLAG_DWORDBoundary ) {
965141cc406Sopenharmony_ci		if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
966141cc406Sopenharmony_ci			scan->dwBytesLine = (scan->sParam.Size.dwBytes / 3 + 3) & 0xfffffffcUL;
967141cc406Sopenharmony_ci		else
968141cc406Sopenharmony_ci			scan->dwBytesLine = (scan->sParam.Size.dwBytes + 3UL) & 0xfffffffcUL;
969141cc406Sopenharmony_ci
970141cc406Sopenharmony_ci	} else {
971141cc406Sopenharmony_ci
972141cc406Sopenharmony_ci		if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
973141cc406Sopenharmony_ci			scan->dwBytesLine = scan->sParam.Size.dwBytes / 3;
974141cc406Sopenharmony_ci		else
975141cc406Sopenharmony_ci			scan->dwBytesLine = scan->sParam.Size.dwBytes;
976141cc406Sopenharmony_ci	}
977141cc406Sopenharmony_ci
978141cc406Sopenharmony_ci	/* on CIS based devices we have to reconfigure the illumination
979141cc406Sopenharmony_ci	 * settings for the gray modes
980141cc406Sopenharmony_ci	 */
981141cc406Sopenharmony_ci	usb_AdjustCISLampSettings( dev, SANE_TRUE );
982141cc406Sopenharmony_ci
983141cc406Sopenharmony_ci	if( scan->dwFlag & SCANFLAG_BottomUp)
984141cc406Sopenharmony_ci		scan->lBufAdjust = -(long)scan->dwBytesLine;
985141cc406Sopenharmony_ci	else
986141cc406Sopenharmony_ci		scan->lBufAdjust = scan->dwBytesLine;
987141cc406Sopenharmony_ci
988141cc406Sopenharmony_ci	/* LM9831 has a BUG in 16-bit mode,
989141cc406Sopenharmony_ci	 * so we generate pseudo 16-bit data from 8-bit
990141cc406Sopenharmony_ci	 */
991141cc406Sopenharmony_ci	if( scan->sParam.bBitDepth > 8 ) {
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci		if( _LM9831 == dev->usbDev.HwSetting.chip ) {
994141cc406Sopenharmony_ci
995141cc406Sopenharmony_ci			scan->sParam.bBitDepth = 8;
996141cc406Sopenharmony_ci			scan->dwFlag |= SCANFLAG_Pseudo48;
997141cc406Sopenharmony_ci			scan->sParam.Size.dwBytes >>= 1;
998141cc406Sopenharmony_ci		}
999141cc406Sopenharmony_ci	}
1000141cc406Sopenharmony_ci
1001141cc406Sopenharmony_ci	/* Source selection */
1002141cc406Sopenharmony_ci	if( scan->sParam.bSource == SOURCE_Reflection ) {
1003141cc406Sopenharmony_ci
1004141cc406Sopenharmony_ci		dev->usbDev.pSource = &caps->Normal;
1005141cc406Sopenharmony_ci		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1006141cc406Sopenharmony_ci		                                      (u_long)dev->usbDev.Normal.lLeft;
1007141cc406Sopenharmony_ci		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1008141cc406Sopenharmony_ci		                                        (u_long)dev->usbDev.Normal.lUp;
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci	} else if( scan->sParam.bSource == SOURCE_Transparency ) {
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci		dev->usbDev.pSource = &caps->Positive;
1013141cc406Sopenharmony_ci		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1014141cc406Sopenharmony_ci		                                    (u_long)dev->usbDev.Positive.lLeft;
1015141cc406Sopenharmony_ci		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1016141cc406Sopenharmony_ci		                                      (u_long)dev->usbDev.Positive.lUp;
1017141cc406Sopenharmony_ci
1018141cc406Sopenharmony_ci	} else if( scan->sParam.bSource == SOURCE_Negative ) {
1019141cc406Sopenharmony_ci
1020141cc406Sopenharmony_ci		dev->usbDev.pSource = &caps->Negative;
1021141cc406Sopenharmony_ci		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1022141cc406Sopenharmony_ci		                                    (u_long)dev->usbDev.Negative.lLeft;
1023141cc406Sopenharmony_ci		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1024141cc406Sopenharmony_ci		                                      (u_long)dev->usbDev.Negative.lUp;
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci	} else {
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci		dev->usbDev.pSource = &dev->usbDev.Caps.Adf;
1029141cc406Sopenharmony_ci		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1030141cc406Sopenharmony_ci		                                      (u_long)dev->usbDev.Normal.lLeft;
1031141cc406Sopenharmony_ci		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1032141cc406Sopenharmony_ci		                                        (u_long)dev->usbDev.Normal.lUp;
1033141cc406Sopenharmony_ci	}
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci	if( scan->sParam.bSource == SOURCE_ADF ) {
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci		if( scan->dwFlag & SCANDEF_ContinuousScan )
1038141cc406Sopenharmony_ci			dev->usbDev.fLastScanIsAdf = SANE_TRUE;
1039141cc406Sopenharmony_ci		else
1040141cc406Sopenharmony_ci			dev->usbDev.fLastScanIsAdf = SANE_FALSE;
1041141cc406Sopenharmony_ci	}
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci	return 0;
1044141cc406Sopenharmony_ci}
1045141cc406Sopenharmony_ci
1046141cc406Sopenharmony_ci/**
1047141cc406Sopenharmony_ci */
1048141cc406Sopenharmony_cistatic int
1049141cc406Sopenharmony_ciusbDev_stopScan( Plustek_Device *dev )
1050141cc406Sopenharmony_ci{
1051141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_stopScan()\n" );
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci	/* in cancel-mode we first stop the motor */
1054141cc406Sopenharmony_ci	usb_ScanEnd( dev );
1055141cc406Sopenharmony_ci
1056141cc406Sopenharmony_ci	dev->scanning.dwFlag = 0;
1057141cc406Sopenharmony_ci
1058141cc406Sopenharmony_ci	if( NULL != dev->scanning.pScanBuffer ) {
1059141cc406Sopenharmony_ci
1060141cc406Sopenharmony_ci		free( dev->scanning.pScanBuffer );
1061141cc406Sopenharmony_ci		dev->scanning.pScanBuffer = NULL;
1062141cc406Sopenharmony_ci		usb_StartLampTimer( dev );
1063141cc406Sopenharmony_ci	}
1064141cc406Sopenharmony_ci	return 0;
1065141cc406Sopenharmony_ci}
1066141cc406Sopenharmony_ci
1067141cc406Sopenharmony_ci/**
1068141cc406Sopenharmony_ci */
1069141cc406Sopenharmony_cistatic int
1070141cc406Sopenharmony_ciusbDev_startScan( Plustek_Device *dev )
1071141cc406Sopenharmony_ci{
1072141cc406Sopenharmony_ci	ScanDef *scan = &dev->scanning;
1073141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_startScan()\n" );
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci/* HEINER: Preview currently not working correctly */
1076141cc406Sopenharmony_ci#if 0
1077141cc406Sopenharmony_ci	if( scan->dwFlag & SCANDEF_QualityScan )
1078141cc406Sopenharmony_ci		dev->usbDev.a_bRegs[0x0a] = 0;
1079141cc406Sopenharmony_ci	else
1080141cc406Sopenharmony_ci		dev->usbDev.a_bRegs[0x0a] = 1;
1081141cc406Sopenharmony_ci#endif
1082141cc406Sopenharmony_ci	dev->usbDev.a_bRegs[0x0a] = 0;
1083141cc406Sopenharmony_ci
1084141cc406Sopenharmony_ci	if((scan->dwFlag & SCANDEF_Adf) && (scan->dwFlag & SCANDEF_ContinuousScan)) {
1085141cc406Sopenharmony_ci		scan->fCalibrated = SANE_TRUE;
1086141cc406Sopenharmony_ci	} else {
1087141cc406Sopenharmony_ci		scan->fCalibrated = SANE_FALSE;
1088141cc406Sopenharmony_ci	}
1089141cc406Sopenharmony_ci
1090141cc406Sopenharmony_ci	scan->sParam.PhyDpi.x = usb_SetAsicDpiX(dev,scan->sParam.UserDpi.x);
1091141cc406Sopenharmony_ci	scan->sParam.PhyDpi.y = usb_SetAsicDpiY(dev,scan->sParam.UserDpi.y);
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci	/* Allocate shading/scan buffer */
1094141cc406Sopenharmony_ci	scan->pScanBuffer = (u_long*)malloc( _SCANBUF_SIZE );
1095141cc406Sopenharmony_ci
1096141cc406Sopenharmony_ci	if( scan->pScanBuffer == NULL )
1097141cc406Sopenharmony_ci		return _E_ALLOC;
1098141cc406Sopenharmony_ci
1099141cc406Sopenharmony_ci	scan->dwFlag |= SCANFLAG_StartScan;
1100141cc406Sopenharmony_ci
1101141cc406Sopenharmony_ci	/* some devices (esp. BearPaw) do need a lamp switch off before
1102141cc406Sopenharmony_ci	 * switching it on again. Otherwise it might happen that the lamp
1103141cc406Sopenharmony_ci	 * remains off
1104141cc406Sopenharmony_ci	 */
1105141cc406Sopenharmony_ci	if(dev->usbDev.Caps.workaroundFlag & _WAF_LOFF_ON_START) {
1106141cc406Sopenharmony_ci		if (usb_GetLampStatus(dev))
1107141cc406Sopenharmony_ci			usb_LampOn( dev, SANE_FALSE, SANE_TRUE );
1108141cc406Sopenharmony_ci	}
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci	usb_LampOn( dev, SANE_TRUE, SANE_TRUE );
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci	m_fStart    = m_fFirst = SANE_TRUE;
1113141cc406Sopenharmony_ci	m_fAutoPark = (scan->dwFlag&SCANFLAG_StillModule)?SANE_FALSE:SANE_TRUE;
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci	if( usb_IsSheetFedDevice(dev))
1116141cc406Sopenharmony_ci		if(usb_InCalibrationMode(dev))
1117141cc406Sopenharmony_ci			m_fAutoPark = SANE_FALSE;
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci	usb_StopLampTimer( dev );
1120141cc406Sopenharmony_ci	return 0;
1121141cc406Sopenharmony_ci}
1122141cc406Sopenharmony_ci
1123141cc406Sopenharmony_ci/**
1124141cc406Sopenharmony_ci * do the reading stuff here...
1125141cc406Sopenharmony_ci * first we perform the calibration step, and then we read the image
1126141cc406Sopenharmony_ci * line for line
1127141cc406Sopenharmony_ci */
1128141cc406Sopenharmony_cistatic int
1129141cc406Sopenharmony_ciusbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf )
1130141cc406Sopenharmony_ci{
1131141cc406Sopenharmony_ci	int       result;
1132141cc406Sopenharmony_ci	SANE_Bool use_alt_cal = SANE_FALSE;
1133141cc406Sopenharmony_ci	ScanDef  *scan        = &dev->scanning;
1134141cc406Sopenharmony_ci	DCapsDef *scaps       = &dev->usbDev.Caps;
1135141cc406Sopenharmony_ci	HWDef    *hw          = &dev->usbDev.HwSetting;
1136141cc406Sopenharmony_ci
1137141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbDev_PrepareScan()\n" );
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci	/* check the current position of the sensor and move it back
1140141cc406Sopenharmony_ci	 * to it's home position if necessary...
1141141cc406Sopenharmony_ci	 */
1142141cc406Sopenharmony_ci	if( !usb_IsSheetFedDevice(dev))
1143141cc406Sopenharmony_ci		usb_SensorStatus( dev );
1144141cc406Sopenharmony_ci
1145141cc406Sopenharmony_ci	/* CIS devices need special handling... */
1146141cc406Sopenharmony_ci	if( usb_IsCISDevice(dev)) {
1147141cc406Sopenharmony_ci		use_alt_cal = SANE_TRUE;
1148141cc406Sopenharmony_ci
1149141cc406Sopenharmony_ci	} else {
1150141cc406Sopenharmony_ci
1151141cc406Sopenharmony_ci		if( dev->adj.altCalibrate )
1152141cc406Sopenharmony_ci			use_alt_cal = SANE_TRUE;
1153141cc406Sopenharmony_ci	}
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci	/* for the skip functionality use the "old" calibration functions */
1156141cc406Sopenharmony_ci	if( dev->usbDev.Caps.workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1157141cc406Sopenharmony_ci		use_alt_cal = SANE_FALSE;
1158141cc406Sopenharmony_ci	}
1159141cc406Sopenharmony_ci
1160141cc406Sopenharmony_ci	if( use_alt_cal ) {
1161141cc406Sopenharmony_ci		result = cano_DoCalibration( dev );
1162141cc406Sopenharmony_ci	} else {
1163141cc406Sopenharmony_ci		result = usb_DoCalibration( dev );
1164141cc406Sopenharmony_ci	}
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci	if( SANE_TRUE != result ) {
1167141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "calibration failed!!!\n" );
1168141cc406Sopenharmony_ci		return _E_ABORT;
1169141cc406Sopenharmony_ci	}
1170141cc406Sopenharmony_ci
1171141cc406Sopenharmony_ci	if( dev->adj.cacheCalData )
1172141cc406Sopenharmony_ci		usb_SaveCalData( dev );
1173141cc406Sopenharmony_ci
1174141cc406Sopenharmony_ci	DBG( _DBG_INFO, "calibration done.\n" );
1175141cc406Sopenharmony_ci	if( usb_InCalibrationMode(dev))
1176141cc406Sopenharmony_ci		return 0;
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci	if( !(scan->dwFlag & SCANFLAG_Scanning)) {
1179141cc406Sopenharmony_ci
1180141cc406Sopenharmony_ci		usleep( 10 * 1000 );
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci		/* need to preset that here, as we need it during parameter setting
1183141cc406Sopenharmony_ci		 */
1184141cc406Sopenharmony_ci		scan->bLinesToSkip = (u_char)(scan->sParam.PhyDpi.y / 50);
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci		scan->dwLinesDiscard = 0;
1187141cc406Sopenharmony_ci		if( scan->sParam.bChannels == 3 ) {
1188141cc406Sopenharmony_ci			scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1189141cc406Sopenharmony_ci			                       scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1190141cc406Sopenharmony_ci			scan->dwLinesDiscard <<= 1;
1191141cc406Sopenharmony_ci		}
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci		if( !usb_SetScanParameters( dev, &scan->sParam )) {
1194141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "Setting Scan Parameters failed!\n" );
1195141cc406Sopenharmony_ci			return 0;
1196141cc406Sopenharmony_ci		}
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci		/* if we bypass the calibration step, we wait on lamp warmup here...
1199141cc406Sopenharmony_ci		 */
1200141cc406Sopenharmony_ci		if( scaps->workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1201141cc406Sopenharmony_ci			if( !usb_Wait4Warmup( dev )) {
1202141cc406Sopenharmony_ci				DBG( _DBG_INFO, "usbDev_Prepare() - Cancel detected...\n" );
1203141cc406Sopenharmony_ci				return 0;
1204141cc406Sopenharmony_ci			}
1205141cc406Sopenharmony_ci		}
1206141cc406Sopenharmony_ci
1207141cc406Sopenharmony_ci		scan->pbScanBufBegin = (u_char*)scan->pScanBuffer;
1208141cc406Sopenharmony_ci
1209141cc406Sopenharmony_ci		if((dev->caps.dwFlag & SFLAG_ADF) && (scaps->OpticDpi.x == 600))
1210141cc406Sopenharmony_ci			scan->dwLinesScanBuf = 8;
1211141cc406Sopenharmony_ci		else
1212141cc406Sopenharmony_ci			scan->dwLinesScanBuf = 32;
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci		scan->dwBytesScanBuf     = scan->dwLinesScanBuf *
1215141cc406Sopenharmony_ci		                           scan->sParam.Size.dwPhyBytes;
1216141cc406Sopenharmony_ci
1217141cc406Sopenharmony_ci		scan->dwNumberOfScanBufs = _SCANBUF_SIZE / scan->dwBytesScanBuf;
1218141cc406Sopenharmony_ci		scan->dwLinesPerScanBufs = scan->dwNumberOfScanBufs *
1219141cc406Sopenharmony_ci		                           scan->dwLinesScanBuf;
1220141cc406Sopenharmony_ci		scan->pbScanBufEnd       = scan->pbScanBufBegin +
1221141cc406Sopenharmony_ci		                           scan->dwLinesPerScanBufs *
1222141cc406Sopenharmony_ci		                           scan->sParam.Size.dwPhyBytes;
1223141cc406Sopenharmony_ci		scan->dwRedShift   = 0;
1224141cc406Sopenharmony_ci		scan->dwBlueShift  = 0;
1225141cc406Sopenharmony_ci		scan->dwGreenShift = 0;
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci		/* CCD scanner */
1228141cc406Sopenharmony_ci		if( scan->sParam.bChannels == 3 ) {
1229141cc406Sopenharmony_ci
1230141cc406Sopenharmony_ci			scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1231141cc406Sopenharmony_ci			                       scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1232141cc406Sopenharmony_ci
1233141cc406Sopenharmony_ci			switch( scaps->bSensorOrder ) {
1234141cc406Sopenharmony_ci
1235141cc406Sopenharmony_ci			case SENSORORDER_rgb:
1236141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin;
1237141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1238141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1239141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1240141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes * 2UL;
1241141cc406Sopenharmony_ci				break;
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci			case SENSORORDER_rbg:
1244141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin;
1245141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1246141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1247141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1248141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes * 2UL;
1249141cc406Sopenharmony_ci				break;
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci			case SENSORORDER_gbr:
1252141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin;
1253141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1254141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1255141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1256141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes * 2UL;
1257141cc406Sopenharmony_ci				break;
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_ci			case SENSORORDER_grb:
1260141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin;
1261141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1262141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1263141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1264141cc406Sopenharmony_ci                                 scan->sParam.Size.dwPhyBytes * 2UL;
1265141cc406Sopenharmony_ci				break;
1266141cc406Sopenharmony_ci
1267141cc406Sopenharmony_ci			case SENSORORDER_brg:
1268141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin;
1269141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1270141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1271141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1272141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes * 2UL;
1273141cc406Sopenharmony_ci				break;
1274141cc406Sopenharmony_ci
1275141cc406Sopenharmony_ci			case SENSORORDER_bgr:
1276141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin;
1277141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1278141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes;
1279141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1280141cc406Sopenharmony_ci				                 scan->sParam.Size.dwPhyBytes * 2UL;
1281141cc406Sopenharmony_ci			}
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci			/* double it for last channel */
1284141cc406Sopenharmony_ci			scan->dwLinesDiscard <<= 1;
1285141cc406Sopenharmony_ci			scan->dwGreenShift = (7UL+scan->sParam.bBitDepth) >> 3;
1286141cc406Sopenharmony_ci			scan->Green.pb += scan->dwGreenShift;
1287141cc406Sopenharmony_ci			scan->Blue.pb  += (scan->dwGreenShift * 2);
1288141cc406Sopenharmony_ci
1289141cc406Sopenharmony_ci			if( scan->dwFlag & SCANFLAG_bgr) {
1290141cc406Sopenharmony_ci
1291141cc406Sopenharmony_ci				u_char *pb = scan->Blue.pb;
1292141cc406Sopenharmony_ci
1293141cc406Sopenharmony_ci				scan->Blue.pb = scan->Red.pb;
1294141cc406Sopenharmony_ci				scan->Red.pb  = pb;
1295141cc406Sopenharmony_ci				scan->dwBlueShift = 0;
1296141cc406Sopenharmony_ci				scan->dwRedShift  = scan->dwGreenShift << 1;
1297141cc406Sopenharmony_ci			} else {
1298141cc406Sopenharmony_ci				scan->dwRedShift  = 0;
1299141cc406Sopenharmony_ci				scan->dwBlueShift = scan->dwGreenShift << 1;
1300141cc406Sopenharmony_ci			}
1301141cc406Sopenharmony_ci
1302141cc406Sopenharmony_ci		} else {
1303141cc406Sopenharmony_ci
1304141cc406Sopenharmony_ci			/* CIS section */
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci			/* this might be a simple gray operation or AFE 1 channel op */
1307141cc406Sopenharmony_ci			scan->dwLinesDiscard = 0;
1308141cc406Sopenharmony_ci			scan->Green.pb       = scan->pbScanBufBegin;
1309141cc406Sopenharmony_ci
1310141cc406Sopenharmony_ci			if(( scan->sParam.bDataType == SCANDATATYPE_Color ) &&
1311141cc406Sopenharmony_ci			   ( hw->bReg_0x26 & _ONE_CH_COLOR )) {
1312141cc406Sopenharmony_ci
1313141cc406Sopenharmony_ci				u_char so;
1314141cc406Sopenharmony_ci				u_long len = scan->sParam.Size.dwPhyBytes / 3;
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci				so = scaps->bSensorOrder;
1317141cc406Sopenharmony_ci				if (_WAF_RESET_SO_TO_RGB & scaps->workaroundFlag) {
1318141cc406Sopenharmony_ci					if (scaps->bPCB != 0) {
1319141cc406Sopenharmony_ci						if (scan->sParam.PhyDpi.x > scaps->bPCB) {
1320141cc406Sopenharmony_ci							so = SENSORORDER_rgb;
1321141cc406Sopenharmony_ci							DBG(_DBG_INFO, "* Resetting sensororder to RGB\n");
1322141cc406Sopenharmony_ci						}
1323141cc406Sopenharmony_ci					}
1324141cc406Sopenharmony_ci				}
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci				switch( so ) {
1327141cc406Sopenharmony_ci
1328141cc406Sopenharmony_ci				case SENSORORDER_rgb:
1329141cc406Sopenharmony_ci					scan->Red.pb   = scan->pbScanBufBegin;
1330141cc406Sopenharmony_ci					scan->Green.pb = scan->pbScanBufBegin + len;
1331141cc406Sopenharmony_ci					scan->Blue.pb  = scan->pbScanBufBegin + len * 2UL;
1332141cc406Sopenharmony_ci					break;
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci				case SENSORORDER_gbr:
1335141cc406Sopenharmony_ci					scan->Green.pb = scan->pbScanBufBegin;
1336141cc406Sopenharmony_ci					scan->Blue.pb  = scan->pbScanBufBegin + len;
1337141cc406Sopenharmony_ci					scan->Red.pb   = scan->pbScanBufBegin + len * 2UL;
1338141cc406Sopenharmony_ci					break;
1339141cc406Sopenharmony_ci				default:
1340141cc406Sopenharmony_ci					DBG( _DBG_ERROR, "CIS: This bSensorOrder "
1341141cc406Sopenharmony_ci					                 "is not defined\n" );
1342141cc406Sopenharmony_ci					return _E_INTERNAL;
1343141cc406Sopenharmony_ci				}
1344141cc406Sopenharmony_ci			}
1345141cc406Sopenharmony_ci		}
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci		/* set a function to process the RAW data... */
1348141cc406Sopenharmony_ci		usb_GetImageProc( dev );
1349141cc406Sopenharmony_ci
1350141cc406Sopenharmony_ci		if( scan->sParam.bSource == SOURCE_ADF )
1351141cc406Sopenharmony_ci			scan->dwFlag |= SCANFLAG_StillModule;
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci		DBG( _DBG_INFO, "* scan->dwFlag=0x%08lx\n", scan->dwFlag );
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci		if( !usb_ScanBegin( dev,
1356141cc406Sopenharmony_ci			(scan->dwFlag&SCANFLAG_StillModule) ? SANE_FALSE:SANE_TRUE)) {
1357141cc406Sopenharmony_ci
1358141cc406Sopenharmony_ci			return _E_INTERNAL;
1359141cc406Sopenharmony_ci		}
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci		scan->dwFlag |= SCANFLAG_Scanning;
1362141cc406Sopenharmony_ci
1363141cc406Sopenharmony_ci		if( scan->sParam.UserDpi.y != scan->sParam.PhyDpi.y ) {
1364141cc406Sopenharmony_ci
1365141cc406Sopenharmony_ci			if( scan->sParam.UserDpi.y < scan->sParam.PhyDpi.y ) {
1366141cc406Sopenharmony_ci
1367141cc406Sopenharmony_ci				scan->wSumY = scan->sParam.PhyDpi.y - scan->sParam.UserDpi.y;
1368141cc406Sopenharmony_ci				scan->dwFlag |= SCANFLAG_SampleY;
1369141cc406Sopenharmony_ci				DBG( _DBG_INFO, "SampleY Flag set (%u != %u, wSumY=%u)\n",
1370141cc406Sopenharmony_ci				  scan->sParam.UserDpi.y, scan->sParam.PhyDpi.y, scan->wSumY );
1371141cc406Sopenharmony_ci			}
1372141cc406Sopenharmony_ci		}
1373141cc406Sopenharmony_ci	}
1374141cc406Sopenharmony_ci
1375141cc406Sopenharmony_ci	dumpPicInit( &scan->sParam, "plustek-pic.raw" );
1376141cc406Sopenharmony_ci
1377141cc406Sopenharmony_ci	/* here the NT driver uses an extra reading thread...
1378141cc406Sopenharmony_ci	 * as the SANE stuff already forked the driver to read data, I think
1379141cc406Sopenharmony_ci	 * we should only read data by using a function...
1380141cc406Sopenharmony_ci	 */
1381141cc406Sopenharmony_ci	scan->dwLinesUser = scan->sParam.Size.dwLines;
1382141cc406Sopenharmony_ci	if( !scan->dwLinesUser )
1383141cc406Sopenharmony_ci		return _E_BUFFER_TOO_SMALL;
1384141cc406Sopenharmony_ci
1385141cc406Sopenharmony_ci	if( scan->sParam.Size.dwLines < scan->dwLinesUser )
1386141cc406Sopenharmony_ci		scan->dwLinesUser = scan->sParam.Size.dwLines;
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci	scan->sParam.Size.dwLines -= scan->dwLinesUser;
1389141cc406Sopenharmony_ci	if( scan->dwFlag & SCANFLAG_BottomUp )
1390141cc406Sopenharmony_ci		scan->UserBuf.pb = buf + (scan->dwLinesUser - 1) * scan->dwBytesLine;
1391141cc406Sopenharmony_ci	else
1392141cc406Sopenharmony_ci		scan->UserBuf.pb = buf;
1393141cc406Sopenharmony_ci
1394141cc406Sopenharmony_ci	DBG(_DBG_INFO,"Reading the data now!\n" );
1395141cc406Sopenharmony_ci	DBG(_DBG_INFO,"PhyDpi.x         = %u\n", scan->sParam.PhyDpi.x  );
1396141cc406Sopenharmony_ci	DBG(_DBG_INFO,"PhyDpi.y         = %u\n", scan->sParam.PhyDpi.y  );
1397141cc406Sopenharmony_ci	DBG(_DBG_INFO,"UserDpi.x        = %u\n", scan->sParam.UserDpi.x );
1398141cc406Sopenharmony_ci	DBG(_DBG_INFO,"UserDpi.y        = %u\n", scan->sParam.UserDpi.y );
1399141cc406Sopenharmony_ci	DBG(_DBG_INFO,"NumberOfScanBufs = %lu\n",scan->dwNumberOfScanBufs);
1400141cc406Sopenharmony_ci	DBG(_DBG_INFO,"LinesPerScanBufs = %lu\n",scan->dwLinesPerScanBufs);
1401141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwPhyBytes       = %lu\n",scan->sParam.Size.dwPhyBytes);
1402141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwPhyPixels      = %lu\n",scan->sParam.Size.dwPhyPixels);
1403141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwTotalBytes     = %lu\n",scan->sParam.Size.dwTotalBytes);
1404141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwPixels         = %lu\n",scan->sParam.Size.dwPixels);
1405141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwBytes          = %lu\n",scan->sParam.Size.dwBytes);
1406141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwValidPixels    = %lu\n",scan->sParam.Size.dwValidPixels);
1407141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwBytesScanBuf   = %lu\n",scan->dwBytesScanBuf );
1408141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwLinesDiscard   = %lu\n",scan->dwLinesDiscard );
1409141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwLinesToSkip    = %u\n", scan->bLinesToSkip );
1410141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwLinesUser      = %lu\n",scan->dwLinesUser  );
1411141cc406Sopenharmony_ci	DBG(_DBG_INFO,"dwBytesLine      = %lu\n",scan->dwBytesLine  );
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci	scan->pbGetDataBuf = scan->pbScanBufBegin;
1414141cc406Sopenharmony_ci
1415141cc406Sopenharmony_ci	scan->dwLinesToProcess = usb_ReadData( dev  );
1416141cc406Sopenharmony_ci	if( 0 == scan->dwLinesToProcess )
1417141cc406Sopenharmony_ci		return _E_DATAREAD;
1418141cc406Sopenharmony_ci
1419141cc406Sopenharmony_ci	return 0;
1420141cc406Sopenharmony_ci}
1421141cc406Sopenharmony_ci
1422141cc406Sopenharmony_ci/** as the name says, read one line...
1423141cc406Sopenharmony_ci */
1424141cc406Sopenharmony_cistatic int
1425141cc406Sopenharmony_ciusbDev_ReadLine( Plustek_Device *dev )
1426141cc406Sopenharmony_ci{
1427141cc406Sopenharmony_ci	int      wrap;
1428141cc406Sopenharmony_ci	u_long   cur;
1429141cc406Sopenharmony_ci	ScanDef *scan = &dev->scanning;
1430141cc406Sopenharmony_ci	HWDef   *hw   = &dev->usbDev.HwSetting;
1431141cc406Sopenharmony_ci
1432141cc406Sopenharmony_ci	cur = scan->dwLinesUser;
1433141cc406Sopenharmony_ci
1434141cc406Sopenharmony_ci	/* we stay within this sample loop until one line has been processed for
1435141cc406Sopenharmony_ci	 * the user...
1436141cc406Sopenharmony_ci	 */
1437141cc406Sopenharmony_ci	while( cur == scan->dwLinesUser ) {
1438141cc406Sopenharmony_ci
1439141cc406Sopenharmony_ci		if( usb_IsEscPressed()) {
1440141cc406Sopenharmony_ci			DBG( _DBG_INFO, "readLine() - Cancel detected...\n" );
1441141cc406Sopenharmony_ci			return _E_ABORT;
1442141cc406Sopenharmony_ci		}
1443141cc406Sopenharmony_ci
1444141cc406Sopenharmony_ci		if( !(scan->dwFlag & SCANFLAG_SampleY))	{
1445141cc406Sopenharmony_ci
1446141cc406Sopenharmony_ci			scan->pfnProcess( dev );
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci			/* Adjust user buffer pointer */
1449141cc406Sopenharmony_ci			scan->UserBuf.pb += scan->lBufAdjust;
1450141cc406Sopenharmony_ci			scan->dwLinesUser--;
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_ci		} else {
1453141cc406Sopenharmony_ci
1454141cc406Sopenharmony_ci			scan->wSumY += scan->sParam.UserDpi.y;
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci			if( scan->wSumY >= scan->sParam.PhyDpi.y ) {
1457141cc406Sopenharmony_ci				scan->wSumY -= scan->sParam.PhyDpi.y;
1458141cc406Sopenharmony_ci
1459141cc406Sopenharmony_ci				scan->pfnProcess( dev );
1460141cc406Sopenharmony_ci
1461141cc406Sopenharmony_ci				/* Adjust user buffer pointer */
1462141cc406Sopenharmony_ci				scan->UserBuf.pb += scan->lBufAdjust;
1463141cc406Sopenharmony_ci				scan->dwLinesUser--;
1464141cc406Sopenharmony_ci			}
1465141cc406Sopenharmony_ci		}
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci		/* Adjust get buffer pointers */
1468141cc406Sopenharmony_ci		wrap = 0;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci		if( scan->sParam.bDataType == SCANDATATYPE_Color ) {
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci			scan->Red.pb += scan->sParam.Size.dwPhyBytes;
1473141cc406Sopenharmony_ci			if( scan->Red.pb >= scan->pbScanBufEnd ) {
1474141cc406Sopenharmony_ci				scan->Red.pb = scan->pbScanBufBegin + scan->dwRedShift;
1475141cc406Sopenharmony_ci				wrap = 1;
1476141cc406Sopenharmony_ci			}
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci			scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1479141cc406Sopenharmony_ci			if( scan->Green.pb >= scan->pbScanBufEnd ) {
1480141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1481141cc406Sopenharmony_ci				wrap = 1;
1482141cc406Sopenharmony_ci			}
1483141cc406Sopenharmony_ci
1484141cc406Sopenharmony_ci			scan->Blue.pb += scan->sParam.Size.dwPhyBytes;
1485141cc406Sopenharmony_ci			if( scan->Blue.pb >= scan->pbScanBufEnd ) {
1486141cc406Sopenharmony_ci				scan->Blue.pb = scan->pbScanBufBegin + scan->dwBlueShift;
1487141cc406Sopenharmony_ci				wrap = 1;
1488141cc406Sopenharmony_ci			}
1489141cc406Sopenharmony_ci		} else {
1490141cc406Sopenharmony_ci			scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1491141cc406Sopenharmony_ci			if( scan->Green.pb >= scan->pbScanBufEnd )
1492141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1493141cc406Sopenharmony_ci		}
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci		/* on any wrap-around of the get pointers in one channel mode
1496141cc406Sopenharmony_ci		 * we have to reset them
1497141cc406Sopenharmony_ci		 */
1498141cc406Sopenharmony_ci		if( wrap ) {
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci			u_long len = scan->sParam.Size.dwPhyBytes;
1501141cc406Sopenharmony_ci
1502141cc406Sopenharmony_ci			if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1503141cc406Sopenharmony_ci
1504141cc406Sopenharmony_ci				if(scan->sParam.bDataType == SCANDATATYPE_Color) {
1505141cc406Sopenharmony_ci					len /= 3;
1506141cc406Sopenharmony_ci				}
1507141cc406Sopenharmony_ci				scan->Red.pb   = scan->pbScanBufBegin;
1508141cc406Sopenharmony_ci				scan->Green.pb = scan->pbScanBufBegin + len;
1509141cc406Sopenharmony_ci				scan->Blue.pb  = scan->pbScanBufBegin + len * 2UL;
1510141cc406Sopenharmony_ci			}
1511141cc406Sopenharmony_ci		}
1512141cc406Sopenharmony_ci
1513141cc406Sopenharmony_ci		/* line processed, check if we have to get more...
1514141cc406Sopenharmony_ci		 */
1515141cc406Sopenharmony_ci		scan->dwLinesToProcess--;
1516141cc406Sopenharmony_ci
1517141cc406Sopenharmony_ci		if( 0 == scan->dwLinesToProcess ) {
1518141cc406Sopenharmony_ci
1519141cc406Sopenharmony_ci			scan->dwLinesToProcess = usb_ReadData( dev );
1520141cc406Sopenharmony_ci			if( 0 == scan->dwLinesToProcess ) {
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci				if( usb_IsEscPressed())
1523141cc406Sopenharmony_ci					return _E_ABORT;
1524141cc406Sopenharmony_ci			}
1525141cc406Sopenharmony_ci		}
1526141cc406Sopenharmony_ci	}
1527141cc406Sopenharmony_ci	return 0;
1528141cc406Sopenharmony_ci}
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci/* END PLUSTEK-USB.C ........................................................*/
1531