1 /*.............................................................................
2  * Project : SANE library for Plustek flatbed scanners.
3  *.............................................................................
4  */
5 
6 /** @file plustek-usb.c
7  *  @brief The interface functions to the USB driver stuff.
8  *
9  * Based on sources acquired from Plustek Inc.<br>
10  * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de>
11  *
12  * History:
13  * - 0.40 - starting version of the USB support
14  * - 0.41 - removed CHECK
15  *        - added Canon to the manufacturer list
16  * - 0.42 - added warmup stuff
17  *        - added setmap function
18  *        - changed detection stuff, so we first check whether
19  *        - the vendor and product Ids match with the ones in our list
20  * - 0.43 - cleanup
21  * - 0.44 - changes to integration CIS based devices
22  * - 0.45 - added skipFine assignment
23  *        - added auto device name detection if only product and vendor id<br>
24  *          has been specified
25  *        - made 16-bit gray mode work
26  *        - added special handling for Genius devices
27  *        - added TPA autodetection for EPSON Photo
28  *        - fixed bug that causes warmup each time autodetected<br>
29  *          TPA on EPSON is used
30  *        - removed Genius from PCB-Id check
31  *        - added Compaq to the list
32  *        - removed the scaler stuff for CIS devices
33  *        - removed homeing stuff from readline function
34  *        - fixed flag setting in usbDev_startScan()
35  * - 0.46 - added additional branch to support alternate calibration
36  * - 0.47 - added special handling with 0x400 vendor ID and model override
37  *        - removed PATH_MAX
38  *        - change usbDev_stopScan and usbDev_open prototype
39  *        - cleanup
40  * - 0.48 - added function usb_CheckAndCopyAdjs()
41  * - 0.49 - changed autodetection
42  *        - added support for LiDE25 (pid 0x2220)
43  * - 0.50 - minor fix for startup reset
44  *          removed unnecessary calls to usbio_ResetLM983x()
45  *          1200DPI CIS devices don't use GrayFromColor any longer
46  * - 0.51 - added Syscan to the vendor list
47  *        - added SCANFLAG_Calibration handling
48  * - 0.52 - added _WAF_LOFF_ON_START and _WAF_INC_DARKTGT
49  *          handling in usbDev_startScan()
50  *          added Visioneer
51  * .
52  * <hr>
53  * This file is part of the SANE package.
54  *
55  * This program is free software; you can redistribute it and/or
56  * modify it under the terms of the GNU General Public License as
57  * published by the Free Software Foundation; either version 2 of the
58  * License, or (at your option) any later version.
59  *
60  * This program is distributed in the hope that it will be useful, but
61  * WITHOUT ANY WARRANTY; without even the implied warranty of
62  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
63  * General Public License for more details.
64  *
65  * You should have received a copy of the GNU General Public License
66  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
67  *
68  * As a special exception, the authors of SANE give permission for
69  * additional uses of the libraries contained in this release of SANE.
70  *
71  * The exception is that, if you link a SANE library with other files
72  * to produce an executable, this does not by itself cause the
73  * resulting executable to be covered by the GNU General Public
74  * License.  Your use of that executable is in no way restricted on
75  * account of linking the SANE library code into it.
76  *
77  * This exception does not, however, invalidate any other reasons why
78  * the executable file might be covered by the GNU General Public
79  * License.
80  *
81  * If you submit changes to SANE to the maintainers to be included in
82  * a subsequent release, you agree by submitting the changes that
83  * those changes may be distributed with this exception intact.
84  *
85  * If you write modifications of your own for SANE, it is your choice
86  * whether to permit this exception to apply to your modifications.
87  * If you do not wish that, delete this exception notice.
88  * <hr>
89  */
90 
91 /** useful for description tables
92  */
93 typedef struct {
94 	int   id;
95 	char *desc;
96 	char *desc_alt;
97 } TabDef, *pTabDef;
98 
99 /** to allow different vendors...
100  */
101 static TabDef usbVendors[] = {
102 
103 	{ 0x07B3, "Plustek",         NULL     },
104 	{ 0x0400, "NSC",             "Mustek" },
105 	{ 0x0458, "KYE/Genius",      NULL     },
106 	{ 0x03F0, "Hewlett-Packard", NULL     },
107 	{ 0x04B8, "Epson",           NULL     },
108 	{ 0x04A7, "Visioneer",       NULL     },
109 	{ 0x04A9, "Canon",           NULL     },
110 	{ 0x1606, "UMAX",            NULL     },
111 	{ 0x049F, "Compaq",          NULL     },
112 	{ 0x0A82, "Syscan",          NULL     },
113 	{ 0x0A53, "PandP Co., Ltd.", NULL     },
114 	{ 0xFFFF, NULL,              NULL     }
115 };
116 
117 /** we use at least 8 megs for scanning... */
118 #define _SCANBUF_SIZE (8 * 1024 * 1024)
119 
120 /********************** the USB scanner interface ****************************/
121 
122 /** remove the slash out of the model-name to obtain a valid filename
123  */
usb_normFileName( char *fname, char* buffer, u_long max_len )124 static SANE_Bool usb_normFileName( char *fname, char* buffer, u_long max_len )
125 {
126 	char *src, *dst;
127 
128 	if( NULL == fname )
129 		return SANE_FALSE;
130 
131 	if( strlen( fname ) >= max_len )
132 		return SANE_FALSE;
133 
134 	src = fname;
135 	dst = buffer;
136 	while( *src != '\0' ) {
137 
138 		if((*src == '/') || isspace(*src) || ispunct(*src))
139 			*dst = '_';
140 		else
141 			*dst = *src;
142 
143 		dst++;
144 		src++;
145 	}
146 	*dst = '\0';
147 
148 	return SANE_TRUE;
149 }
150 
151 /** do some range checking and copy the adjustment values from the
152  * frontend to our internal structures, so that the backend can take
153  * care of them.
154  */
usb_CheckAndCopyAdjs( Plustek_Device *dev )155 static void usb_CheckAndCopyAdjs( Plustek_Device *dev )
156 {
157 	if( dev->adj.lampOff >= 0 )
158 		dev->usbDev.dwLampOnPeriod = dev->adj.lampOff;
159 
160 	if( dev->adj.lampOffOnEnd >= 0 )
161 		dev->usbDev.bLampOffOnEnd = dev->adj.lampOffOnEnd;
162 
163 	if( dev->adj.skipCalibration > 0 )
164 		dev->usbDev.Caps.workaroundFlag |= _WAF_BYPASS_CALIBRATION;
165 
166 	if( dev->adj.skipFine > 0 )
167 		dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_FINE;
168 
169 	if( dev->adj.skipFineWhite > 0 )
170 		dev->usbDev.Caps.workaroundFlag |= _WAF_SKIP_WHITEFINE;
171 
172 	if( dev->adj.incDarkTgt > 0 )
173 		dev->usbDev.Caps.workaroundFlag |= _WAF_INC_DARKTGT;
174 
175 	if( dev->adj.skipDarkStrip > 0 )
176 		dev->usbDev.Caps.Normal.DarkShadOrgY = -1;
177 
178 	if( dev->adj.invertNegatives > 0 )
179 		dev->usbDev.Caps.workaroundFlag |= _WAF_INV_NEGATIVE_MAP;
180 }
181 
182 /**
183  * assign the values to the structures used by the currently found scanner
184  */
185 static void
usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor )186 usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor )
187 {
188 	char     *ptr;
189 	char      tmp_str1[PATH_MAX];
190 	char      tmp_str2[PATH_MAX];
191 	int       i;
192 	ScanParam sParam;
193 	u_short   tmp = 0;
194 	int       ret = 0;
195 
196 	DBG( _DBG_INFO, "usb_initDev(%d,0x%04x,%i)\n",
197 	                idx, vendor, dev->initialized );
198 	/* save capability flags... */
199 	if( dev->initialized >= 0 ) {
200 		tmp = DEVCAPSFLAG_TPA;
201 	}
202 
203 	/* copy the original values... */
204 	memcpy( &dev->usbDev.Caps, Settings[idx].pDevCaps, sizeof(DCapsDef));
205 	memcpy( &dev->usbDev.HwSetting, Settings[idx].pHwDef, sizeof(HWDef));
206 
207 	/* restore capability flags... */
208 	if( dev->initialized >= 0 ) {
209 		dev->usbDev.Caps.wFlags |= tmp;
210 	}
211 
212 	usb_CheckAndCopyAdjs( dev );
213 	DBG( _DBG_INFO, "Device WAF  : 0x%08lx\n", dev->usbDev.Caps.workaroundFlag );
214 	DBG( _DBG_INFO, "Transferrate: %lu Bytes/s\n", dev->transferRate );
215 
216 	/* adjust data origin
217 	 */
218 	dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x;
219 	dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y;
220 
221 	dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x;
222 	dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y;
223 
224 	dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x;
225 	dev->usbDev.Caps.Normal.DataOrigin.y -= dev->adj.pos.y;
226 
227 	/** adjust shading position
228 	 */
229 	if( dev->adj.posShadingY >= 0 )
230 		dev->usbDev.Caps.Normal.ShadingOriginY   = dev->adj.posShadingY;
231 
232 	if( dev->adj.tpaShadingY >= 0 )
233 		dev->usbDev.Caps.Positive.ShadingOriginY = dev->adj.tpaShadingY;
234 
235 	if( dev->adj.negShadingY >= 0 )
236 		dev->usbDev.Caps.Negative.ShadingOriginY = dev->adj.negShadingY;
237 
238 	/* adjust the gamma settings... */
239 	if( dev->adj.rgamma == 1.0 )
240 		dev->adj.rgamma = dev->usbDev.HwSetting.gamma;
241 	if( dev->adj.ggamma == 1.0 )
242 		dev->adj.ggamma = dev->usbDev.HwSetting.gamma;
243 	if( dev->adj.bgamma == 1.0 )
244 		dev->adj.bgamma = dev->usbDev.HwSetting.gamma;
245 	if( dev->adj.graygamma == 1.0 )
246 		dev->adj.graygamma = dev->usbDev.HwSetting.gamma;
247 
248 	/* the following you normally get from the registry...
249 	 */
250 	bMaxITA = 0;     /* Maximum integration time adjust */
251 
252 	dev->usbDev.ModelStr = Settings[idx].pModelString;
253 
254 	dev->fd = handle;
255 
256 	if( dev->initialized < 0 ) {
257 		if( usb_HasTPA( dev ))
258 			dev->usbDev.Caps.wFlags |= DEVCAPSFLAG_TPA;
259 	}
260 	DBG( _DBG_INFO, "Device Flags: 0x%08x\n", dev->usbDev.Caps.wFlags );
261 
262 	/* well now we patch the vendor string...
263 	 * if not found, the default vendor will be Plustek
264 	 */
265 	for( i = 0; usbVendors[i].desc != NULL; i++ ) {
266 
267 		if( usbVendors[i].id == vendor ) {
268 			dev->sane.vendor = usbVendors[i].desc;
269 			if (dev->usbDev.Caps.workaroundFlag & _WAF_USE_ALT_DESC )
270 				if (usbVendors[i].desc_alt )
271 					dev->sane.vendor = usbVendors[i].desc_alt;
272 			DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor );
273 			break;
274 		}
275 	}
276 
277 	dev->usbDev.dwTicksLampOn = 0;
278 	dev->usbDev.currentLamp   = usb_GetLampStatus( dev );
279 	usb_ResetRegisters( dev );
280 
281 	if( dev->initialized >= 0 )
282 		return;
283 
284 	usb_IsScannerReady( dev );
285 
286 	sParam.bBitDepth     = 8;
287 	sParam.bCalibration  = PARAM_Scan;
288 	sParam.bChannels     = 3;
289 	sParam.bDataType     = SCANDATATYPE_Color;
290 	sParam.bSource       = SOURCE_Reflection;
291 	sParam.Origin.x      = 0;
292 	sParam.Origin.y      = 0;
293 	sParam.UserDpi.x     = 150;
294 	sParam.UserDpi.y     = 150;
295 	sParam.dMCLK         = 4;
296 	sParam.Size.dwPixels = 0;
297 
298 	/* create calibration-filename */
299 	sprintf( tmp_str2, "%s-%s",
300 	         dev->sane.vendor, dev->usbDev.ModelStr );
301 
302 	if( !usb_normFileName( tmp_str2, tmp_str1, PATH_MAX )) {
303 		strcpy( tmp_str1, "plustek-default" );
304 	}
305 
306 	ptr = getenv ("HOME");
307 	ret = ( NULL == ptr )?
308 		snprintf( tmp_str2, sizeof(tmp_str2), "/tmp/%s", tmp_str1 ):
309 		snprintf( tmp_str2, sizeof(tmp_str2), "%s/.sane/%s", ptr, tmp_str1 );
310 
311 	if ((ret < 0) || (ret > (int)sizeof(tmp_str2))) {
312 		DBG( _DBG_WARNING,
313 		     "Failed to generate calibration file path. Default substituted.\n" );
314 		snprintf(tmp_str2, sizeof(tmp_str2), "/tmp/plustek-default");
315 	}
316 
317 	dev->calFile = strdup( tmp_str2 );
318 	DBG( _DBG_INFO, "Calibration file-names set to:\n" );
319 	DBG( _DBG_INFO, ">%s-coarse.cal<\n", dev->calFile );
320 	DBG( _DBG_INFO, ">%s-fine.cal<\n", dev->calFile );
321 
322 	/* initialize the ASIC registers */
323 	usb_SetScanParameters( dev, &sParam );
324 
325 	/* check and move sensor to its home position */
326 	usb_ModuleToHome( dev, SANE_FALSE );
327 
328 	/* set the global flag, that we are initialized so far */
329 	dev->initialized = idx;
330 }
331 
332 /**
333  * will be used for retrieving a Plustek device
334  */
usb_CheckForPlustekDevice( int handle, Plustek_Device *dev )335 static int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev )
336 {
337 	char   tmp[50];
338 	char   pcbStr[10];
339 	u_char reg59[3], reg59s[3], pcbID;
340 	int    i, result;
341 
342 	/*
343 	 * Plustek uses the misc IO 12 to get the PCB ID
344 	 * (PCB = printed circuit board), so it's possible to have one
345 	 * product ID and up to 7 different devices...
346 	 */
347 	DBG( _DBG_INFO, "Trying to get the pcbID of a Plustek device...\n" );
348 
349 	/* get the PCB-ID */
350 	result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
351 	if( SANE_STATUS_GOOD != result ) {
352 		sanei_usb_close( handle );
353 		return -1;
354 	}
355 
356 	reg59[0] = 0x22;	/* PIO1: Input, PIO2: Input         */
357 	reg59[1] = 0x02;	/* PIO3: Input, PIO4: Output as low */
358 	reg59[2] = 0x03;
359 
360 	result = sanei_lm983x_write( handle, 0x59,  reg59, 3, SANE_TRUE );
361 	if( SANE_STATUS_GOOD != result ) {
362 		sanei_usb_close( handle );
363 		return -1;
364 	}
365 
366 	result = sanei_lm983x_read ( handle, 0x02, &pcbID, 1, SANE_TRUE );
367 	if( SANE_STATUS_GOOD != result ) {
368 		sanei_usb_close( handle );
369 		return -1;
370 	}
371 
372 	pcbID = (u_char)((pcbID >> 2) & 0x07);
373 
374 	result = sanei_lm983x_read( handle, 0x59, reg59s, 3, SANE_TRUE );
375 	if( SANE_STATUS_GOOD != result ) {
376 		sanei_usb_close( handle );
377 		return -1;
378 	}
379 
380 	DBG( _DBG_INFO, "pcbID=0x%02x\n", pcbID );
381 
382 	/* now roam through the setting list... */
383 	strncpy( tmp, dev->usbId, 13 );
384 	tmp[13] = '\0';
385 
386 	sprintf( pcbStr, "-%u", pcbID );
387 	strcat ( tmp, pcbStr );
388 
389 	DBG( _DBG_INFO, "Checking for device >%s<\n", tmp );
390 
391 	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
392 
393 		if( 0 == strcmp( Settings[i].pIDString, tmp )) {
394 			DBG(_DBG_INFO, "Device description for >%s< found.\n", tmp );
395 			usb_initDev( dev, i, handle, dev->usbDev.vendor );
396 			return handle;
397 		}
398 	}
399 
400 	return -1;
401 }
402 
403 /**
404  * will be called upon sane_exit
405  */
usbDev_shutdown( Plustek_Device *dev )406 static void usbDev_shutdown( Plustek_Device *dev  )
407 {
408 	SANE_Int handle;
409 
410 	DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n",
411 	                dev->fd, dev->sane.name );
412 	if( NULL == dev->usbDev.ModelStr ) {
413 		DBG( _DBG_INFO, "Function ignored!\n" );
414 		return;
415 	}
416 
417 	if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) {
418 
419 		dev->fd = handle;
420 
421 		DBG( _DBG_INFO, "Waiting for scanner-ready...\n" );
422 		usb_IsScannerReady( dev );
423 
424 		if( 0 != dev->usbDev.bLampOffOnEnd ) {
425 
426 			DBG( _DBG_INFO, "Switching lamp off...\n" );
427 			usb_LampOn( dev, SANE_FALSE, SANE_FALSE );
428 		}
429 		dev->fd = -1;
430 		sanei_usb_close( handle );
431 	}
432 	usb_StopLampTimer( dev );
433 }
434 
435 /**
436  * This function checks whether a device, described by a given
437  * string(vendor and product ID), is support by this backend or not
438  *
439  * @param usbIdStr - string consisting out of product and vendor ID
440  *                   format: "0xVVVVx0xPPPP" VVVV = Vendor ID, PPP = Product ID
441  * @returns; SANE_TRUE if supported, SANE_FALSE if not
442  */
usb_IsDeviceInList( char *usbIdStr )443 static SANE_Bool usb_IsDeviceInList( char *usbIdStr )
444 {
445 	int i;
446 
447 	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
448 
449 		if( 0 == strncmp( Settings[i].pIDString, usbIdStr, 13 ))
450 			return SANE_TRUE;
451 	}
452 	return SANE_FALSE;
453 }
454 
455 /** get last valid entry of a list
456  */
457 static DevList*
getLast( DevList *l )458 getLast( DevList *l )
459 {
460 	if( l == NULL )
461 		return NULL;
462 
463 	while( l->next != NULL )
464 		l = l->next;
465 	return l;
466 }
467 
468 /** add a new entry to our internal device list, when a device is detected
469  */
usb_attach( SANE_String_Const dev_name )470 static SANE_Status usb_attach( SANE_String_Const dev_name )
471 {
472 	int      len;
473 	DevList *tmp, *last;
474 
475 	/* get some memory for the entry... */
476 	len = sizeof(DevList) + strlen(dev_name) + 1;
477 	tmp = (DevList*)malloc(len);
478 
479 	/* initialize and set the values */
480 	memset(tmp, 0, len );
481 
482 	/* the device name is part of our structure space */
483 	tmp->dev_name = &((char*)tmp)[sizeof(DevList)];
484 	strcpy( tmp->dev_name, dev_name );
485 	tmp->attached = SANE_FALSE;
486 
487 	/* root set ? */
488 	if( usbDevs == NULL ) {
489 		usbDevs = tmp;
490 	} else {
491 		last = getLast(usbDevs); /* append... */
492 		last->next = tmp;
493 	}
494 	return SANE_STATUS_GOOD;
495 }
496 
497 /**
498  */
499 static void
usbGetList( DevList **devs )500 usbGetList( DevList **devs )
501 {
502 	int        i;
503 	SANE_Bool  il;
504 	SANE_Word  v, p;
505 	DevList   *tmp;
506 
507 	DBG( _DBG_INFO, "Retrieving all supported and conntected devices\n" );
508 	for( i = 0; NULL != Settings[i].pIDString; i++ ) {
509 
510 		v = strtol( &(Settings[i].pIDString)[0], 0, 0 );
511 		p = strtol( &(Settings[i].pIDString)[7], 0, 0 );
512 
513 		/* check if this vendor- and product-ID has already been added, needed
514 		 * for Plustek devices - here one product-ID is used for more than one
515 		 * device type...
516 		 */
517 		il = SANE_FALSE;
518 		for( tmp = *devs; tmp ; tmp = tmp->next ) {
519 			if( tmp->device_id == p && tmp->vendor_id == v ) {
520 				il = SANE_TRUE;
521 				break;
522 			}
523 		}
524 		if( il ) {
525 			DBG( _DBG_INFO2, "Already in list: 0x%04x-0x%04x\n", v, p );
526 			continue;
527 		}
528 
529 		/* get the last entry... */
530 		tmp = getLast(*devs);
531 		DBG( _DBG_INFO2, "Checking for 0x%04x-0x%04x\n", v, p );
532 		sanei_usb_find_devices( v, p, usb_attach );
533 
534 		if( getLast(*devs) != tmp ) {
535 
536 			if( tmp == NULL )
537 				tmp = *devs;
538 			else
539 				tmp = tmp->next;
540 
541 			while( tmp != NULL ) {
542 				tmp->vendor_id = v;
543 				tmp->device_id = p;
544 				tmp = tmp->next;
545 			}
546 		}
547 	}
548 
549 	DBG( _DBG_INFO, "Available and supported devices:\n" );
550 	if( *devs == NULL )
551 		DBG( _DBG_INFO, "NONE.\n" );
552 
553 	for( tmp = *devs; tmp; tmp = tmp->next ) {
554 		DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n",
555 			tmp->dev_name, tmp->vendor_id, tmp->device_id );
556 	}
557 }
558 
559 /**
560  */
usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock )561 static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock )
562 {
563 	char        dn[512];
564 	char        devStr[50];
565 	int         result;
566 	int         i;
567 	int         lc;
568 	SANE_Int    handle;
569 	SANE_Byte   version;
570 	SANE_Word   vendor, product;
571 	SANE_Bool   was_empty;
572 	SANE_Status status;
573 	DevList    *tmp;
574 
575 	DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n",
576 	    dev->name, dev->usbId, (void*)devs );
577 
578 	/* preset our internal usb device structure */
579 	memset( &dev->usbDev, 0, sizeof(DeviceDef));
580 
581 	/* devs is NULL, when called from sane_start */
582 	if( devs ) {
583 
584 		dn[0] = '\0';
585 		if( !strcmp( dev->name, "auto" )) {
586 
587 			/* use the first "unattached"... */
588 			for( tmp = devs; tmp; tmp = tmp->next ) {
589 				if( !tmp->attached ) {
590 					tmp->attached = SANE_TRUE;
591 					strcpy( dn, tmp->dev_name );
592 					break;
593 				}
594 			}
595 		} else {
596 
597 			vendor  = strtol( &dev->usbId[0], 0, 0 );
598 			product = strtol( &dev->usbId[7], 0, 0 );
599 
600 			/* check the first match... */
601 			for( tmp = devs; tmp; tmp = tmp->next ) {
602 				if( tmp->vendor_id == vendor && tmp->device_id == product ) {
603 					if( !tmp->attached ) {
604 						tmp->attached = SANE_TRUE;
605 						strcpy( dn, tmp->dev_name );
606 						break;
607 					}
608 				}
609 			}
610 		}
611 
612 		if( !dn[0] ) {
613 			DBG( _DBG_ERROR, "No supported device found!\n" );
614 			return -1;
615 		}
616 
617 		status = sanei_access_lock( dn, 5 );
618 		if( SANE_STATUS_GOOD != status ) {
619 			DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
620 			return -1;
621 		}
622 
623 		status = sanei_usb_open( dn, &handle );
624 		if( SANE_STATUS_GOOD != status ) {
625 			DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
626 			     strerror(errno), errno);
627 			sanei_access_unlock( dev->sane.name );
628 			return -1;
629 		}
630 
631 		/* replace the old devname, so we are able to have multiple
632 		 * auto-detected devices
633 		 */
634 		free( dev->name );
635 		dev->name      = strdup(dn);
636 		dev->sane.name = dev->name;
637 
638 	} else {
639 
640 		status = sanei_access_lock( dev->sane.name, 5 );
641 		if( SANE_STATUS_GOOD != status ) {
642 			DBG( _DBG_ERROR, "sanei_access_lock failed: %d\n", status );
643 			return -1;
644 		}
645 
646 		status = sanei_usb_open( dev->name, &handle );
647 		if( SANE_STATUS_GOOD != status ) {
648 			DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n",
649 			     strerror(errno), errno);
650 			sanei_access_unlock( dev->sane.name );
651 			return -1;
652 		}
653 	}
654 
655 	was_empty = SANE_FALSE;
656 
657 	result = sanei_usb_get_vendor_product( handle, &vendor, &product );
658 
659 	if( SANE_STATUS_GOOD == result ) {
660 
661 		sprintf( devStr, "0x%04X-0x%04X", vendor, product );
662 
663 		DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product);
664 
665 		if( dev->usbId[0] != '\0' ) {
666 
667 			if( 0 != strcmp( dev->usbId, devStr )) {
668 				DBG( _DBG_ERROR, "Specified Vendor and Product ID "
669 								 "doesn't match with the ones\n"
670 								 "in the config file\n" );
671 				sanei_access_unlock( dev->sane.name );
672 				sanei_usb_close( handle );
673 				return -1;
674 			}
675 		} else {
676 			sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product );
677 			was_empty = SANE_TRUE;
678 		}
679 
680 	} else {
681 
682 		DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" );
683 
684 		/* if the ioctl stuff is not supported by the kernel and we have
685 		 * nothing specified, we have to give up...
686 		 */
687 		if( dev->usbId[0] == '\0' ) {
688 			DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, "
689 							 "please specify in config file.\n" );
690 			sanei_access_unlock( dev->sane.name );
691 			sanei_usb_close( handle );
692 	        return -1;
693 		}
694 
695 		vendor  = strtol( &dev->usbId[0], 0, 0 );
696 		product = strtol( &dev->usbId[7], 0, 0 );
697 		DBG( _DBG_INFO, "... using the specified: "
698 		                "0x%04X-0x%04X\n", vendor, product );
699 	}
700 
701 	/* before accessing the scanner, check if supported!
702 	 */
703 	if( !usb_IsDeviceInList( dev->usbId )) {
704 		DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId );
705 		sanei_access_unlock( dev->sane.name );
706 		sanei_usb_close( handle );
707 		return -1;
708 	}
709 
710 	status = usbio_DetectLM983x( handle, &version );
711 	if( SANE_STATUS_GOOD != status ) {
712 		sanei_usb_close( handle );
713 		sanei_access_unlock( dev->sane.name );
714 		return -1;
715 	}
716 
717 	if ((version < 3) || (version > 4)) {
718 		DBG( _DBG_ERROR, "This is not a LM9831 or LM9832 chip based scanner.\n" );
719 		sanei_usb_close( handle );
720 		sanei_access_unlock( dev->sane.name );
721 		return -1;
722 	}
723 
724 	/* need to set the handle and the detected chiptype... */
725 	dev->fd = handle;
726 	dev->usbDev.HwSetting.chip = (version==3 ? _LM9831:_LM9832);
727 	usbio_ResetLM983x( dev );
728 	dev->fd = -1;
729 
730 	dev->usbDev.vendor  = vendor;
731 	dev->usbDev.product = product;
732 
733 	DBG( _DBG_INFO, "Detected vendor & product ID: "
734 		                "0x%04X-0x%04X\n", vendor, product );
735 
736 	/*
737 	 * Plustek uses the misc IO 1/2 to get the PCB ID
738 	 * (PCB = printed circuit board), so it's possible to have one
739 	 * product ID and up to 7 different devices...
740 	 */
741 	if( 0x07B3 == vendor ) {
742 
743 		handle = usb_CheckForPlustekDevice( handle, dev );
744 
745 		if( was_empty )
746 			dev->usbId[0] = '\0';
747 
748 		if( handle >= 0 ) {
749 			if( !keep_lock )
750 				sanei_access_unlock( dev->sane.name );
751 			return handle;
752 		}
753 
754 	} else {
755 
756 		/* now roam through the setting list... */
757 		lc = 13;
758 		strncpy( devStr, dev->usbId, lc );
759 		devStr[lc] = '\0';
760 
761 		if( 0x400 == vendor ) {
762 			if((dev->adj.mov < 0) || (dev->adj.mov > 1)) {
763 				DBG(_DBG_INFO, "BearPaw MOV out of range: %d\n", dev->adj.mov);
764 				dev->adj.mov = 0;
765 			}
766 			sprintf( devStr, "%s-%d", dev->usbId, dev->adj.mov );
767 			lc = strlen(devStr);
768 			DBG( _DBG_INFO, "BearPaw device: %s (%d)\n", devStr, lc );
769 		}
770 
771 		if( was_empty )
772 			dev->usbId[0] = '\0';
773 
774 		/* if we don't use the PCD ID extension...
775 		 */
776 		for( i = 0; NULL != Settings[i].pIDString; i++ ) {
777 
778 			if( 0 == strncmp( Settings[i].pIDString, devStr, lc )) {
779 				DBG( _DBG_INFO, "Device description for >%s< found.\n", devStr );
780 				usb_initDev( dev, i, handle, vendor );
781 				if( !keep_lock )
782 					sanei_access_unlock( dev->sane.name );
783 			    return handle;
784 			}
785 		}
786 	}
787 
788 	sanei_access_unlock( dev->sane.name );
789 	sanei_usb_close( handle );
790 	DBG( _DBG_ERROR, "No matching device found >%s<\n", devStr );
791 	return -1;
792 }
793 
794 /**
795  */
usbDev_close( Plustek_Device *dev )796 static int usbDev_close( Plustek_Device *dev )
797 {
798 	DBG( _DBG_INFO, "usbDev_close()\n" );
799 	sanei_usb_close( dev->fd );
800 	dev->fd = -1;
801 	return 0;
802 }
803 
804 /** convert the stuff
805  */
usbDev_getCaps( Plustek_Device *dev )806 static int usbDev_getCaps( Plustek_Device *dev )
807 {
808 	DCapsDef *scaps = &dev->usbDev.Caps;
809 
810 	DBG( _DBG_INFO, "usbDev_getCaps()\n" );
811 
812 	dev->caps.dwFlag = 0;
813 
814 	if(((DEVCAPSFLAG_Positive & scaps->wFlags)  &&
815 	    (DEVCAPSFLAG_Negative & scaps->wFlags)) ||
816 		(DEVCAPSFLAG_TPA      & scaps->wFlags)) {
817 		dev->caps.dwFlag |= SFLAG_TPA;
818 	}
819 
820 	dev->caps.wMaxExtentX = scaps->Normal.Size.x;
821 	dev->caps.wMaxExtentY = scaps->Normal.Size.y;
822 	return 0;
823 }
824 
825 /** usbDev_getCropInfo
826  * function to set the image relevant stuff
827  */
usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci )828 static int usbDev_getCropInfo( Plustek_Device *dev, CropInfo *ci )
829 {
830 	WinInfo size;
831 
832 	DBG( _DBG_INFO, "usbDev_getCropInfo()\n" );
833 
834 	usb_GetImageInfo( dev, &ci->ImgDef, &size );
835 
836 	ci->dwPixelsPerLine = size.dwPixels;
837 	ci->dwLinesPerArea  = size.dwLines;
838 	ci->dwBytesPerLine  = size.dwBytes;
839 
840 	if( ci->ImgDef.dwFlag & SCANFLAG_DWORDBoundary )
841 		ci->dwBytesPerLine = (ci->dwBytesPerLine + 3UL) & 0xfffffffcUL;
842 
843 	DBG( _DBG_INFO, "PPL = %lu\n",  ci->dwPixelsPerLine );
844 	DBG( _DBG_INFO, "LPA = %lu\n",  ci->dwLinesPerArea );
845 	DBG( _DBG_INFO, "BPL = %lu\n",  ci->dwBytesPerLine );
846 
847 	return 0;
848 }
849 
850 /**
851  */
usbDev_setMap( Plustek_Device *dev, SANE_Word *map, SANE_Word length, SANE_Word channel )852 static int usbDev_setMap( Plustek_Device *dev, SANE_Word *map,
853                           SANE_Word length, SANE_Word channel )
854 {
855 	SANE_Word i, idx;
856 
857 	DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n",channel,(unsigned long)map);
858 
859 	_VAR_NOT_USED( dev );
860 
861 	if( channel == _MAP_MASTER ) {
862 
863 		for( i = 0; i < length; i++ ) {
864 			a_bMap[i]            = (SANE_Byte)map[i];
865 			a_bMap[length +i]    = (SANE_Byte)map[i];
866 			a_bMap[(length*2)+i] = (SANE_Byte)map[i];
867 		}
868 
869 	} else {
870 
871 		idx = 0;
872 		if( channel == _MAP_GREEN )
873 			idx = 1;
874 		if( channel == _MAP_BLUE )
875 			idx = 2;
876 
877 		for( i = 0; i < length; i++ ) {
878 			a_bMap[(length * idx)+i] = (SANE_Byte)map[i];
879 		}
880 	}
881 
882 	return 0;
883 }
884 
885 /**
886  */
887 static int
usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si )888 usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si )
889 {
890 	ScanDef  *scan  = &dev->scanning;
891 	DCapsDef *caps = &dev->usbDev.Caps;
892 
893 	DBG( _DBG_INFO, "usbDev_setScanEnv()\n" );
894 
895 	/* clear all the stuff */
896 	memset( scan, 0, sizeof(ScanDef));
897 
898 	if((si->ImgDef.dwFlag & SCANDEF_Adf) &&
899 	   (si->ImgDef.dwFlag & SCANDEF_ContinuousScan)) {
900 		scan->sParam.dMCLK = dMCLK_ADF;
901 	}
902 
903     /* Save necessary information */
904 	scan->fGrayFromColor = 0;
905 
906 	/* for some devices and settings, we tweak the physical settings
907 	 * how to get the image - but not in calibration mode
908 	 */
909 	if((si->ImgDef.dwFlag & SCANFLAG_Calibration) == 0) {
910 
911 		if( si->ImgDef.wDataType == COLOR_256GRAY ) {
912 
913 			if( !(si->ImgDef.dwFlag & SCANDEF_Adf) && !usb_IsCISDevice(dev) &&
914 			   (caps->OpticDpi.x == 1200 && si->ImgDef.xyDpi.x <= 300)) {
915 				scan->fGrayFromColor = 2;
916 				si->ImgDef.wDataType = COLOR_TRUE24;
917 				DBG( _DBG_INFO, "* Gray from color set!\n" );
918 			}
919 
920 			if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
921 				DBG( _DBG_INFO, "* Gray(8-bit) from color set!\n" );
922 				scan->fGrayFromColor = 2;
923 				si->ImgDef.wDataType = COLOR_TRUE24;
924 			}
925 
926 		} else if ( si->ImgDef.wDataType == COLOR_GRAY16 ) {
927 			if( caps->workaroundFlag & _WAF_GRAY_FROM_COLOR ) {
928 				DBG( _DBG_INFO, "* Gray(16-bit) from color set!\n" );
929 				scan->fGrayFromColor = 2;
930 				si->ImgDef.wDataType = COLOR_TRUE48;
931 			}
932 
933 		} else if ( si->ImgDef.wDataType == COLOR_BW ) {
934 			if( caps->workaroundFlag & _WAF_BIN_FROM_COLOR ) {
935 				DBG( _DBG_INFO, "* Binary from color set!\n" );
936 				scan->fGrayFromColor = 10;
937 				si->ImgDef.wDataType = COLOR_TRUE24;
938 			}
939 		}
940 	}
941 
942 	usb_SaveImageInfo( dev, &si->ImgDef );
943 	usb_GetImageInfo ( dev, &si->ImgDef, &scan->sParam.Size );
944 
945 	/* mask the flags */
946 	scan->dwFlag = si->ImgDef.dwFlag &
947 	              (SCANFLAG_bgr | SCANFLAG_BottomUp | SCANFLAG_Calibration |
948 	               SCANFLAG_DWORDBoundary | SCANFLAG_RightAlign |
949 	               SCANFLAG_StillModule | SCANDEF_Adf | SCANDEF_ContinuousScan);
950 
951 	if( !(SCANDEF_QualityScan & si->ImgDef.dwFlag)) {
952 		DBG( _DBG_INFO, "* Preview Mode set!\n" );
953 	} else {
954 		DBG( _DBG_INFO, "* Preview Mode NOT set!\n" );
955 		scan->dwFlag |= SCANDEF_QualityScan;
956 	}
957 
958 	scan->sParam.brightness  = si->siBrightness;
959 	scan->sParam.contrast    = si->siContrast;
960 
961 	if( scan->sParam.bBitDepth <= 8 )
962 		scan->dwFlag &= ~SCANFLAG_RightAlign;
963 
964 	if( scan->dwFlag & SCANFLAG_DWORDBoundary ) {
965 		if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
966 			scan->dwBytesLine = (scan->sParam.Size.dwBytes / 3 + 3) & 0xfffffffcUL;
967 		else
968 			scan->dwBytesLine = (scan->sParam.Size.dwBytes + 3UL) & 0xfffffffcUL;
969 
970 	} else {
971 
972 		if( scan->fGrayFromColor && scan->fGrayFromColor < 10)
973 			scan->dwBytesLine = scan->sParam.Size.dwBytes / 3;
974 		else
975 			scan->dwBytesLine = scan->sParam.Size.dwBytes;
976 	}
977 
978 	/* on CIS based devices we have to reconfigure the illumination
979 	 * settings for the gray modes
980 	 */
981 	usb_AdjustCISLampSettings( dev, SANE_TRUE );
982 
983 	if( scan->dwFlag & SCANFLAG_BottomUp)
984 		scan->lBufAdjust = -(long)scan->dwBytesLine;
985 	else
986 		scan->lBufAdjust = scan->dwBytesLine;
987 
988 	/* LM9831 has a BUG in 16-bit mode,
989 	 * so we generate pseudo 16-bit data from 8-bit
990 	 */
991 	if( scan->sParam.bBitDepth > 8 ) {
992 
993 		if( _LM9831 == dev->usbDev.HwSetting.chip ) {
994 
995 			scan->sParam.bBitDepth = 8;
996 			scan->dwFlag |= SCANFLAG_Pseudo48;
997 			scan->sParam.Size.dwBytes >>= 1;
998 		}
999 	}
1000 
1001 	/* Source selection */
1002 	if( scan->sParam.bSource == SOURCE_Reflection ) {
1003 
1004 		dev->usbDev.pSource = &caps->Normal;
1005 		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1006 		                                      (u_long)dev->usbDev.Normal.lLeft;
1007 		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1008 		                                        (u_long)dev->usbDev.Normal.lUp;
1009 
1010 	} else if( scan->sParam.bSource == SOURCE_Transparency ) {
1011 
1012 		dev->usbDev.pSource = &caps->Positive;
1013 		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1014 		                                    (u_long)dev->usbDev.Positive.lLeft;
1015 		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1016 		                                      (u_long)dev->usbDev.Positive.lUp;
1017 
1018 	} else if( scan->sParam.bSource == SOURCE_Negative ) {
1019 
1020 		dev->usbDev.pSource = &caps->Negative;
1021 		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1022 		                                    (u_long)dev->usbDev.Negative.lLeft;
1023 		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1024 		                                      (u_long)dev->usbDev.Negative.lUp;
1025 
1026 	} else {
1027 
1028 		dev->usbDev.pSource = &dev->usbDev.Caps.Adf;
1029 		scan->sParam.Origin.x += dev->usbDev.pSource->DataOrigin.x +
1030 		                                      (u_long)dev->usbDev.Normal.lLeft;
1031 		scan->sParam.Origin.y += dev->usbDev.pSource->DataOrigin.y +
1032 		                                        (u_long)dev->usbDev.Normal.lUp;
1033 	}
1034 
1035 	if( scan->sParam.bSource == SOURCE_ADF ) {
1036 
1037 		if( scan->dwFlag & SCANDEF_ContinuousScan )
1038 			dev->usbDev.fLastScanIsAdf = SANE_TRUE;
1039 		else
1040 			dev->usbDev.fLastScanIsAdf = SANE_FALSE;
1041 	}
1042 
1043 	return 0;
1044 }
1045 
1046 /**
1047  */
1048 static int
usbDev_stopScan( Plustek_Device *dev )1049 usbDev_stopScan( Plustek_Device *dev )
1050 {
1051 	DBG( _DBG_INFO, "usbDev_stopScan()\n" );
1052 
1053 	/* in cancel-mode we first stop the motor */
1054 	usb_ScanEnd( dev );
1055 
1056 	dev->scanning.dwFlag = 0;
1057 
1058 	if( NULL != dev->scanning.pScanBuffer ) {
1059 
1060 		free( dev->scanning.pScanBuffer );
1061 		dev->scanning.pScanBuffer = NULL;
1062 		usb_StartLampTimer( dev );
1063 	}
1064 	return 0;
1065 }
1066 
1067 /**
1068  */
1069 static int
usbDev_startScan( Plustek_Device *dev )1070 usbDev_startScan( Plustek_Device *dev )
1071 {
1072 	ScanDef *scan = &dev->scanning;
1073 	DBG( _DBG_INFO, "usbDev_startScan()\n" );
1074 
1075 /* HEINER: Preview currently not working correctly */
1076 #if 0
1077 	if( scan->dwFlag & SCANDEF_QualityScan )
1078 		dev->usbDev.a_bRegs[0x0a] = 0;
1079 	else
1080 		dev->usbDev.a_bRegs[0x0a] = 1;
1081 #endif
1082 	dev->usbDev.a_bRegs[0x0a] = 0;
1083 
1084 	if((scan->dwFlag & SCANDEF_Adf) && (scan->dwFlag & SCANDEF_ContinuousScan)) {
1085 		scan->fCalibrated = SANE_TRUE;
1086 	} else {
1087 		scan->fCalibrated = SANE_FALSE;
1088 	}
1089 
1090 	scan->sParam.PhyDpi.x = usb_SetAsicDpiX(dev,scan->sParam.UserDpi.x);
1091 	scan->sParam.PhyDpi.y = usb_SetAsicDpiY(dev,scan->sParam.UserDpi.y);
1092 
1093 	/* Allocate shading/scan buffer */
1094 	scan->pScanBuffer = (u_long*)malloc( _SCANBUF_SIZE );
1095 
1096 	if( scan->pScanBuffer == NULL )
1097 		return _E_ALLOC;
1098 
1099 	scan->dwFlag |= SCANFLAG_StartScan;
1100 
1101 	/* some devices (esp. BearPaw) do need a lamp switch off before
1102 	 * switching it on again. Otherwise it might happen that the lamp
1103 	 * remains off
1104 	 */
1105 	if(dev->usbDev.Caps.workaroundFlag & _WAF_LOFF_ON_START) {
1106 		if (usb_GetLampStatus(dev))
1107 			usb_LampOn( dev, SANE_FALSE, SANE_TRUE );
1108 	}
1109 
1110 	usb_LampOn( dev, SANE_TRUE, SANE_TRUE );
1111 
1112 	m_fStart    = m_fFirst = SANE_TRUE;
1113 	m_fAutoPark = (scan->dwFlag&SCANFLAG_StillModule)?SANE_FALSE:SANE_TRUE;
1114 
1115 	if( usb_IsSheetFedDevice(dev))
1116 		if(usb_InCalibrationMode(dev))
1117 			m_fAutoPark = SANE_FALSE;
1118 
1119 	usb_StopLampTimer( dev );
1120 	return 0;
1121 }
1122 
1123 /**
1124  * do the reading stuff here...
1125  * first we perform the calibration step, and then we read the image
1126  * line for line
1127  */
1128 static int
usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf )1129 usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf )
1130 {
1131 	int       result;
1132 	SANE_Bool use_alt_cal = SANE_FALSE;
1133 	ScanDef  *scan        = &dev->scanning;
1134 	DCapsDef *scaps       = &dev->usbDev.Caps;
1135 	HWDef    *hw          = &dev->usbDev.HwSetting;
1136 
1137 	DBG( _DBG_INFO, "usbDev_PrepareScan()\n" );
1138 
1139 	/* check the current position of the sensor and move it back
1140 	 * to it's home position if necessary...
1141 	 */
1142 	if( !usb_IsSheetFedDevice(dev))
1143 		usb_SensorStatus( dev );
1144 
1145 	/* CIS devices need special handling... */
1146 	if( usb_IsCISDevice(dev)) {
1147 		use_alt_cal = SANE_TRUE;
1148 
1149 	} else {
1150 
1151 		if( dev->adj.altCalibrate )
1152 			use_alt_cal = SANE_TRUE;
1153 	}
1154 
1155 	/* for the skip functionality use the "old" calibration functions */
1156 	if( dev->usbDev.Caps.workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1157 		use_alt_cal = SANE_FALSE;
1158 	}
1159 
1160 	if( use_alt_cal ) {
1161 		result = cano_DoCalibration( dev );
1162 	} else {
1163 		result = usb_DoCalibration( dev );
1164 	}
1165 
1166 	if( SANE_TRUE != result ) {
1167 		DBG( _DBG_ERROR, "calibration failed!!!\n" );
1168 		return _E_ABORT;
1169 	}
1170 
1171 	if( dev->adj.cacheCalData )
1172 		usb_SaveCalData( dev );
1173 
1174 	DBG( _DBG_INFO, "calibration done.\n" );
1175 	if( usb_InCalibrationMode(dev))
1176 		return 0;
1177 
1178 	if( !(scan->dwFlag & SCANFLAG_Scanning)) {
1179 
1180 		usleep( 10 * 1000 );
1181 
1182 		/* need to preset that here, as we need it during parameter setting
1183 		 */
1184 		scan->bLinesToSkip = (u_char)(scan->sParam.PhyDpi.y / 50);
1185 
1186 		scan->dwLinesDiscard = 0;
1187 		if( scan->sParam.bChannels == 3 ) {
1188 			scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1189 			                       scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1190 			scan->dwLinesDiscard <<= 1;
1191 		}
1192 
1193 		if( !usb_SetScanParameters( dev, &scan->sParam )) {
1194 			DBG( _DBG_ERROR, "Setting Scan Parameters failed!\n" );
1195 			return 0;
1196 		}
1197 
1198 		/* if we bypass the calibration step, we wait on lamp warmup here...
1199 		 */
1200 		if( scaps->workaroundFlag & _WAF_BYPASS_CALIBRATION ) {
1201 			if( !usb_Wait4Warmup( dev )) {
1202 				DBG( _DBG_INFO, "usbDev_Prepare() - Cancel detected...\n" );
1203 				return 0;
1204 			}
1205 		}
1206 
1207 		scan->pbScanBufBegin = (u_char*)scan->pScanBuffer;
1208 
1209 		if((dev->caps.dwFlag & SFLAG_ADF) && (scaps->OpticDpi.x == 600))
1210 			scan->dwLinesScanBuf = 8;
1211 		else
1212 			scan->dwLinesScanBuf = 32;
1213 
1214 		scan->dwBytesScanBuf     = scan->dwLinesScanBuf *
1215 		                           scan->sParam.Size.dwPhyBytes;
1216 
1217 		scan->dwNumberOfScanBufs = _SCANBUF_SIZE / scan->dwBytesScanBuf;
1218 		scan->dwLinesPerScanBufs = scan->dwNumberOfScanBufs *
1219 		                           scan->dwLinesScanBuf;
1220 		scan->pbScanBufEnd       = scan->pbScanBufBegin +
1221 		                           scan->dwLinesPerScanBufs *
1222 		                           scan->sParam.Size.dwPhyBytes;
1223 		scan->dwRedShift   = 0;
1224 		scan->dwBlueShift  = 0;
1225 		scan->dwGreenShift = 0;
1226 
1227 		/* CCD scanner */
1228 		if( scan->sParam.bChannels == 3 ) {
1229 
1230 			scan->dwLinesDiscard = (u_long)scaps->bSensorDistance *
1231 			                       scan->sParam.PhyDpi.y / scaps->OpticDpi.y;
1232 
1233 			switch( scaps->bSensorOrder ) {
1234 
1235 			case SENSORORDER_rgb:
1236 				scan->Red.pb   = scan->pbScanBufBegin;
1237 				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1238 				                 scan->sParam.Size.dwPhyBytes;
1239 				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1240 				                 scan->sParam.Size.dwPhyBytes * 2UL;
1241 				break;
1242 
1243 			case SENSORORDER_rbg:
1244 				scan->Red.pb   = scan->pbScanBufBegin;
1245 				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1246 				                 scan->sParam.Size.dwPhyBytes;
1247 				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1248 				                 scan->sParam.Size.dwPhyBytes * 2UL;
1249 				break;
1250 
1251 			case SENSORORDER_gbr:
1252 				scan->Green.pb = scan->pbScanBufBegin;
1253 				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1254 				                 scan->sParam.Size.dwPhyBytes;
1255 				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1256 				                 scan->sParam.Size.dwPhyBytes * 2UL;
1257 				break;
1258 
1259 			case SENSORORDER_grb:
1260 				scan->Green.pb = scan->pbScanBufBegin;
1261 				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1262 				                 scan->sParam.Size.dwPhyBytes;
1263 				scan->Blue.pb  = scan->pbScanBufBegin + scan->dwLinesDiscard *
1264                                  scan->sParam.Size.dwPhyBytes * 2UL;
1265 				break;
1266 
1267 			case SENSORORDER_brg:
1268 				scan->Blue.pb  = scan->pbScanBufBegin;
1269 				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1270 				                 scan->sParam.Size.dwPhyBytes;
1271 				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1272 				                 scan->sParam.Size.dwPhyBytes * 2UL;
1273 				break;
1274 
1275 			case SENSORORDER_bgr:
1276 				scan->Blue.pb  = scan->pbScanBufBegin;
1277 				scan->Green.pb = scan->pbScanBufBegin + scan->dwLinesDiscard *
1278 				                 scan->sParam.Size.dwPhyBytes;
1279 				scan->Red.pb   = scan->pbScanBufBegin + scan->dwLinesDiscard *
1280 				                 scan->sParam.Size.dwPhyBytes * 2UL;
1281 			}
1282 
1283 			/* double it for last channel */
1284 			scan->dwLinesDiscard <<= 1;
1285 			scan->dwGreenShift = (7UL+scan->sParam.bBitDepth) >> 3;
1286 			scan->Green.pb += scan->dwGreenShift;
1287 			scan->Blue.pb  += (scan->dwGreenShift * 2);
1288 
1289 			if( scan->dwFlag & SCANFLAG_bgr) {
1290 
1291 				u_char *pb = scan->Blue.pb;
1292 
1293 				scan->Blue.pb = scan->Red.pb;
1294 				scan->Red.pb  = pb;
1295 				scan->dwBlueShift = 0;
1296 				scan->dwRedShift  = scan->dwGreenShift << 1;
1297 			} else {
1298 				scan->dwRedShift  = 0;
1299 				scan->dwBlueShift = scan->dwGreenShift << 1;
1300 			}
1301 
1302 		} else {
1303 
1304 			/* CIS section */
1305 
1306 			/* this might be a simple gray operation or AFE 1 channel op */
1307 			scan->dwLinesDiscard = 0;
1308 			scan->Green.pb       = scan->pbScanBufBegin;
1309 
1310 			if(( scan->sParam.bDataType == SCANDATATYPE_Color ) &&
1311 			   ( hw->bReg_0x26 & _ONE_CH_COLOR )) {
1312 
1313 				u_char so;
1314 				u_long len = scan->sParam.Size.dwPhyBytes / 3;
1315 
1316 				so = scaps->bSensorOrder;
1317 				if (_WAF_RESET_SO_TO_RGB & scaps->workaroundFlag) {
1318 					if (scaps->bPCB != 0) {
1319 						if (scan->sParam.PhyDpi.x > scaps->bPCB) {
1320 							so = SENSORORDER_rgb;
1321 							DBG(_DBG_INFO, "* Resetting sensororder to RGB\n");
1322 						}
1323 					}
1324 				}
1325 
1326 				switch( so ) {
1327 
1328 				case SENSORORDER_rgb:
1329 					scan->Red.pb   = scan->pbScanBufBegin;
1330 					scan->Green.pb = scan->pbScanBufBegin + len;
1331 					scan->Blue.pb  = scan->pbScanBufBegin + len * 2UL;
1332 					break;
1333 
1334 				case SENSORORDER_gbr:
1335 					scan->Green.pb = scan->pbScanBufBegin;
1336 					scan->Blue.pb  = scan->pbScanBufBegin + len;
1337 					scan->Red.pb   = scan->pbScanBufBegin + len * 2UL;
1338 					break;
1339 				default:
1340 					DBG( _DBG_ERROR, "CIS: This bSensorOrder "
1341 					                 "is not defined\n" );
1342 					return _E_INTERNAL;
1343 				}
1344 			}
1345 		}
1346 
1347 		/* set a function to process the RAW data... */
1348 		usb_GetImageProc( dev );
1349 
1350 		if( scan->sParam.bSource == SOURCE_ADF )
1351 			scan->dwFlag |= SCANFLAG_StillModule;
1352 
1353 		DBG( _DBG_INFO, "* scan->dwFlag=0x%08lx\n", scan->dwFlag );
1354 
1355 		if( !usb_ScanBegin( dev,
1356 			(scan->dwFlag&SCANFLAG_StillModule) ? SANE_FALSE:SANE_TRUE)) {
1357 
1358 			return _E_INTERNAL;
1359 		}
1360 
1361 		scan->dwFlag |= SCANFLAG_Scanning;
1362 
1363 		if( scan->sParam.UserDpi.y != scan->sParam.PhyDpi.y ) {
1364 
1365 			if( scan->sParam.UserDpi.y < scan->sParam.PhyDpi.y ) {
1366 
1367 				scan->wSumY = scan->sParam.PhyDpi.y - scan->sParam.UserDpi.y;
1368 				scan->dwFlag |= SCANFLAG_SampleY;
1369 				DBG( _DBG_INFO, "SampleY Flag set (%u != %u, wSumY=%u)\n",
1370 				  scan->sParam.UserDpi.y, scan->sParam.PhyDpi.y, scan->wSumY );
1371 			}
1372 		}
1373 	}
1374 
1375 	dumpPicInit( &scan->sParam, "plustek-pic.raw" );
1376 
1377 	/* here the NT driver uses an extra reading thread...
1378 	 * as the SANE stuff already forked the driver to read data, I think
1379 	 * we should only read data by using a function...
1380 	 */
1381 	scan->dwLinesUser = scan->sParam.Size.dwLines;
1382 	if( !scan->dwLinesUser )
1383 		return _E_BUFFER_TOO_SMALL;
1384 
1385 	if( scan->sParam.Size.dwLines < scan->dwLinesUser )
1386 		scan->dwLinesUser = scan->sParam.Size.dwLines;
1387 
1388 	scan->sParam.Size.dwLines -= scan->dwLinesUser;
1389 	if( scan->dwFlag & SCANFLAG_BottomUp )
1390 		scan->UserBuf.pb = buf + (scan->dwLinesUser - 1) * scan->dwBytesLine;
1391 	else
1392 		scan->UserBuf.pb = buf;
1393 
1394 	DBG(_DBG_INFO,"Reading the data now!\n" );
1395 	DBG(_DBG_INFO,"PhyDpi.x         = %u\n", scan->sParam.PhyDpi.x  );
1396 	DBG(_DBG_INFO,"PhyDpi.y         = %u\n", scan->sParam.PhyDpi.y  );
1397 	DBG(_DBG_INFO,"UserDpi.x        = %u\n", scan->sParam.UserDpi.x );
1398 	DBG(_DBG_INFO,"UserDpi.y        = %u\n", scan->sParam.UserDpi.y );
1399 	DBG(_DBG_INFO,"NumberOfScanBufs = %lu\n",scan->dwNumberOfScanBufs);
1400 	DBG(_DBG_INFO,"LinesPerScanBufs = %lu\n",scan->dwLinesPerScanBufs);
1401 	DBG(_DBG_INFO,"dwPhyBytes       = %lu\n",scan->sParam.Size.dwPhyBytes);
1402 	DBG(_DBG_INFO,"dwPhyPixels      = %lu\n",scan->sParam.Size.dwPhyPixels);
1403 	DBG(_DBG_INFO,"dwTotalBytes     = %lu\n",scan->sParam.Size.dwTotalBytes);
1404 	DBG(_DBG_INFO,"dwPixels         = %lu\n",scan->sParam.Size.dwPixels);
1405 	DBG(_DBG_INFO,"dwBytes          = %lu\n",scan->sParam.Size.dwBytes);
1406 	DBG(_DBG_INFO,"dwValidPixels    = %lu\n",scan->sParam.Size.dwValidPixels);
1407 	DBG(_DBG_INFO,"dwBytesScanBuf   = %lu\n",scan->dwBytesScanBuf );
1408 	DBG(_DBG_INFO,"dwLinesDiscard   = %lu\n",scan->dwLinesDiscard );
1409 	DBG(_DBG_INFO,"dwLinesToSkip    = %u\n", scan->bLinesToSkip );
1410 	DBG(_DBG_INFO,"dwLinesUser      = %lu\n",scan->dwLinesUser  );
1411 	DBG(_DBG_INFO,"dwBytesLine      = %lu\n",scan->dwBytesLine  );
1412 
1413 	scan->pbGetDataBuf = scan->pbScanBufBegin;
1414 
1415 	scan->dwLinesToProcess = usb_ReadData( dev  );
1416 	if( 0 == scan->dwLinesToProcess )
1417 		return _E_DATAREAD;
1418 
1419 	return 0;
1420 }
1421 
1422 /** as the name says, read one line...
1423  */
1424 static int
usbDev_ReadLine( Plustek_Device *dev )1425 usbDev_ReadLine( Plustek_Device *dev )
1426 {
1427 	int      wrap;
1428 	u_long   cur;
1429 	ScanDef *scan = &dev->scanning;
1430 	HWDef   *hw   = &dev->usbDev.HwSetting;
1431 
1432 	cur = scan->dwLinesUser;
1433 
1434 	/* we stay within this sample loop until one line has been processed for
1435 	 * the user...
1436 	 */
1437 	while( cur == scan->dwLinesUser ) {
1438 
1439 		if( usb_IsEscPressed()) {
1440 			DBG( _DBG_INFO, "readLine() - Cancel detected...\n" );
1441 			return _E_ABORT;
1442 		}
1443 
1444 		if( !(scan->dwFlag & SCANFLAG_SampleY))	{
1445 
1446 			scan->pfnProcess( dev );
1447 
1448 			/* Adjust user buffer pointer */
1449 			scan->UserBuf.pb += scan->lBufAdjust;
1450 			scan->dwLinesUser--;
1451 
1452 		} else {
1453 
1454 			scan->wSumY += scan->sParam.UserDpi.y;
1455 
1456 			if( scan->wSumY >= scan->sParam.PhyDpi.y ) {
1457 				scan->wSumY -= scan->sParam.PhyDpi.y;
1458 
1459 				scan->pfnProcess( dev );
1460 
1461 				/* Adjust user buffer pointer */
1462 				scan->UserBuf.pb += scan->lBufAdjust;
1463 				scan->dwLinesUser--;
1464 			}
1465 		}
1466 
1467 		/* Adjust get buffer pointers */
1468 		wrap = 0;
1469 
1470 		if( scan->sParam.bDataType == SCANDATATYPE_Color ) {
1471 
1472 			scan->Red.pb += scan->sParam.Size.dwPhyBytes;
1473 			if( scan->Red.pb >= scan->pbScanBufEnd ) {
1474 				scan->Red.pb = scan->pbScanBufBegin + scan->dwRedShift;
1475 				wrap = 1;
1476 			}
1477 
1478 			scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1479 			if( scan->Green.pb >= scan->pbScanBufEnd ) {
1480 				scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1481 				wrap = 1;
1482 			}
1483 
1484 			scan->Blue.pb += scan->sParam.Size.dwPhyBytes;
1485 			if( scan->Blue.pb >= scan->pbScanBufEnd ) {
1486 				scan->Blue.pb = scan->pbScanBufBegin + scan->dwBlueShift;
1487 				wrap = 1;
1488 			}
1489 		} else {
1490 			scan->Green.pb += scan->sParam.Size.dwPhyBytes;
1491 			if( scan->Green.pb >= scan->pbScanBufEnd )
1492 				scan->Green.pb = scan->pbScanBufBegin + scan->dwGreenShift;
1493 		}
1494 
1495 		/* on any wrap-around of the get pointers in one channel mode
1496 		 * we have to reset them
1497 		 */
1498 		if( wrap ) {
1499 
1500 			u_long len = scan->sParam.Size.dwPhyBytes;
1501 
1502 			if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
1503 
1504 				if(scan->sParam.bDataType == SCANDATATYPE_Color) {
1505 					len /= 3;
1506 				}
1507 				scan->Red.pb   = scan->pbScanBufBegin;
1508 				scan->Green.pb = scan->pbScanBufBegin + len;
1509 				scan->Blue.pb  = scan->pbScanBufBegin + len * 2UL;
1510 			}
1511 		}
1512 
1513 		/* line processed, check if we have to get more...
1514 		 */
1515 		scan->dwLinesToProcess--;
1516 
1517 		if( 0 == scan->dwLinesToProcess ) {
1518 
1519 			scan->dwLinesToProcess = usb_ReadData( dev );
1520 			if( 0 == scan->dwLinesToProcess ) {
1521 
1522 				if( usb_IsEscPressed())
1523 					return _E_ABORT;
1524 			}
1525 		}
1526 	}
1527 	return 0;
1528 }
1529 
1530 /* END PLUSTEK-USB.C ........................................................*/
1531