1 /*.............................................................................
2  * Project : SANE library for Plustek flatbed scanners.
3  *.............................................................................
4  */
5 
6 /** @file plustek.c
7  *  @brief SANE backend for Plustek scanner
8  *
9  * Based on Kazuhiro Sasayama previous work on
10  * plustek.[ch] file from the SANE package.<br>
11  * Original code taken from sane-0.71<br>
12  * Copyright (C) 1997 Hypercore Software Design, Ltd.<br>
13  * Also based on the work done by Rick Bronson<br>
14  * Copyright (C) 2000-2007 Gerhard Jaeger <gerhard@gjaeger.de><br>
15  *
16  * History:
17  * - 0.30 - initial version
18  * - 0.31 - no changes
19  * - 0.32 - no changes
20  * - 0.33 - no changes
21  * - 0.34 - moved some definitions and typedefs to plustek.h
22  * - 0.35 - removed Y-correction for 12000P model<br>
23  *        - getting Y-size of scan area from driver
24  * - 0.36 - disabled Dropout, as this does currently not work<br>
25  *        - enabled Halftone selection only for Halftone-mode<br>
26  *        - made the cancel button work by using a child process during read<br>
27  *        - added version code to driver interface<br>
28  *        - cleaned up the code<br>
29  *        - fixed sane compatibility problems<br>
30  *        - added multiple device support<br>
31  *        - 12bit color-depth are now available for scanimage
32  * - 0.37 - removed X/Y autocorrection, now correcting the stuff
33  *          before scanning
34  *        - applied Michaels' patch to solve the sane_get_parameter problem<br>
35  *        - getting X-size of scan area from driver<br>
36  *        - applied Michaels patch for OPT_RESOLUTION (SANE_INFO_INEXACT stuff)
37  * - 0.38 - now using the information from the driver
38  *        - some minor fixes<br>
39  *        - removed dropout stuff<br>
40  *        - removed some warning conditions
41  * - 0.39 - added stuff to use the backend completely in user mode<br>
42  *        - fixed a potential buffer problem<br>
43  *        - removed function attach_one()<br>
44  *        - added USB interface stuff
45  * - 0.40 - USB scanning works now
46  * - 0.41 - added some configuration stuff and also changed .conf file<br>
47  *        - added call to sanei_usb_init() and sanei_lm983x_init()
48  * - 0.42 - added adjustment stuff<br>
49  *        - added custom gamma tables<br>
50  *        - fixed a problem with the "size-sliders"<br>
51  *        - fixed a bug that causes segfault when using the autodetection for
52  *          USB devices<br>
53  *        - added OS/2 switch to disable the USB stuff for OS/2
54  * - 0.43 - added support for PREVIEW flag
55  * - 0.44 - added _DBG_DUMP debug level<br>
56  *        - fixed a bug, that stops our lamp timer
57  * - 0.45 - added additional flags
58  *        - added WIFSIGNALED to check result of child termination
59  *        - changed readImage interface for USB devices
60  *        - homeing of USB scanner is now working correctly
61  * - 0.46 - added plustek-usbcal.c for extra CIS device calibration
62  *          based on Montys' great work
63  *        - added altCalibration option
64  *        - removed parallelport support --> new backend: plustek_pp
65  *        - cleanup
66  *        - added sanei_thread support
67  * - 0.47 - added mov-option (model override)
68  *        - removed drvOpen
69  *        - added call to usb_StartLampTimer, when we're using
70  *          SIGALRM for lamp timer
71  *        - closing now writer pipe, when reader_process is done
72  * - 0.48 - added additional options
73  *          split scanmode and bit-depth
74  * - 0.49 - improved multi-device capability
75  *        - tweaked some device settings
76  *        - added button support
77  *        - moved AFE stuff to enhanced options
78  * - 0.50 - cleanup
79  *        - activated IPC stuff
80  *        - added _DBG_DCALDATA for fine calibration data logging
81  *        - added OPT_SPEEDUP handling
82  *        - fixed constraint_type for OPT_BUTTON
83  * - 0.51 - added fine calibration caching
84  *        - removed #define _PLUSTEK_USB
85  * - 0.52 - added skipDarkStrip and OPT_LOFF4DARK to frontend options
86  *        - fixed batch scanning
87  *.
88  * <hr>
89  * This file is part of the SANE package.
90  *
91  * This program is free software; you can redistribute it and/or
92  * modify it under the terms of the GNU General Public License as
93  * published by the Free Software Foundation; either version 2 of the
94  * License, or (at your option) any later version.
95  *
96  * This program is distributed in the hope that it will be useful, but
97  * WITHOUT ANY WARRANTY; without even the implied warranty of
98  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
99  * General Public License for more details.
100  *
101  * You should have received a copy of the GNU General Public License
102  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
103  *
104  * As a special exception, the authors of SANE give permission for
105  * additional uses of the libraries contained in this release of SANE.
106  *
107  * The exception is that, if you link a SANE library with other files
108  * to produce an executable, this does not by itself cause the
109  * resulting executable to be covered by the GNU General Public
110  * License.  Your use of that executable is in no way restricted on
111  * account of linking the SANE library code into it.
112  *
113  * This exception does not, however, invalidate any other reasons why
114  * the executable file might be covered by the GNU General Public
115  * License.
116  *
117  * If you submit changes to SANE to the maintainers to be included in
118  * a subsequent release, you agree by submitting the changes that
119  * those changes may be distributed with this exception intact.
120  *
121  * If you write modifications of your own for SANE, it is your choice
122  * whether to permit this exception to apply to your modifications.
123  * If you do not wish that, delete this exception notice.
124  * <hr>
125  */
126 
127 /** @mainpage
128  *  @verbinclude Plustek-USB.txt
129  */
130 
131 #ifdef _AIX
132 # include "../include/lalloca.h"
133 #endif
134 
135 #include "../include/sane/config.h"
136 #include "../include/lalloca.h"
137 
138 #include <errno.h>
139 #include <fcntl.h>
140 #include <limits.h>
141 #include <signal.h>
142 #include <stdlib.h>
143 #include <string.h>
144 #include <ctype.h>
145 #include <unistd.h>
146 #include <time.h>
147 #include <math.h>
148 
149 #ifdef HAVE_SYS_TIME_H
150 #include <sys/time.h>
151 #endif
152 
153 #include <sys/types.h>
154 #include <sys/ioctl.h>
155 
156 #include "../include/sane/sane.h"
157 #include "../include/sane/sanei.h"
158 #include "../include/sane/saneopts.h"
159 
160 #define BACKEND_VERSION "0.52-12"
161 
162 #define BACKEND_NAME    plustek
163 #include "../include/sane/sanei_access.h"
164 #include "../include/sane/sanei_backend.h"
165 #include "../include/sane/sanei_config.h"
166 #include "../include/sane/sanei_thread.h"
167 
168 #define USE_IPC
169 
170 #include "plustek-usb.h"
171 #include "plustek.h"
172 
173 /*********************** the debug levels ************************************/
174 
175 #define _DBG_FATAL      0
176 #define _DBG_ERROR      1
177 #define _DBG_WARNING    3
178 #define _DBG_INFO       5
179 #define _DBG_PROC       7
180 #define _DBG_SANE_INIT 10
181 #define _DBG_INFO2     15
182 #define _DBG_DREGS     20
183 #define _DBG_DCALDATA  22
184 #define _DBG_DPIC      25
185 #define _DBG_READ      30
186 
187 /*****************************************************************************/
188 
189 #define _SECTION        "[usb]"
190 #define _DEFAULT_DEVICE "auto"
191 
192 /** to disable the backend... */
193 
194 /* declare it here, as it's used in plustek-usbscan.c too :-( */
195 static SANE_Bool  cancelRead;
196 static DevList   *usbDevs;
197 
198 /* the USB-stuff... I know this is in general no good idea, but it works */
199 #include "plustek-usbio.c"
200 #include "plustek-usbdevs.c"
201 #include "plustek-usbhw.c"
202 #include "plustek-usbmap.c"
203 #include "plustek-usbscan.c"
204 #include "plustek-usbimg.c"
205 #include "plustek-usbcalfile.c"
206 #include "plustek-usbshading.c"
207 #include "plustek-usbcal.c"
208 #include "plustek-usb.c"
209 
210 /************************** global vars **************************************/
211 
212 static int                 num_devices;
213 static Plustek_Device     *first_dev;
214 static Plustek_Scanner    *first_handle;
215 static const SANE_Device **devlist = 0;
216 static unsigned long       tsecs   = 0;
217 static Plustek_Scanner    *sc = NULL;
218 
219 static const SANE_Int bpp_lm9832_list [] = { 2, 8, 14 };
220 static const SANE_Int bpp_lm9833_list [] = { 2, 8, 16 };
221 
222 static const SANE_String_Const mode_list[] =
223 {
224 	SANE_VALUE_SCAN_MODE_LINEART,
225 	SANE_VALUE_SCAN_MODE_GRAY,
226 	SANE_VALUE_SCAN_MODE_COLOR,
227 	NULL
228 };
229 
230 static const SANE_String_Const source_list[] =
231 {
232 	SANE_I18N("Normal"),
233 	SANE_I18N("Transparency"),
234 	SANE_I18N("Negative"),
235 	NULL
236 };
237 
238 static const SANE_Range percentage_range =
239 {
240 	SANE_FIX(-100),         /* minimum      */
241 	SANE_FIX( 100),         /* maximum      */
242 	SANE_FIX(   1)          /* quantization */
243 };
244 
245 static const SANE_Range warmup_range   = { -1,   999, 1 };
246 static const SANE_Range offtimer_range = {  0,   999, 1 };
247 static const SANE_Range gain_range     = { -1,    63, 1 };
248 static const SANE_Range loff_range     = { -1, 16363, 1 };
249 
250 /* authorization stuff */
251 static SANE_Auth_Callback auth = NULL;
252 
253 /* prototype... */
254 static SANE_Status local_sane_start(Plustek_Scanner *, int);
255 
256 /****************************** the backend... *******************************/
257 
258 #define _YN(x) (x?"yes":"no")
259 
260 /** function to display the configuration options for the current device
261  * @param cnf - pointer to the configuration structure whose content should be
262  *              displayed
263  */
show_cnf(CnfDef * cnf)264 static void show_cnf( CnfDef *cnf )
265 {
266 	DBG( _DBG_SANE_INIT,"Device configuration:\n" );
267 	DBG( _DBG_SANE_INIT,"device name  : >%s<\n",cnf->devName                 );
268 	DBG( _DBG_SANE_INIT,"USB-ID       : >%s<\n",cnf->usbId                   );
269 	DBG( _DBG_SANE_INIT,"model ovr.   : %d\n",  cnf->adj.mov                 );
270 	DBG( _DBG_SANE_INIT,"warmup       : %ds\n", cnf->adj.warmup              );
271 	DBG( _DBG_SANE_INIT,"lampOff      : %d\n",  cnf->adj.lampOff             );
272 	DBG( _DBG_SANE_INIT,"lampOffOnEnd : %s\n",  _YN(cnf->adj.lampOffOnEnd   ));
273 	DBG( _DBG_SANE_INIT,"cacheCalData : %s\n",  _YN(cnf->adj.cacheCalData   ));
274 	DBG( _DBG_SANE_INIT,"altCalibrate : %s\n",  _YN(cnf->adj.altCalibrate   ));
275 	DBG( _DBG_SANE_INIT,"skipCalibr.  : %s\n",  _YN(cnf->adj.skipCalibration));
276 	DBG( _DBG_SANE_INIT,"skipFine     : %s\n",  _YN(cnf->adj.skipFine       ));
277 	DBG( _DBG_SANE_INIT,"skipFineWhite: %s\n",  _YN(cnf->adj.skipFineWhite  ));
278 	DBG( _DBG_SANE_INIT,"skipDarkStrip: %s\n",  _YN(cnf->adj.skipDarkStrip   ));
279 	DBG( _DBG_SANE_INIT,"incDarkTarget: %s\n",  _YN(cnf->adj.incDarkTgt      ));
280 	DBG( _DBG_SANE_INIT,"invertNegs.  : %s\n",  _YN(cnf->adj.invertNegatives));
281 	DBG( _DBG_SANE_INIT,"dis.Speedup  : %s\n",  _YN(cnf->adj.disableSpeedup ));
282 	DBG( _DBG_SANE_INIT,"pos_x        : %d\n",  cnf->adj.pos.x               );
283 	DBG( _DBG_SANE_INIT,"pos_y        : %d\n",  cnf->adj.pos.y               );
284 	DBG( _DBG_SANE_INIT,"pos_shading_y: %d\n",  cnf->adj.posShadingY         );
285 	DBG( _DBG_SANE_INIT,"neg_x        : %d\n",  cnf->adj.neg.x               );
286 	DBG( _DBG_SANE_INIT,"neg_y        : %d\n",  cnf->adj.neg.y               );
287 	DBG( _DBG_SANE_INIT,"neg_shading_y: %d\n",  cnf->adj.negShadingY         );
288 	DBG( _DBG_SANE_INIT,"tpa_x        : %d\n",  cnf->adj.tpa.x               );
289 	DBG( _DBG_SANE_INIT,"tpa_y        : %d\n",  cnf->adj.tpa.y               );
290 	DBG( _DBG_SANE_INIT,"tpa_shading_y: %d\n",  cnf->adj.tpaShadingY         );
291 	DBG( _DBG_SANE_INIT,"red gain     : %d\n",  cnf->adj.rgain               );
292 	DBG( _DBG_SANE_INIT,"green gain   : %d\n",  cnf->adj.ggain               );
293 	DBG( _DBG_SANE_INIT,"blue gain    : %d\n",  cnf->adj.bgain               );
294 	DBG( _DBG_SANE_INIT,"red offset   : %d\n",  cnf->adj.rofs                );
295 	DBG( _DBG_SANE_INIT,"green offset : %d\n",  cnf->adj.gofs                );
296 	DBG( _DBG_SANE_INIT,"blue offset  : %d\n",  cnf->adj.bofs                );
297 	DBG( _DBG_SANE_INIT,"red lampoff  : %d\n",  cnf->adj.rlampoff            );
298 	DBG( _DBG_SANE_INIT,"green lampoff: %d\n",  cnf->adj.glampoff            );
299 	DBG( _DBG_SANE_INIT,"blue lampoff : %d\n",  cnf->adj.blampoff            );
300 	DBG( _DBG_SANE_INIT,"red Gamma    : %.2f\n",cnf->adj.rgamma              );
301 	DBG( _DBG_SANE_INIT,"green Gamma  : %.2f\n",cnf->adj.ggamma              );
302 	DBG( _DBG_SANE_INIT,"blue Gamma   : %.2f\n",cnf->adj.bgamma              );
303 	DBG( _DBG_SANE_INIT,"gray Gamma   : %.2f\n",cnf->adj.graygamma           );
304 	DBG( _DBG_SANE_INIT,"---------------------\n" );
305 }
306 
307 /** Calls the device specific stop and close functions.
308  * @param  dev - pointer to the device specific structure
309  * @return The function always returns SANE_STATUS_GOOD
310  */
311 static SANE_Status
drvclose(Plustek_Device * dev)312 drvclose( Plustek_Device *dev )
313 {
314 	if( dev->fd >= 0 ) {
315 
316 		DBG( _DBG_INFO, "drvclose()\n" );
317 
318 		if( 0 != tsecs ) {
319 			DBG( _DBG_INFO, "TIME END 1: %lus\n", time(NULL)-tsecs);
320 		}
321 
322 		/* don't check the return values, simply do it */
323 		usbDev_stopScan( dev );
324 		usbDev_close   ( dev );
325 		sanei_access_unlock( dev->sane.name );
326 	}
327 	dev->fd = -1;
328 
329 	return SANE_STATUS_GOOD;
330 }
331 
332 /** according to the mode and source we return the corresponding scanmode and
333  *  bit-depth per pixel
334  */
335 static int
getScanMode(Plustek_Scanner * scanner)336 getScanMode( Plustek_Scanner *scanner )
337 {
338 	int mode;
339 	int scanmode;
340 
341 	/* are we in TPA-mode? */
342 	mode = scanner->val[OPT_MODE].w;
343 	if( scanner->val[OPT_EXT_MODE].w != 0 )
344 		mode += 2;
345 
346 	scanner->params.depth = scanner->val[OPT_BIT_DEPTH].w;
347 
348 	if( mode == 0 ) {
349 		scanmode = COLOR_BW;
350 		scanner->params.depth = 1;
351 	} else if( scanner->params.depth == 8 ) {
352 
353 		if( mode == 1 )
354 			scanmode = COLOR_256GRAY;
355 		else
356 			scanmode = COLOR_TRUE24;
357 	} else {
358 		scanner->params.depth = 16;
359 		if( mode == 1 )
360 			scanmode = COLOR_GRAY16;
361 		else
362 			scanmode = COLOR_TRUE48;
363 	}
364 	return scanmode;
365 }
366 
367 /** return the len of the largest string in the array
368  */
369 static size_t
max_string_size(const SANE_String_Const strings[])370 max_string_size (const SANE_String_Const strings[])
371 {
372 	size_t size, max_size = 0;
373 	SANE_Int i;
374 
375 	for (i = 0; strings[i]; ++i) {
376 		size = strlen (strings[i]) + 1;
377 		if (size > max_size)
378 			max_size = size;
379 	}
380 	return max_size;
381 }
382 
383 /** shutdown open pipes
384  */
385 static SANE_Status
close_pipe(Plustek_Scanner * scanner)386 close_pipe( Plustek_Scanner *scanner )
387 {
388 	if( scanner->r_pipe >= 0 ) {
389 
390 		DBG( _DBG_PROC, "close_pipe (r_pipe)\n" );
391 		close( scanner->r_pipe );
392 		scanner->r_pipe = -1;
393 	}
394 	if( scanner->w_pipe >= 0 ) {
395 
396 		DBG( _DBG_PROC, "close_pipe (w_pipe)\n" );
397 		close( scanner->w_pipe );
398 		scanner->w_pipe = -1;
399 	}
400 	return SANE_STATUS_EOF;
401 }
402 
403 /** will be called when a child is going down
404  */
405 static void
sig_chldhandler(int signo)406 sig_chldhandler( int signo )
407 {
408 	DBG( _DBG_PROC, "(SIG) Child is down (signal=%d)\n", signo );
409 	if (sc) {
410 		sc->calibrating = SANE_FALSE;
411 		sc = NULL;
412 	}
413 }
414 
415 /** signal handler to kill the child process
416  */
417 static void
reader_process_sigterm_handler(int signo)418 reader_process_sigterm_handler( int signo )
419 {
420 	DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo );
421 	_exit( SANE_STATUS_GOOD );
422 }
423 
424 static void
usb_reader_process_sigterm_handler(int signo)425 usb_reader_process_sigterm_handler( int signo )
426 {
427 	DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo );
428 	cancelRead = SANE_TRUE;
429 }
430 
431 static void
sigalarm_handler(int signo)432 sigalarm_handler( int signo )
433 {
434 	_VAR_NOT_USED( signo );
435 	DBG( _DBG_PROC, "ALARM!!!\n" );
436 }
437 
438 /**
439  */
440 static void
thread_entry(void)441 thread_entry(void)
442 {
443 	struct SIGACTION act;
444 	sigset_t         ignore_set;
445 
446 	sigfillset ( &ignore_set );
447 	sigdelset  ( &ignore_set, SIGTERM );
448 #if defined (__APPLE__) && defined (__MACH__)
449 	sigdelset  ( &ignore_set, SIGUSR2 );
450 #endif
451 	sigprocmask( SIG_SETMASK, &ignore_set, 0 );
452 
453 	memset(&act, 0, sizeof (act));
454 	sigaction( SIGTERM, &act, 0 );
455 
456 	cancelRead = SANE_FALSE;
457 
458 	/* install the signal handler */
459 	sigemptyset(&(act.sa_mask));
460 	act.sa_flags = 0;
461 
462 	act.sa_handler = reader_process_sigterm_handler;
463 	sigaction( SIGTERM, &act, 0 );
464 
465 	act.sa_handler = usb_reader_process_sigterm_handler;
466 	sigaction( SIGUSR1, &act, 0 );
467 }
468 
469 /** executed as a child process
470  * read the data from the driver and send them to the parent process
471  */
472 static int
reader_process(void * args)473 reader_process( void *args )
474 {
475 	int              line, lerrn;
476 	unsigned char   *buf;
477 	unsigned long    status;
478 	unsigned long    data_length;
479 	Plustek_Scanner *scanner = (Plustek_Scanner *)args;
480 	Plustek_Device  *dev = scanner->hw;
481 #ifdef USE_IPC
482 	IPCDef           ipc;
483 #endif
484 
485 	if( sanei_thread_is_forked()) {
486 		DBG( _DBG_PROC, "reader_process started (forked)\n" );
487 		close( scanner->r_pipe );
488 		scanner->r_pipe = -1;
489 	} else {
490 		DBG( _DBG_PROC, "reader_process started (as thread)\n" );
491 	}
492 
493 	thread_entry();
494 
495 	data_length = scanner->params.lines * scanner->params.bytes_per_line;
496 
497 	DBG( _DBG_PROC, "reader_process:"
498 					"starting to READ data (%lu bytes)\n", data_length );
499 	DBG( _DBG_PROC, "buf = 0x%08lx\n", (unsigned long)scanner->buf );
500 
501 	if( NULL == scanner->buf ) {
502 		DBG( _DBG_FATAL, "NULL Pointer !!!!\n" );
503 		return SANE_STATUS_IO_ERROR;
504 	}
505 
506 	/* prepare for scanning: speed-test, warmup, calibration */
507 	buf    = scanner->buf;
508 	status = usbDev_Prepare( scanner->hw, buf );
509 
510 #ifdef USE_IPC
511 	/* prepare IPC structure */
512 	memset(&ipc, 0, sizeof(ipc));
513 	ipc.transferRate = DEFAULT_RATE;
514 
515 	if( dev->transferRate > 0 && dev->transferRate != DEFAULT_RATE )
516 		ipc.transferRate = dev->transferRate;
517 
518 	/* write ipc back to parent in any case... */
519 	write( scanner->w_pipe, &ipc, sizeof(ipc));
520 #endif
521 
522 	/* on success, we read all data from the driver... */
523 	if( 0 == status ) {
524 
525 		if( !usb_InCalibrationMode(dev)) {
526 
527 			DBG( _DBG_INFO, "reader_process: READING....\n" );
528 
529 			for( line = 0; line < scanner->params.lines; line++ ) {
530 
531 				status = usbDev_ReadLine( scanner->hw );
532 				if((int)status < 0 ) {
533 					break;
534 				}
535 				write( scanner->w_pipe, buf, scanner->params.bytes_per_line );
536 				buf += scanner->params.bytes_per_line;
537 			}
538 		}
539 	}
540 	/* on error, there's no need to clean up, as this is done by the parent */
541 	lerrn = errno;
542 
543 	close( scanner->w_pipe );
544 	scanner->w_pipe = -1;
545 
546 	if((int)status < 0 ) {
547 		DBG( _DBG_ERROR,"reader_process: read failed, status = %i, errno %i\n",
548                                                           (int)status, lerrn );
549 		if( _E_ABORT == (int)status )
550 			return SANE_STATUS_CANCELLED;
551 
552 		if( lerrn == EBUSY )
553 			return SANE_STATUS_DEVICE_BUSY;
554 
555 		return SANE_STATUS_IO_ERROR;
556 	}
557 
558 	DBG( _DBG_PROC, "reader_process: finished reading data\n" );
559 	return SANE_STATUS_GOOD;
560 }
561 
562 /** stop the current scan process
563  */
564 static SANE_Status
do_cancel(Plustek_Scanner * scanner,SANE_Bool closepipe)565 do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe )
566 {
567 	struct SIGACTION act;
568 	SANE_Pid         res;
569 
570 	DBG( _DBG_PROC,"do_cancel\n" );
571 	scanner->scanning = SANE_FALSE;
572 
573 	if( sanei_thread_is_valid (scanner->reader_pid) ) {
574 
575                 DBG( _DBG_PROC, "---- killing reader_process ----\n" );
576 
577 		cancelRead = SANE_TRUE;
578 		scanner->calibrating = SANE_FALSE;
579 
580 		sigemptyset(&(act.sa_mask));
581 		act.sa_flags = 0;
582 
583 		act.sa_handler = sigalarm_handler;
584 		sigaction( SIGALRM, &act, 0 );
585 
586 		/* kill our child process and wait until done */
587 		sanei_thread_sendsig( scanner->reader_pid, SIGUSR1 );
588 
589 		/* give'em 10 seconds 'til done...*/
590 		alarm(10);
591 		res = sanei_thread_waitpid( scanner->reader_pid, 0 );
592 		alarm(0);
593 
594 		if( res != scanner->reader_pid ) {
595 			DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
596 
597 			/* do it the hard way...*/
598 #ifdef USE_PTHREAD
599 			sanei_thread_kill( scanner->reader_pid );
600 #else
601 			sanei_thread_sendsig( scanner->reader_pid, SIGKILL );
602 #endif
603 		}
604 
605 		sanei_thread_invalidate( scanner->reader_pid );
606 		DBG( _DBG_PROC,"reader_process killed\n");
607 #ifndef HAVE_SETITIMER
608 		usb_StartLampTimer( scanner->hw );
609 #endif
610 	}
611 	scanner->calibrating = SANE_FALSE;
612 
613 	if( SANE_TRUE == closepipe ) {
614 		close_pipe( scanner );
615 	}
616 
617 	drvclose( scanner->hw );
618 
619 	if( tsecs != 0 ) {
620 		DBG( _DBG_INFO, "TIME END 2: %lus\n", time(NULL)-tsecs);
621 		tsecs = 0;
622 	}
623 
624 	return SANE_STATUS_CANCELLED;
625 }
626 
627 /** As we support only LM9831/2/3 chips we use the same
628  * sizes for each device...
629  * @param  s - pointer to the scanner specific structure
630  * @return The function always returns SANE_STATUS_GOOD
631  */
632 static SANE_Status
initGammaSettings(Plustek_Scanner * s)633 initGammaSettings( Plustek_Scanner *s )
634 {
635 	int    i, j, val;
636 	double gamma;
637 
638 	s->gamma_length      = 4096;
639 	s->gamma_range.min   = 0;
640 	s->gamma_range.max   = 255;
641 	s->gamma_range.quant = 0;
642 
643 	DBG( _DBG_INFO, "Presetting Gamma tables (len=%u)\n", s->gamma_length );
644 
645 	/* preset the gamma maps
646 	 */
647 	for( i = 0; i < 4; i++ ) {
648 
649 		switch( i ) {
650 			case 1:  gamma = s->hw->adj.rgamma;    break;
651 			case 2:  gamma = s->hw->adj.ggamma;    break;
652 			case 3:  gamma = s->hw->adj.bgamma;    break;
653 			default: gamma = s->hw->adj.graygamma; break;
654 		}
655 		DBG( _DBG_INFO, "* Channel[%u], gamma %.3f\n", i, gamma );
656 
657 		for( j = 0; j < s->gamma_length; j++ ) {
658 
659 			val = (s->gamma_range.max *
660 			       pow((double)j / (double)(s->gamma_length-1.0),
661 			       1.0 / gamma ));
662 
663 			if( val > s->gamma_range.max )
664 				val = s->gamma_range.max;
665 
666 			s->gamma_table[i][j] = val;
667 		}
668 	}
669 	DBG( _DBG_INFO, "----------------------------------\n" );
670 	return SANE_STATUS_GOOD;
671 }
672 
673 /** Check the gamma vectors we got back and limit if necessary
674  * @param  s - pointer to the scanner specific structure
675  * @return nothing
676  */
677 static void
checkGammaSettings(Plustek_Scanner * s)678 checkGammaSettings( Plustek_Scanner *s )
679 {
680 	int i, j;
681 
682 	DBG( _DBG_INFO, "Maps changed...\n" );
683 	for( i = 0; i < 4 ; i++ ) {
684 		for( j = 0; j < s->gamma_length; j++ ) {
685 			if( s->gamma_table[i][j] > s->gamma_range.max ) {
686 				s->gamma_table[i][j] = s->gamma_range.max;
687 			}
688 		}
689 	}
690 }
691 
692 /** initialize the options for the backend according to the device we have
693  */
694 static SANE_Status
init_options(Plustek_Scanner * s)695 init_options( Plustek_Scanner *s )
696 {
697 	int i;
698 	Plustek_Device *dev  = s->hw;
699 	AdjDef         *adj  = &dev->adj;
700 	DCapsDef       *caps = &dev->usbDev.Caps;
701 
702 	memset(s->opt, 0, sizeof(s->opt));
703 
704 	for( i = 0; i < NUM_OPTIONS; ++i ) {
705 		s->opt[i].size = sizeof (SANE_Word);
706 		s->opt[i].cap  = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
707 		s->opt[i].unit = SANE_UNIT_NONE;
708 	}
709 
710 	s->opt[OPT_NUM_OPTS].name  = SANE_NAME_NUM_OPTIONS;
711 	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
712 	s->opt[OPT_NUM_OPTS].desc  = SANE_DESC_NUM_OPTIONS;
713 	s->opt[OPT_NUM_OPTS].type  = SANE_TYPE_INT;
714 	s->opt[OPT_NUM_OPTS].cap   = SANE_CAP_SOFT_DETECT;
715 	s->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
716 	s->val[OPT_NUM_OPTS].w     = NUM_OPTIONS;
717 
718 	/* "Scan Mode" group: */
719 	s->opt[OPT_MODE_GROUP].title = SANE_I18N("Scan Mode");
720 	s->opt[OPT_MODE_GROUP].desc  = "";
721 	s->opt[OPT_MODE_GROUP].type  = SANE_TYPE_GROUP;
722 	s->opt[OPT_MODE_GROUP].cap   = 0;
723 
724 	/* scan mode */
725 	s->opt[OPT_MODE].name  = SANE_NAME_SCAN_MODE;
726 	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
727 	s->opt[OPT_MODE].desc  = SANE_DESC_SCAN_MODE;
728 	s->opt[OPT_MODE].type  = SANE_TYPE_STRING;
729 	s->opt[OPT_MODE].size  = max_string_size(mode_list);
730 	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
731 	s->opt[OPT_MODE].constraint.string_list = mode_list;
732 	s->val[OPT_MODE].w = 2; /* Color */
733 
734 	/* bit depth */
735 	s->opt[OPT_BIT_DEPTH].name  = SANE_NAME_BIT_DEPTH;
736 	s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH;
737 	s->opt[OPT_BIT_DEPTH].desc  = SANE_DESC_BIT_DEPTH;
738 	s->opt[OPT_BIT_DEPTH].type  = SANE_TYPE_INT;
739 	s->opt[OPT_BIT_DEPTH].unit  = SANE_UNIT_BIT;
740 	s->opt[OPT_BIT_DEPTH].size  = sizeof (SANE_Word);
741 	s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
742 	if( _LM9833 == dev->usbDev.HwSetting.chip )
743 		s->opt[OPT_BIT_DEPTH].constraint.word_list = bpp_lm9833_list;
744 	else
745 		s->opt[OPT_BIT_DEPTH].constraint.word_list = bpp_lm9832_list;
746 	s->val[OPT_BIT_DEPTH].w = 8;
747 
748 	if (caps->workaroundFlag & _WAF_ONLY_8BIT)
749 		_DISABLE(OPT_BIT_DEPTH);
750 
751 	/* scan source */
752 	s->opt[OPT_EXT_MODE].name  = SANE_NAME_SCAN_SOURCE;
753 	s->opt[OPT_EXT_MODE].title = SANE_TITLE_SCAN_SOURCE;
754 	s->opt[OPT_EXT_MODE].desc  = SANE_DESC_SCAN_SOURCE;
755 	s->opt[OPT_EXT_MODE].type  = SANE_TYPE_STRING;
756 	s->opt[OPT_EXT_MODE].size  = max_string_size(source_list);
757 	s->opt[OPT_EXT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
758 	s->opt[OPT_EXT_MODE].constraint.string_list = source_list;
759 	s->val[OPT_EXT_MODE].w     = 0; /* Normal */
760 
761 	/* brightness */
762 	s->opt[OPT_BRIGHTNESS].name  = SANE_NAME_BRIGHTNESS;
763 	s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
764 	s->opt[OPT_BRIGHTNESS].desc  = SANE_DESC_BRIGHTNESS;
765 	s->opt[OPT_BRIGHTNESS].type  = SANE_TYPE_FIXED;
766 	s->opt[OPT_BRIGHTNESS].unit  = SANE_UNIT_PERCENT;
767 	s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
768 	s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
769 	s->val[OPT_BRIGHTNESS].w     = 0;
770 
771 	/* contrast */
772 	s->opt[OPT_CONTRAST].name  = SANE_NAME_CONTRAST;
773 	s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
774 	s->opt[OPT_CONTRAST].desc  = SANE_DESC_CONTRAST;
775 	s->opt[OPT_CONTRAST].type  = SANE_TYPE_FIXED;
776 	s->opt[OPT_CONTRAST].unit  = SANE_UNIT_PERCENT;
777 	s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
778 	s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
779 	s->val[OPT_CONTRAST].w     = 0;
780 
781 	/* resolution */
782 	s->opt[OPT_RESOLUTION].name  = SANE_NAME_SCAN_RESOLUTION;
783 	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
784 	s->opt[OPT_RESOLUTION].desc  = SANE_DESC_SCAN_RESOLUTION;
785 	s->opt[OPT_RESOLUTION].type  = SANE_TYPE_INT;
786 	s->opt[OPT_RESOLUTION].unit  = SANE_UNIT_DPI;
787 	s->opt[OPT_RESOLUTION].constraint_type  = SANE_CONSTRAINT_RANGE;
788 	s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
789 	s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
790 
791 	/* custom-gamma table */
792 	s->opt[OPT_CUSTOM_GAMMA].name  = SANE_NAME_CUSTOM_GAMMA;
793 	s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
794 	s->opt[OPT_CUSTOM_GAMMA].desc  = SANE_DESC_CUSTOM_GAMMA;
795 	s->opt[OPT_CUSTOM_GAMMA].type  = SANE_TYPE_BOOL;
796 	s->val[OPT_CUSTOM_GAMMA].w     = SANE_FALSE;
797 
798 	/* preview */
799 	s->opt[OPT_PREVIEW].name  = SANE_NAME_PREVIEW;
800 	s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
801 	s->opt[OPT_PREVIEW].desc  = SANE_DESC_PREVIEW;
802 	s->opt[OPT_PREVIEW].cap   = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
803 	s->val[OPT_PREVIEW].w     = 0;
804 
805 	/* "Geometry" group: */
806 	s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N("Geometry");
807 	s->opt[OPT_GEOMETRY_GROUP].desc  = "";
808 	s->opt[OPT_GEOMETRY_GROUP].type  = SANE_TYPE_GROUP;
809 	s->opt[OPT_GEOMETRY_GROUP].cap   = SANE_CAP_ADVANCED;
810 
811 	/* top-left x */
812 	s->opt[OPT_TL_X].name  = SANE_NAME_SCAN_TL_X;
813 	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
814 	s->opt[OPT_TL_X].desc  = SANE_DESC_SCAN_TL_X;
815 	s->opt[OPT_TL_X].type  = SANE_TYPE_FIXED;
816 	s->opt[OPT_TL_X].unit  = SANE_UNIT_MM;
817 	s->opt[OPT_TL_X].constraint_type  = SANE_CONSTRAINT_RANGE;
818 	s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
819 	s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
820 
821 	/* top-left y */
822 	s->opt[OPT_TL_Y].name  = SANE_NAME_SCAN_TL_Y;
823 	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
824 	s->opt[OPT_TL_Y].desc  = SANE_DESC_SCAN_TL_Y;
825 	s->opt[OPT_TL_Y].type  = SANE_TYPE_FIXED;
826 	s->opt[OPT_TL_Y].unit  = SANE_UNIT_MM;
827 	s->opt[OPT_TL_Y].constraint_type  = SANE_CONSTRAINT_RANGE;
828 	s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
829 	s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
830 
831 	/* bottom-right x */
832 	s->opt[OPT_BR_X].name  = SANE_NAME_SCAN_BR_X;
833 	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
834 	s->opt[OPT_BR_X].desc  = SANE_DESC_SCAN_BR_X;
835 	s->opt[OPT_BR_X].type  = SANE_TYPE_FIXED;
836 	s->opt[OPT_BR_X].unit  = SANE_UNIT_MM;
837 	s->opt[OPT_BR_X].constraint_type  = SANE_CONSTRAINT_RANGE;
838 	s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
839 	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
840 
841 	/* bottom-right y */
842 	s->opt[OPT_BR_Y].name  = SANE_NAME_SCAN_BR_Y;
843 	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
844 	s->opt[OPT_BR_Y].desc  = SANE_DESC_SCAN_BR_Y;
845 	s->opt[OPT_BR_Y].type  = SANE_TYPE_FIXED;
846 	s->opt[OPT_BR_Y].unit  = SANE_UNIT_MM;
847 	s->opt[OPT_BR_Y].constraint_type  = SANE_CONSTRAINT_RANGE;
848 	s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
849 	s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
850 
851 	/* "Enhancement" group: */
852 	s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement");
853 	s->opt[OPT_ENHANCEMENT_GROUP].desc  = "";
854 	s->opt[OPT_ENHANCEMENT_GROUP].type  = SANE_TYPE_GROUP;
855 	s->opt[OPT_ENHANCEMENT_GROUP].cap   = 0;
856 	s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
857 
858 	initGammaSettings( s );
859 
860 	/* grayscale gamma vector */
861 	s->opt[OPT_GAMMA_VECTOR].name  = SANE_NAME_GAMMA_VECTOR;
862 	s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
863 	s->opt[OPT_GAMMA_VECTOR].desc  = SANE_DESC_GAMMA_VECTOR;
864 	s->opt[OPT_GAMMA_VECTOR].type  = SANE_TYPE_INT;
865 	s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
866 	s->val[OPT_GAMMA_VECTOR].wa   = &(s->gamma_table[0][0]);
867 	s->opt[OPT_GAMMA_VECTOR].constraint.range = &(s->gamma_range);
868 	s->opt[OPT_GAMMA_VECTOR].size = s->gamma_length * sizeof(SANE_Word);
869 
870 	/* red gamma vector */
871 	s->opt[OPT_GAMMA_VECTOR_R].name  = SANE_NAME_GAMMA_VECTOR_R;
872 	s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
873 	s->opt[OPT_GAMMA_VECTOR_R].desc  = SANE_DESC_GAMMA_VECTOR_R;
874 	s->opt[OPT_GAMMA_VECTOR_R].type  = SANE_TYPE_INT;
875 	s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
876 	s->val[OPT_GAMMA_VECTOR_R].wa   = &(s->gamma_table[1][0]);
877 	s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(s->gamma_range);
878 	s->opt[OPT_GAMMA_VECTOR_R].size = s->gamma_length * sizeof(SANE_Word);
879 
880 	/* green gamma vector */
881 	s->opt[OPT_GAMMA_VECTOR_G].name  = SANE_NAME_GAMMA_VECTOR_G;
882 	s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
883 	s->opt[OPT_GAMMA_VECTOR_G].desc  = SANE_DESC_GAMMA_VECTOR_G;
884 	s->opt[OPT_GAMMA_VECTOR_G].type  = SANE_TYPE_INT;
885 	s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
886 	s->val[OPT_GAMMA_VECTOR_G].wa   = &(s->gamma_table[2][0]);
887 	s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(s->gamma_range);
888 	s->opt[OPT_GAMMA_VECTOR_G].size = s->gamma_length * sizeof(SANE_Word);
889 
890 	/* blue gamma vector */
891 	s->opt[OPT_GAMMA_VECTOR_B].name  = SANE_NAME_GAMMA_VECTOR_B;
892 	s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
893 	s->opt[OPT_GAMMA_VECTOR_B].desc  = SANE_DESC_GAMMA_VECTOR_B;
894 	s->opt[OPT_GAMMA_VECTOR_B].type  = SANE_TYPE_INT;
895 	s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
896 	s->val[OPT_GAMMA_VECTOR_B].wa   = &(s->gamma_table[3][0]);
897 	s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range);
898 	s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof(SANE_Word);
899 
900 	/* GAMMA stuff is disabled per default */
901 	_DISABLE(OPT_GAMMA_VECTOR);
902 	_DISABLE(OPT_GAMMA_VECTOR_R);
903 	_DISABLE(OPT_GAMMA_VECTOR_G);
904 	_DISABLE(OPT_GAMMA_VECTOR_B);
905 
906 	/* disable extended mode list for devices without TPA */
907 	if( 0 == (s->hw->caps.dwFlag & SFLAG_TPA))
908 		_DISABLE(OPT_EXT_MODE);
909 
910 	/* "Device settings" group: */
911 	s->opt[OPT_DEVICE_GROUP].title = SANE_I18N("Device-Settings");
912 	s->opt[OPT_DEVICE_GROUP].desc  = "";
913 	s->opt[OPT_DEVICE_GROUP].type  = SANE_TYPE_GROUP;
914 	s->opt[OPT_DEVICE_GROUP].cap   = 0;
915 	s->opt[OPT_DEVICE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
916 
917 	s->opt[OPT_LAMPSWITCH].name  = "lamp-switch";
918 	s->opt[OPT_LAMPSWITCH].title = SANE_I18N("Lampswitch");;
919 	s->opt[OPT_LAMPSWITCH].desc  = SANE_I18N("Manually switching the lamp(s).");
920 	s->opt[OPT_LAMPSWITCH].type  = SANE_TYPE_BOOL;
921 	s->val[OPT_LAMPSWITCH].w     = SANE_FALSE;
922 
923 	s->opt[OPT_LOFF4DARK].name  = "lamp-off-during-dcal";
924 	s->opt[OPT_LOFF4DARK].title = SANE_I18N("Lamp off during dark calibration");;
925 	s->opt[OPT_LOFF4DARK].desc  = SANE_I18N("Always switches lamp off when doing dark calibration.");
926 	s->opt[OPT_LOFF4DARK].type  = SANE_TYPE_BOOL;
927 	s->val[OPT_LOFF4DARK].w     = adj->skipDarkStrip;
928 
929 	if (dev->usbDev.Caps.Normal.DarkShadOrgY < 0)
930 		_DISABLE(OPT_LOFF4DARK);
931 
932 	s->opt[OPT_CACHECAL].name  = "calibration-cache";
933 	s->opt[OPT_CACHECAL].title = SANE_I18N("Calibration data cache");;
934 	s->opt[OPT_CACHECAL].desc  = SANE_I18N("Enables or disables calibration data cache.");
935 	s->opt[OPT_CACHECAL].type  = SANE_TYPE_BOOL;
936 	s->val[OPT_CACHECAL].w     = adj->cacheCalData;
937 
938 	s->opt[OPT_CALIBRATE].name  = "calibrate";
939 	s->opt[OPT_CALIBRATE].title = SANE_I18N("Calibrate");;
940 	s->opt[OPT_CALIBRATE].desc  = SANE_I18N("Performs calibration");
941 	s->opt[OPT_CALIBRATE].type  = SANE_TYPE_BUTTON;
942 	s->opt[OPT_CALIBRATE].size = sizeof (SANE_Word);
943 	s->opt[OPT_CALIBRATE].constraint_type = SANE_CONSTRAINT_NONE;
944 	s->opt[OPT_CALIBRATE].constraint.range = 0;
945 	s->opt[OPT_CALIBRATE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT |
946 	                            SANE_CAP_AUTOMATIC;
947 	_ENABLE(OPT_CALIBRATE);
948 	if( !adj->cacheCalData )
949 		_DISABLE(OPT_CALIBRATE);
950 	s->val[OPT_CALIBRATE].w = 0;
951 
952 	/* it's currently not available for CCD devices */
953 	if( !usb_IsCISDevice(dev) && !dev->adj.altCalibrate)
954 		_DISABLE(OPT_CALIBRATE);
955 
956 	s->opt[OPT_SPEEDUP].name  = "speedup-switch";
957 	s->opt[OPT_SPEEDUP].title = SANE_I18N("Speedup sensor");;
958 	s->opt[OPT_SPEEDUP].desc  = SANE_I18N("Enables or disables speeding up sensor movement.");
959 	s->opt[OPT_SPEEDUP].type  = SANE_TYPE_BOOL;
960 	s->val[OPT_SPEEDUP].w     = !(adj->disableSpeedup);
961 
962 	if( s->hw->usbDev.HwSetting.dHighSpeed == 0.0 )
963 		_DISABLE(OPT_SPEEDUP);
964 
965 	s->opt[OPT_LAMPOFF_ONEND].name  = SANE_NAME_LAMP_OFF_AT_EXIT;
966 	s->opt[OPT_LAMPOFF_ONEND].title = SANE_TITLE_LAMP_OFF_AT_EXIT;
967 	s->opt[OPT_LAMPOFF_ONEND].desc  = SANE_DESC_LAMP_OFF_AT_EXIT;
968 	s->opt[OPT_LAMPOFF_ONEND].type  = SANE_TYPE_BOOL;
969 	s->val[OPT_LAMPOFF_ONEND].w     = adj->lampOffOnEnd;
970 
971 	s->opt[OPT_WARMUPTIME].name  = "warmup-time";
972 	s->opt[OPT_WARMUPTIME].title = SANE_I18N("Warmup-time");;
973 	s->opt[OPT_WARMUPTIME].desc  = SANE_I18N("Warmup-time in seconds.");
974 	s->opt[OPT_WARMUPTIME].type  = SANE_TYPE_INT;
975 	s->opt[OPT_WARMUPTIME].constraint_type = SANE_CONSTRAINT_RANGE;
976 	s->opt[OPT_WARMUPTIME].constraint.range = &warmup_range;
977 	s->val[OPT_WARMUPTIME].w     = adj->warmup;
978 	/* only available for CCD devices*/
979 	if( usb_IsCISDevice( dev )) {
980 		_DISABLE(OPT_WARMUPTIME);
981 		s->val[OPT_WARMUPTIME].w = 0;
982 	}
983 
984 	s->opt[OPT_LAMPOFF_TIMER].name  = "lampoff-time";
985 	s->opt[OPT_LAMPOFF_TIMER].title = SANE_I18N("Lampoff-time");;
986 	s->opt[OPT_LAMPOFF_TIMER].desc  = SANE_I18N("Lampoff-time in seconds.");
987 	s->opt[OPT_LAMPOFF_TIMER].type  = SANE_TYPE_INT;
988 	s->opt[OPT_LAMPOFF_TIMER].constraint_type = SANE_CONSTRAINT_RANGE;
989 	s->opt[OPT_LAMPOFF_TIMER].constraint.range = &offtimer_range;
990 	s->val[OPT_LAMPOFF_TIMER].w     = adj->lampOff;
991 
992 	/* "Analog Frontend" group*/
993 	s->opt[OPT_AFE_GROUP].title = SANE_I18N("Analog frontend");
994 	s->opt[OPT_AFE_GROUP].desc  = "";
995 	s->opt[OPT_AFE_GROUP].type  = SANE_TYPE_GROUP;
996 	s->opt[OPT_AFE_GROUP].cap   = SANE_CAP_ADVANCED;
997 
998 	s->opt[OPT_OVR_REDGAIN].name  = "red-gain";
999 	s->opt[OPT_OVR_REDGAIN].title = SANE_I18N("Red gain");
1000 	s->opt[OPT_OVR_REDGAIN].desc  = SANE_I18N("Red gain value of the AFE");
1001 	s->opt[OPT_OVR_REDGAIN].type  = SANE_TYPE_INT;
1002 	s->opt[OPT_OVR_REDGAIN].constraint_type = SANE_CONSTRAINT_RANGE;
1003 	s->opt[OPT_OVR_REDGAIN].constraint.range = &gain_range;
1004 	s->val[OPT_OVR_REDGAIN].w     = adj->rgain;
1005 
1006 	s->opt[OPT_OVR_REDOFS].name  = "red-offset";
1007 	s->opt[OPT_OVR_REDOFS].title = SANE_I18N("Red offset");
1008 	s->opt[OPT_OVR_REDOFS].desc  = SANE_I18N("Red offset value of the AFE");
1009 	s->opt[OPT_OVR_REDOFS].type  = SANE_TYPE_INT;
1010 	s->opt[OPT_OVR_REDOFS].constraint_type = SANE_CONSTRAINT_RANGE;
1011 	s->opt[OPT_OVR_REDOFS].constraint.range = &gain_range;
1012 	s->val[OPT_OVR_REDOFS].w     = adj->rofs;
1013 
1014 	s->opt[OPT_OVR_GREENGAIN].name  = "green-gain";
1015 	s->opt[OPT_OVR_GREENGAIN].title = SANE_I18N("Green gain");
1016 	s->opt[OPT_OVR_GREENGAIN].desc  = SANE_I18N("Green gain value of the AFE");
1017 	s->opt[OPT_OVR_GREENGAIN].type  = SANE_TYPE_INT;
1018 	s->opt[OPT_OVR_GREENGAIN].constraint_type = SANE_CONSTRAINT_RANGE;
1019 	s->opt[OPT_OVR_GREENGAIN].constraint.range = &gain_range;
1020 	s->val[OPT_OVR_GREENGAIN].w     = adj->ggain;
1021 
1022 	s->opt[OPT_OVR_GREENOFS].name  = "green-offset";
1023 	s->opt[OPT_OVR_GREENOFS].title = SANE_I18N("Green offset");
1024 	s->opt[OPT_OVR_GREENOFS].desc  = SANE_I18N("Green offset value of the AFE");
1025 	s->opt[OPT_OVR_GREENOFS].type  = SANE_TYPE_INT;
1026 	s->opt[OPT_OVR_GREENOFS].constraint_type = SANE_CONSTRAINT_RANGE;
1027 	s->opt[OPT_OVR_GREENOFS].constraint.range = &gain_range;
1028 	s->val[OPT_OVR_GREENOFS].w     = adj->gofs;
1029 
1030 	s->opt[OPT_OVR_BLUEGAIN].name  = "blue-gain";
1031 	s->opt[OPT_OVR_BLUEGAIN].title = SANE_I18N("Blue gain");
1032 	s->opt[OPT_OVR_BLUEGAIN].desc  = SANE_I18N("Blue gain value of the AFE");
1033 	s->opt[OPT_OVR_BLUEGAIN].type  = SANE_TYPE_INT;
1034 	s->opt[OPT_OVR_BLUEGAIN].constraint_type = SANE_CONSTRAINT_RANGE;
1035 	s->opt[OPT_OVR_BLUEGAIN].constraint.range = &gain_range;
1036 	s->val[OPT_OVR_BLUEGAIN].w     = adj->bgain;
1037 
1038 	s->opt[OPT_OVR_BLUEOFS].name  = "blue-offset";
1039 	s->opt[OPT_OVR_BLUEOFS].title = SANE_I18N("Blue offset");
1040 	s->opt[OPT_OVR_BLUEOFS].desc  = SANE_I18N("Blue offset value of the AFE");
1041 	s->opt[OPT_OVR_BLUEOFS].type  = SANE_TYPE_INT;
1042 	s->opt[OPT_OVR_BLUEOFS].constraint_type = SANE_CONSTRAINT_RANGE;
1043 	s->opt[OPT_OVR_BLUEOFS].constraint.range = &gain_range;
1044 	s->val[OPT_OVR_BLUEOFS].w     = adj->bofs;
1045 
1046 	s->opt[OPT_OVR_RED_LOFF].name  = "redlamp-off";
1047 	s->opt[OPT_OVR_RED_LOFF].title = SANE_I18N("Red lamp off");
1048 	s->opt[OPT_OVR_RED_LOFF].desc  = SANE_I18N("Defines red lamp off parameter");
1049 	s->opt[OPT_OVR_RED_LOFF].type  = SANE_TYPE_INT;
1050 	s->opt[OPT_OVR_RED_LOFF].constraint_type = SANE_CONSTRAINT_RANGE;
1051 	s->opt[OPT_OVR_RED_LOFF].constraint.range = &loff_range;
1052 	s->val[OPT_OVR_RED_LOFF].w     = adj->rlampoff;
1053 
1054 	s->opt[OPT_OVR_GREEN_LOFF].name  = "greenlamp-off";
1055 	s->opt[OPT_OVR_GREEN_LOFF].title = SANE_I18N("Green lamp off");
1056 	s->opt[OPT_OVR_GREEN_LOFF].desc  = SANE_I18N("Defines green lamp off parameter");
1057 	s->opt[OPT_OVR_GREEN_LOFF].type  = SANE_TYPE_INT;
1058 	s->opt[OPT_OVR_GREEN_LOFF].constraint_type = SANE_CONSTRAINT_RANGE;
1059 	s->opt[OPT_OVR_GREEN_LOFF].constraint.range = &loff_range;
1060 	s->val[OPT_OVR_GREEN_LOFF].w     = adj->glampoff;
1061 
1062 	s->opt[OPT_OVR_BLUE_LOFF].name  = "bluelamp-off";
1063 	s->opt[OPT_OVR_BLUE_LOFF].title = SANE_I18N("Blue lamp off");
1064 	s->opt[OPT_OVR_BLUE_LOFF].desc  = SANE_I18N("Defines blue lamp off parameter");
1065 	s->opt[OPT_OVR_BLUE_LOFF].type  = SANE_TYPE_INT;
1066 	s->opt[OPT_OVR_BLUE_LOFF].constraint_type = SANE_CONSTRAINT_RANGE;
1067 	s->opt[OPT_OVR_BLUE_LOFF].constraint.range = &loff_range;
1068 	s->val[OPT_OVR_BLUE_LOFF].w     = adj->blampoff;
1069 
1070 	/* only available for CIS devices*/
1071 	if( !usb_IsCISDevice( dev )) {
1072 		_DISABLE(OPT_OVR_RED_LOFF);
1073 		_DISABLE(OPT_OVR_GREEN_LOFF);
1074 		_DISABLE(OPT_OVR_BLUE_LOFF);
1075 	}
1076 
1077 	/* "Button" group*/
1078 	s->opt[OPT_BUTTON_GROUP].title = SANE_I18N("Buttons");
1079 	s->opt[OPT_BUTTON_GROUP].desc  = "";
1080 	s->opt[OPT_BUTTON_GROUP].type  = SANE_TYPE_GROUP;
1081 	s->opt[OPT_BUTTON_GROUP].cap   = SANE_CAP_ADVANCED;
1082 
1083 	/* scanner buttons */
1084 	for( i = OPT_BUTTON_0; i <= OPT_BUTTON_LAST; i++ ) {
1085 
1086 		char buf [128];
1087 
1088 		snprintf (buf, sizeof(buf), "button %d", i - OPT_BUTTON_0);
1089 		s->opt[i].name  = strdup(buf);
1090 
1091 		snprintf (buf, sizeof(buf), "Scanner button %d", i - OPT_BUTTON_0);
1092 		s->opt[i].title = strdup(buf);
1093 
1094 		s->opt[i].desc  = SANE_I18N("This option reflects the status "
1095 		                            "of the scanner buttons.");
1096 		s->opt[i].type = SANE_TYPE_BOOL;
1097 		s->opt[i].cap  = SANE_CAP_SOFT_DETECT |
1098 		                 SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED;
1099 		if (i - OPT_BUTTON_0 >= dev->usbDev.Caps.bButtons )
1100 			_DISABLE(i);
1101 
1102 		s->opt[i].unit = SANE_UNIT_NONE;
1103 		s->opt[i].size = sizeof (SANE_Word);
1104 		s->opt[i].constraint_type = SANE_CONSTRAINT_NONE;
1105 		s->opt[i].constraint.range = 0;
1106 		s->val[i].w = SANE_FALSE;
1107 	}
1108 
1109 	usb_UpdateButtonStatus( s );
1110 	return SANE_STATUS_GOOD;
1111 }
1112 
1113 /** Function to retrieve the vendor and product id from a given string
1114  * @param src  - string, that should be investigated
1115  * @param dest - pointer to a string to receive the USB ID
1116  */
1117 static void
decodeUsbIDs(char * src,char ** dest)1118 decodeUsbIDs( char *src, char **dest )
1119 {
1120 	const char *name;
1121 	char       *tmp = *dest;
1122 	int         len = strlen(_SECTION);
1123 
1124 	if( isspace(src[len])) {
1125 		strncpy( tmp, &src[len+1], (strlen(src)-(len+1)));
1126         tmp[(strlen(src)-(len+1))] = '\0';
1127 	}
1128 
1129 	name = tmp;
1130 	name = sanei_config_skip_whitespace( name );
1131 
1132 	if( '\0' == name[0] ) {
1133 		DBG( _DBG_SANE_INIT, "next device uses autodetection\n" );
1134 	} else {
1135 
1136 		u_short pi = 0, vi = 0;
1137 
1138 		if( *name ) {
1139 
1140 			name = sanei_config_get_string( name, &tmp );
1141 			if( tmp ) {
1142 		    	vi = strtol( tmp, 0, 0 );
1143 			    free( tmp );
1144 			}
1145 	    }
1146 
1147 		name = sanei_config_skip_whitespace( name );
1148 		if( *name ) {
1149 
1150 			name = sanei_config_get_string( name, &tmp );
1151 			if( tmp ) {
1152 				pi = strtol( tmp, 0, 0 );
1153 				free( tmp );
1154 			}
1155 		}
1156 
1157 		/* create what we need to go through our device list...*/
1158 		sprintf( *dest, "0x%04X-0x%04X", vi, pi );
1159 		DBG( _DBG_SANE_INIT, "next device is a USB device (%s)\n", *dest );
1160 	}
1161 }
1162 
1163 #define _INT   0
1164 #define _FLOAT 1
1165 
1166 /** function to decode an value and give it back to the caller.
1167  * @param src    -  pointer to the source string to check
1168  * @param opt    -  string that keeps the option name to check src for
1169  * @param what   - _FLOAT or _INT
1170  * @param result -  pointer to the var that should receive our result
1171  * @param def    - default value that result should be in case of any error
1172  * @return The function returns SANE_TRUE if the option has been found,
1173  *         if not, it returns SANE_FALSE
1174  */
1175 static SANE_Bool
decodeVal(char * src,char * opt,int what,void * result,void * def)1176 decodeVal( char *src, char *opt, int what, void *result, void *def )
1177 {
1178 	char       *tmp, *tmp2;
1179 	const char *name;
1180 
1181 	/* skip the option string */
1182 	name = (const char*)&src[strlen("option")];
1183 
1184 	/* get the name of the option */
1185 	name = sanei_config_get_string( name, &tmp );
1186 
1187 	if( tmp ) {
1188 
1189 		/* on success, compare with the given one */
1190 		if( 0 == strcmp( tmp, opt )) {
1191 
1192 			DBG( _DBG_SANE_INIT, "Decoding option >%s<\n", opt );
1193 
1194 			if( _INT == what ) {
1195 
1196 				/* assign the default value for this option... */
1197 				*((int*)result) = *((int*)def);
1198 
1199 				if( *name ) {
1200 
1201 					/* get the configuration value and decode it */
1202 					name = sanei_config_get_string( name, &tmp2 );
1203 
1204 					if( tmp2 ) {
1205 						*((int*)result) = strtol( tmp2, 0, 0 );
1206 						free( tmp2 );
1207 					}
1208 				}
1209 				free( tmp );
1210 				return SANE_TRUE;
1211 
1212 			} else if( _FLOAT == what ) {
1213 
1214 				/* assign the default value for this option... */
1215 				*((double*)result) = *((double*)def);
1216 
1217 				if( *name ) {
1218 
1219 					/* get the configuration value and decode it */
1220 					name = sanei_config_get_string( name, &tmp2 );
1221 
1222 					if( tmp2 ) {
1223 						*((double*)result) = strtod( tmp2, 0 );
1224 						free( tmp2 );
1225 					}
1226 				}
1227 				free( tmp );
1228 				return SANE_TRUE;
1229 			}
1230 		}
1231 		free( tmp );
1232 	}
1233 	return SANE_FALSE;
1234 }
1235 
1236 /** function to retrieve the device name of a given string
1237  * @param src  -  string that keeps the option name to check src for
1238  * @param dest -  pointer to the string, that should receive the detected
1239  *                devicename
1240  * @return The function returns SANE_TRUE if the devicename has been found,
1241  *         if not, it returns SANE_FALSE
1242  */
1243 static SANE_Bool
decodeDevName(char * src,char * dest)1244 decodeDevName( char *src, char *dest )
1245 {
1246 	char       *tmp;
1247 	const char *name;
1248 
1249 	if( 0 == strncmp( "device", src, 6 )) {
1250 
1251 		name = (const char*)&src[strlen("device")];
1252 		name = sanei_config_skip_whitespace( name );
1253 
1254 		DBG( _DBG_SANE_INIT, "Decoding device name >%s<\n", name );
1255 
1256 		if( *name ) {
1257 			name = sanei_config_get_string( name, &tmp );
1258 			if( tmp ) {
1259 
1260 				strcpy( dest, tmp );
1261 				free( tmp );
1262 				return SANE_TRUE;
1263 			}
1264 		}
1265 	}
1266 	return SANE_FALSE;
1267 }
1268 
1269 /** attach a device to the backend
1270  */
1271 static SANE_Status
attach(const char * dev_name,CnfDef * cnf,Plustek_Device ** devp)1272 attach( const char *dev_name, CnfDef *cnf, Plustek_Device **devp )
1273 {
1274 	int             cntr;
1275 	int             result;
1276 	int             handle;
1277 	Plustek_Device *dev;
1278 
1279 	DBG( _DBG_SANE_INIT, "attach (%s, %p, %p)\n",
1280 	                                      dev_name, (void *)cnf, (void *)devp);
1281 	/* already attached ?*/
1282 	for( dev = first_dev; dev; dev = dev->next ) {
1283 
1284 		if( 0 == strcmp( dev->sane.name, dev_name )) {
1285 			if( devp )
1286 				*devp = dev;
1287 
1288 			return SANE_STATUS_GOOD;
1289 		}
1290 	}
1291 
1292 	/* allocate some memory for the device */
1293 	dev = malloc( sizeof (*dev));
1294 	if( NULL == dev )
1295 		return SANE_STATUS_NO_MEM;
1296 
1297 	/* assign all the stuff we need for this device... */
1298 
1299 	memset(dev, 0, sizeof (*dev));
1300 
1301 	dev->fd           = -1;
1302 	dev->name         = strdup(dev_name);    /* hold it double to avoid   */
1303 	dev->sane.name    = dev->name;           /* compiler warnings         */
1304 	dev->sane.vendor  = "Plustek";
1305 	dev->initialized  = -1;                  /* will be used as index too */
1306 	dev->calFile      = NULL;
1307 	dev->transferRate = DEFAULT_RATE;
1308 
1309 	memcpy( &dev->adj, &cnf->adj, sizeof(AdjDef));
1310 
1311 	show_cnf( cnf );
1312 
1313 	strncpy( dev->usbId, cnf->usbId, _MAX_ID_LEN );
1314 
1315 	if( cnf->adj.lampOff >= 0 )
1316 		dev->usbDev.dwLampOnPeriod = cnf->adj.lampOff;
1317 
1318 	if( cnf->adj.lampOffOnEnd >= 0 )
1319 		dev->usbDev.bLampOffOnEnd = cnf->adj.lampOffOnEnd;
1320 
1321 	/* go ahead and open the scanner device */
1322 	handle = usbDev_open( dev, usbDevs, SANE_FALSE );
1323 	if( handle < 0 ) {
1324 		DBG( _DBG_ERROR,"open failed: %d\n", handle );
1325 		return SANE_STATUS_IO_ERROR;
1326 	}
1327 
1328 	/* okay, so assign the handle and the scanner type */
1329 	dev->fd = handle;
1330 	if( usb_IsSheetFedDevice( dev ))
1331 		dev->sane.type = SANE_I18N("sheetfed scanner");
1332 	else
1333 		dev->sane.type = SANE_I18N("flatbed scanner");
1334 
1335 	result = usbDev_getCaps( dev );
1336 	if( result < 0 ) {
1337 		DBG( _DBG_ERROR, "usbDev_getCaps() failed(%d)\n", result);
1338 		usbDev_close(dev);
1339 		return SANE_STATUS_IO_ERROR;
1340 	}
1341 
1342 	/* save the info we got from the driver */
1343 	DBG( _DBG_INFO, "Scanner information:\n" );
1344 	if( NULL != dev->usbDev.ModelStr )
1345 		dev->sane.model = dev->usbDev.ModelStr;
1346 	else
1347 		dev->sane.model = "USB-Device";
1348 
1349 	DBG( _DBG_INFO, "Vendor : %s\n",      dev->sane.vendor  );
1350 	DBG( _DBG_INFO, "Model  : %s\n",      dev->sane.model   );
1351 	DBG( _DBG_INFO, "Flags  : 0x%08lx\n", dev->caps.dwFlag  );
1352 
1353 	dev->max_x = dev->caps.wMaxExtentX*MM_PER_INCH/_MEASURE_BASE;
1354 	dev->max_y = dev->caps.wMaxExtentY*MM_PER_INCH/_MEASURE_BASE;
1355 
1356 	/* calculate the size of the resolution list +
1357 	 * one more to avoid a buffer overflow, then allocate it...
1358 	 */
1359 	dev->res_list = (SANE_Int *)
1360 	                 calloc((((dev->usbDev.Caps.OpticDpi.x*16)-_DEF_DPI)/25+1),
1361 	                 sizeof (SANE_Int));
1362 
1363 	if (NULL == dev->res_list) {
1364 		DBG( _DBG_ERROR, "calloc failed: %s\n", strerror(errno));
1365 		usbDev_close(dev);
1366 		return SANE_STATUS_INVAL;
1367 	}
1368 
1369 	/* build up the resolution table */
1370 	dev->res_list_size = 0;
1371 	for(cntr = _DEF_DPI; cntr <= (dev->usbDev.Caps.OpticDpi.x*16); cntr += 25){
1372 		dev->res_list_size++;
1373 		dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr;
1374 	}
1375 
1376 	/* set the limits */
1377 	dev->dpi_range.min = _DEF_DPI;
1378 	dev->dpi_range.max = dev->usbDev.Caps.OpticDpi.x * 2;
1379 	dev->x_range.max   = SANE_FIX(dev->max_x);
1380 	dev->y_range.max   = SANE_FIX(dev->max_y);
1381 
1382 	dev->fd = handle;
1383 	drvclose( dev );
1384 
1385 	DBG( _DBG_SANE_INIT, "attach: model = >%s<\n", dev->sane.model );
1386 
1387 	++num_devices;
1388 	dev->next = first_dev;
1389 	first_dev = dev;
1390 
1391 	if (devp)
1392 		*devp = dev;
1393 
1394 	return SANE_STATUS_GOOD;
1395 }
1396 
1397 /** function to preset a configuration structure
1398  * @param cnf - pointer to the structure that should be initialized
1399  */
1400 static void
init_config_struct(CnfDef * cnf)1401 init_config_struct( CnfDef *cnf )
1402 {
1403 	memset(cnf, 0, sizeof(CnfDef));
1404 
1405 	cnf->adj.warmup       = -1;
1406 	cnf->adj.lampOff      = -1;
1407 	cnf->adj.lampOffOnEnd = -1;
1408 
1409 	cnf->adj.posShadingY  = -1;
1410 	cnf->adj.tpaShadingY  = -1;
1411 	cnf->adj.negShadingY  = -1;
1412 	cnf->adj.rgain        = -1;
1413 	cnf->adj.ggain        = -1;
1414 	cnf->adj.bgain        = -1;
1415 	cnf->adj.rofs         = -1;
1416 	cnf->adj.gofs         = -1;
1417 	cnf->adj.bofs         = -1;
1418 	cnf->adj.rlampoff     = -1;
1419 	cnf->adj.glampoff     = -1;
1420 	cnf->adj.blampoff     = -1;
1421 
1422 	cnf->adj.incDarkTgt = 1;
1423 
1424 	cnf->adj.graygamma = 1.0;
1425 	cnf->adj.rgamma    = 1.0;
1426 	cnf->adj.ggamma    = 1.0;
1427 	cnf->adj.bgamma    = 1.0;
1428 }
1429 
1430 /** initialize the backend
1431  */
1432 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)1433 sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize )
1434 {
1435 	char     str[PATH_MAX] = _DEFAULT_DEVICE;
1436 	CnfDef   config;
1437 	size_t   len;
1438 	FILE    *fp;
1439 
1440 	DBG_INIT();
1441 
1442 	sanei_usb_init();
1443 	sanei_lm983x_init();
1444 	sanei_thread_init();
1445 	sanei_access_init(STRINGIFY(BACKEND_NAME));
1446 
1447 #if defined PACKAGE && defined VERSION
1448 	DBG( _DBG_INFO, "Plustek backend V"BACKEND_VERSION", part of "
1449 	                                      PACKAGE " " VERSION "\n");
1450 #else
1451 	DBG( _DBG_INFO, "Plustek backend V"BACKEND_VERSION"\n" );
1452 #endif
1453 
1454 	/* do some presettings... */
1455 	auth         = authorize;
1456 	first_dev    = NULL;
1457 	first_handle = NULL;
1458 	num_devices  = 0;
1459 	usbDevs      = NULL;
1460 
1461 	/* initialize the configuration structure */
1462 	init_config_struct( &config );
1463 
1464 	/* try and get a list of all connected AND supported devices */
1465 	usbGetList( &usbDevs );
1466 
1467 	if( version_code != NULL )
1468 		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, V_MINOR, 0);
1469 
1470 	fp = sanei_config_open( PLUSTEK_CONFIG_FILE );
1471 
1472 	/* default to _DEFAULT_DEVICE instead of insisting on config file */
1473 	if( NULL == fp ) {
1474 		return attach( _DEFAULT_DEVICE, &config, 0 );
1475 	}
1476 
1477 	while( sanei_config_read( str, sizeof(str), fp)) {
1478 
1479 		DBG( _DBG_SANE_INIT, ">%s<\n", str );
1480 		if( str[0] == '#')		/* ignore line comments */
1481 			continue;
1482 
1483 		len = strlen(str);
1484 		if( 0 == len )
1485 			continue;     /* ignore empty lines */
1486 
1487 		/* check for options */
1488 		if( 0 == strncmp(str, "option", 6)) {
1489 
1490 			int    ival;
1491 			double dval;
1492 
1493 			ival = -1;
1494 			decodeVal( str, "warmup",    _INT, &config.adj.warmup,      &ival);
1495 			decodeVal( str, "lampOff",   _INT, &config.adj.lampOff,     &ival);
1496 			decodeVal( str, "lOffOnEnd", _INT, &config.adj.lampOffOnEnd,&ival);
1497 			decodeVal( str, "posShadingY",_INT, &config.adj.posShadingY,&ival);
1498 			decodeVal( str, "tpaShadingY",_INT, &config.adj.tpaShadingY,&ival);
1499 			decodeVal( str, "negShadingY",_INT, &config.adj.negShadingY,&ival);
1500 			decodeVal( str, "red_gain",   _INT, &config.adj.rgain,      &ival);
1501 			decodeVal( str, "green_gain", _INT, &config.adj.ggain,      &ival);
1502 			decodeVal( str, "blue_gain",  _INT, &config.adj.bgain,      &ival);
1503 			decodeVal( str, "red_offset",    _INT, &config.adj.rofs,    &ival);
1504 			decodeVal( str, "green_offset" , _INT, &config.adj.gofs,    &ival);
1505 			decodeVal( str, "blue_offset",   _INT, &config.adj.bofs,    &ival);
1506 			decodeVal( str, "red_lampoff",   _INT, &config.adj.rlampoff,&ival);
1507 			decodeVal( str, "green_lampoff", _INT, &config.adj.glampoff,&ival);
1508 			decodeVal( str, "blue_lampoff",  _INT, &config.adj.blampoff,&ival);
1509 
1510 			ival = 0;
1511 			decodeVal( str, "enableTPA", _INT, &config.adj.enableTpa, &ival);
1512 			decodeVal( str, "cacheCalData",
1513 									     _INT, &config.adj.cacheCalData,&ival);
1514 			decodeVal( str, "altCalibration",
1515 									     _INT, &config.adj.altCalibrate,&ival);
1516 			decodeVal( str, "skipCalibration",
1517 									  _INT, &config.adj.skipCalibration,&ival);
1518 			decodeVal( str, "skipFine",
1519 									  _INT, &config.adj.skipFine,&ival);
1520 			decodeVal( str, "skipFineWhite",
1521 									  _INT, &config.adj.skipFineWhite,&ival);
1522 			decodeVal( str, "skipDarkStrip",
1523 									  _INT, &config.adj.skipDarkStrip,&ival);
1524 			decodeVal( str, "incDarkTarget",
1525 									  _INT, &config.adj.incDarkTgt,&ival);
1526 			decodeVal( str, "invertNegatives",
1527 									  _INT, &config.adj.invertNegatives,&ival);
1528 			decodeVal( str, "disableSpeedup",
1529 									  _INT, &config.adj.disableSpeedup,&ival);
1530 
1531 			decodeVal( str, "posOffX", _INT, &config.adj.pos.x, &ival );
1532 			decodeVal( str, "posOffY", _INT, &config.adj.pos.y, &ival );
1533 
1534 			decodeVal( str, "negOffX", _INT, &config.adj.neg.x, &ival );
1535 			decodeVal( str, "negOffY", _INT, &config.adj.neg.y, &ival );
1536 
1537 			decodeVal( str, "tpaOffX", _INT, &config.adj.tpa.x, &ival );
1538 			decodeVal( str, "tpaOffY", _INT, &config.adj.tpa.y, &ival );
1539 
1540 			decodeVal( str, "mov", _INT, &config.adj.mov, &ival);
1541 
1542 			dval = 1.0;
1543 			decodeVal( str, "grayGamma",  _FLOAT, &config.adj.graygamma,&dval);
1544 			decodeVal( str, "redGamma",   _FLOAT, &config.adj.rgamma, &dval );
1545 			decodeVal( str, "greenGamma", _FLOAT, &config.adj.ggamma, &dval );
1546 			decodeVal( str, "blueGamma",  _FLOAT, &config.adj.bgamma, &dval );
1547 			continue;
1548 
1549 		/* check for sections: */
1550 		} else if( 0 == strncmp( str, _SECTION, strlen(_SECTION))) {
1551 
1552 		    char *tmp;
1553 
1554 			/* new section, try and attach previous device */
1555 			if( config.devName[0] != '\0' ) {
1556 				attach( config.devName, &config, 0 );
1557 			} else {
1558 				if( first_dev != NULL ) {
1559 					DBG( _DBG_WARNING, "section contains no device name,"
1560 					                   " ignored!\n" );
1561 				 }
1562 			}
1563 
1564 			/* re-initialize the configuration structure */
1565 			init_config_struct( &config );
1566 
1567 			tmp = config.usbId;
1568 			decodeUsbIDs( str, &tmp );
1569 
1570 			DBG( _DBG_SANE_INIT, "... next device\n" );
1571 			continue;
1572 
1573 		} else if( SANE_TRUE == decodeDevName( str, config.devName )) {
1574 			continue;
1575 		}
1576 
1577 		/* ignore other stuff... */
1578 		DBG( _DBG_SANE_INIT, "ignoring >%s<\n", str );
1579 	}
1580 	fclose (fp);
1581 
1582 	/* try to attach the last device in the config file... */
1583 	if( config.devName[0] != '\0' )
1584 		attach( config.devName, &config, 0 );
1585 
1586 	return SANE_STATUS_GOOD;
1587 }
1588 
1589 /** cleanup the backend...
1590  */
1591 void
sane_exit(void)1592 sane_exit( void )
1593 {
1594 	DevList        *tmp;
1595 	Plustek_Device *dev, *next;
1596 
1597 	DBG( _DBG_SANE_INIT, "sane_exit\n" );
1598 
1599 	for( dev = first_dev; dev; ) {
1600 
1601 		next = dev->next;
1602 
1603 		/* call the shutdown function of each device... */
1604 		usbDev_shutdown( dev );
1605 
1606 		/* we're doin' this to avoid compiler warnings as dev->sane.name
1607 		 * is defined as const char*
1608 		 */
1609 		if( dev->sane.name )
1610 			free( dev->name );
1611 
1612 		if( dev->calFile )
1613 			free( dev->calFile );
1614 
1615         if( dev->res_list )
1616 			free( dev->res_list );
1617 		free( dev );
1618 
1619 		dev = next;
1620 	}
1621 
1622 	if( devlist )
1623 		free( devlist );
1624 
1625 	while( usbDevs ) {
1626 		tmp = usbDevs->next;
1627 		free( usbDevs );
1628 		usbDevs = tmp;
1629 	}
1630 
1631 	usbDevs      = NULL;
1632 	devlist      = NULL;
1633 	auth         = NULL;
1634 	first_dev    = NULL;
1635 	first_handle = NULL;
1636 }
1637 
1638 /** return a list of all devices
1639  */
1640 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)1641 sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only )
1642 {
1643 	int             i;
1644 	Plustek_Device *dev;
1645 
1646 	DBG(_DBG_SANE_INIT, "sane_get_devices (%p, %ld)\n",
1647                                        (void *)device_list, (long) local_only);
1648 
1649 	/* already called, so cleanup */
1650 	if( devlist )
1651 		free( devlist );
1652 
1653 	devlist = malloc((num_devices + 1) * sizeof (devlist[0]));
1654 	if ( NULL == devlist )
1655 		return SANE_STATUS_NO_MEM;
1656 
1657 	i = 0;
1658 	for (dev = first_dev; i < num_devices; dev = dev->next)
1659 		devlist[i++] = &dev->sane;
1660 	devlist[i++] = 0;
1661 
1662 	*device_list = devlist;
1663 	return SANE_STATUS_GOOD;
1664 }
1665 
1666 /** open the sane device
1667  */
1668 SANE_Status
sane_open(SANE_String_Const devicename,SANE_Handle * handle)1669 sane_open( SANE_String_Const devicename, SANE_Handle* handle )
1670 {
1671 	SANE_Status      status;
1672 	Plustek_Device  *dev;
1673 	Plustek_Scanner *s;
1674 	CnfDef           config;
1675 
1676 	DBG( _DBG_SANE_INIT, "sane_open - %s\n", devicename );
1677 
1678 	if( devicename[0] ) {
1679 		for( dev = first_dev; dev; dev = dev->next ) {
1680 			if( strcmp( dev->sane.name, devicename ) == 0 )
1681 				break;
1682 		}
1683 
1684 		if( !dev ) {
1685 
1686 			memset(&config, 0, sizeof(CnfDef));
1687 
1688 			status = attach( devicename, &config, &dev );
1689 			if( SANE_STATUS_GOOD != status )
1690 				return status;
1691 		}
1692 	} else {
1693 		/* empty devicename -> use first device */
1694 		dev = first_dev;
1695 	}
1696 
1697 	if( !dev )
1698 		return SANE_STATUS_INVAL;
1699 
1700 	s = malloc (sizeof (*s));
1701 	if( NULL == s )
1702 		return SANE_STATUS_NO_MEM;
1703 
1704 	memset(s, 0, sizeof (*s));
1705 	s->r_pipe      = -1;
1706 	s->w_pipe      = -1;
1707 	s->hw          = dev;
1708 	s->scanning    = SANE_FALSE;
1709 	s->calibrating = SANE_FALSE;
1710 
1711 	init_options(s);
1712 
1713 	/* insert newly opened handle into list of open handles: */
1714 	s->next      = first_handle;
1715 	first_handle = s;
1716 	*handle      = s;
1717 
1718 	return SANE_STATUS_GOOD;
1719 }
1720 
1721 /**
1722  */
1723 void
sane_close(SANE_Handle handle)1724 sane_close( SANE_Handle handle )
1725 {
1726 	Plustek_Scanner *prev, *s = handle;
1727 
1728 	DBG( _DBG_SANE_INIT, "sane_close\n" );
1729 
1730 	if( s->calibrating )
1731 		do_cancel( s, SANE_FALSE );
1732 
1733 	/* remove handle from list of open handles: */
1734 	prev = 0;
1735 
1736 	for( s = first_handle; s; s = s->next ) {
1737 		if( s == handle )
1738 			break;
1739 		prev = s;
1740 	}
1741 
1742 	if (!s) {
1743 		DBG( _DBG_ERROR, "close: invalid handle %p\n", handle);
1744 		return;
1745 	}
1746 
1747 	close_pipe( s );
1748 
1749 	if( NULL != s->buf )
1750 		free(s->buf);
1751 
1752 	drvclose( s->hw );
1753 
1754 	if (prev)
1755 		prev->next = s->next;
1756 	else
1757 		first_handle = s->next;
1758 
1759 	free(s);
1760 }
1761 
1762 /** goes through a string list and returns the start-address of the string
1763  * that has been found, or NULL on error
1764  */
1765 static const SANE_String_Const*
search_string_list(const SANE_String_Const * list,SANE_String value)1766 search_string_list( const SANE_String_Const *list, SANE_String value )
1767 {
1768 	while( *list != NULL && strcmp(value, *list) != 0 )
1769 		++list;
1770 
1771 	if( *list == NULL )
1772 		return NULL;
1773 
1774 	return list;
1775 }
1776 
1777 /**
1778  */
1779 static int
do_calibration(void * args)1780 do_calibration( void *args )
1781 {
1782 	Plustek_Scanner *s    = (Plustek_Scanner *)args;
1783 	Plustek_Device  *dev  = s->hw;
1784 	DCapsDef        *caps = &dev->usbDev.Caps;
1785 	int              scanmode, rc;
1786 	int              modes[] = { COLOR_BW, COLOR_256GRAY, COLOR_GRAY16,
1787 	                             COLOR_TRUE24, COLOR_TRUE48 };
1788 
1789 	thread_entry();
1790 
1791 	/* if the device does only support color scanning, there's no need
1792 	 * to calibrate the gray modes
1793 	 */
1794 	if (caps->workaroundFlag & _WAF_GRAY_FROM_COLOR)
1795 		scanmode = 3;
1796 	else
1797 		scanmode = 0;
1798 
1799 	for ( ; scanmode < 5; scanmode++ ) {
1800 
1801 		if (caps->workaroundFlag & _WAF_ONLY_8BIT) {
1802 
1803 			if ((modes[scanmode] == COLOR_GRAY16) ||
1804 			    (modes[scanmode] == COLOR_TRUE48)) {
1805 				continue;
1806 			}
1807 		}
1808 
1809 		dev->scanning.dwFlag |= SCANFLAG_Calibration;
1810 
1811 		if (SANE_STATUS_GOOD == local_sane_start(s, modes[scanmode])) {
1812 
1813 			/* prepare for scanning: speed-test, warmup, calibration */
1814 			rc = usbDev_Prepare( dev, s->buf );
1815 			if( rc != 0 || scanmode == 4) {
1816 				if (rc != 0 )
1817 					DBG(_DBG_INFO,"Calibration canceled!\n");
1818 				m_fStart    = SANE_TRUE;
1819 				m_fAutoPark = SANE_TRUE;
1820 			}
1821 
1822 			drvclose( dev );
1823 			if( rc != 0 )
1824 				break;
1825 		} else {
1826 			DBG(_DBG_ERROR, "local_sane_start() failed!\n");
1827 			break;
1828 		}
1829 	}
1830 
1831 	/* restore the settings */
1832 	dev->scanning.dwFlag &= ~SCANFLAG_Calibration;
1833 	s->calibrating = SANE_FALSE;
1834 	return 0;
1835 }
1836 
1837 /** return or set the parameter values, also do some checks
1838  */
1839 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * value,SANE_Int * info)1840 sane_control_option( SANE_Handle handle, SANE_Int option,
1841                      SANE_Action action, void *value, SANE_Int *info )
1842 {
1843 	Plustek_Scanner         *s    = (Plustek_Scanner *)handle;
1844 	Plustek_Device          *dev  = s->hw;
1845 	AdjDef                  *adj  = &dev->adj;
1846 	DCapsDef                *caps = &dev->usbDev.Caps;
1847 	SANE_Status              status;
1848 	const SANE_String_Const *optval;
1849 	int                      scanmode;
1850 
1851 	if (s->scanning)
1852 		return SANE_STATUS_DEVICE_BUSY;
1853 
1854 	/* in calibration mode, we do not allow setting any value! */
1855 	if(s->calibrating) {
1856 		if (action == SANE_ACTION_SET_VALUE) {
1857 			if (option == OPT_CALIBRATE) {
1858 				if( NULL != info )
1859 					*info |= SANE_INFO_RELOAD_OPTIONS;
1860 				do_cancel(s, SANE_TRUE);
1861 				return SANE_STATUS_GOOD;
1862 			}
1863 
1864 			/* okay, we need some exceptions */
1865 			switch (option) {
1866 				case OPT_TL_X:
1867 				case OPT_TL_Y:
1868 				case OPT_BR_X:
1869 				case OPT_BR_Y: break;
1870 				default:       return SANE_STATUS_DEVICE_BUSY;
1871 			}
1872 		}
1873 	}
1874 
1875 	if ((option < 0) || (option >= NUM_OPTIONS))
1876 		return SANE_STATUS_INVAL;
1877 
1878 	if (NULL != info)
1879 		*info = 0;
1880 
1881 	switch( action ) {
1882 
1883 		case SANE_ACTION_GET_VALUE:
1884 
1885 			switch (option) {
1886 			case OPT_PREVIEW:
1887 			case OPT_NUM_OPTS:
1888 			case OPT_RESOLUTION:
1889 			case OPT_BIT_DEPTH:
1890 			case OPT_TL_X:
1891 			case OPT_TL_Y:
1892 			case OPT_BR_X:
1893 			case OPT_BR_Y:
1894 			case OPT_LAMPSWITCH:
1895 			case OPT_CUSTOM_GAMMA:
1896 			case OPT_LAMPOFF_ONEND:
1897 			case OPT_LOFF4DARK:
1898 			case OPT_CACHECAL:
1899 			case OPT_SPEEDUP:
1900 			case OPT_OVR_REDGAIN:
1901 			case OPT_OVR_GREENGAIN:
1902 			case OPT_OVR_BLUEGAIN:
1903 			case OPT_OVR_REDOFS:
1904 			case OPT_OVR_GREENOFS:
1905 			case OPT_OVR_BLUEOFS:
1906 			case OPT_OVR_RED_LOFF:
1907 			case OPT_OVR_GREEN_LOFF:
1908 			case OPT_OVR_BLUE_LOFF:
1909 			case OPT_LAMPOFF_TIMER:
1910 			case OPT_WARMUPTIME:
1911 				*(SANE_Word *)value = s->val[option].w;
1912 				break;
1913 
1914 			case OPT_BUTTON_0:
1915 				if(!s->calibrating)
1916 					usb_UpdateButtonStatus(s);
1917                                 // fall through
1918 			case OPT_BUTTON_1:
1919 			case OPT_BUTTON_2:
1920 			case OPT_BUTTON_3:
1921 			case OPT_BUTTON_4:
1922 				/* copy the button state */
1923 				*(SANE_Word*)value = s->val[option].w;
1924 				/* clear the button state */
1925 				s->val[option].w = SANE_FALSE;
1926 				break;
1927 
1928 			case OPT_CONTRAST:
1929 			case OPT_BRIGHTNESS:
1930 				*(SANE_Word *)value =
1931 				                  (s->val[option].w << SANE_FIXED_SCALE_SHIFT);
1932 				break;
1933 
1934 			case OPT_MODE:
1935 			case OPT_EXT_MODE:
1936 				strcpy ((char *) value,
1937 					  s->opt[option].constraint.string_list[s->val[option].w]);
1938 				break;
1939 
1940 			/* word array options: */
1941 			case OPT_GAMMA_VECTOR:
1942 				DBG( _DBG_INFO, "Reading MASTER gamma.\n" );
1943 				memcpy( value, s->val[option].wa, s->opt[option].size );
1944 				break;
1945 
1946 			case OPT_GAMMA_VECTOR_R:
1947 				DBG( _DBG_INFO, "Reading RED gamma.\n" );
1948 				memcpy( value, s->val[option].wa, s->opt[option].size );
1949 				break;
1950 
1951 			case OPT_GAMMA_VECTOR_G:
1952 				DBG( _DBG_INFO, "Reading GREEN gamma.\n" );
1953 				memcpy( value, s->val[option].wa, s->opt[option].size );
1954 				break;
1955 
1956 			case OPT_GAMMA_VECTOR_B:
1957 				DBG( _DBG_INFO, "Reading BLUE gamma.\n" );
1958 				memcpy( value, s->val[option].wa, s->opt[option].size );
1959 				break;
1960 			default:
1961 				return SANE_STATUS_INVAL;
1962 		}
1963 		break;
1964 
1965 		case SANE_ACTION_SET_VALUE:
1966 			status = sanei_constrain_value( s->opt + option, value, info );
1967 			if( SANE_STATUS_GOOD != status )
1968 				return status;
1969 
1970 			optval = NULL;
1971 			if( SANE_CONSTRAINT_STRING_LIST == s->opt[option].constraint_type ) {
1972 
1973 				optval = search_string_list( s->opt[option].constraint.string_list,
1974 								         (char *) value);
1975 				if( NULL == optval )
1976 					return SANE_STATUS_INVAL;
1977 			}
1978 
1979 			switch (option) {
1980 
1981 				case OPT_RESOLUTION: {
1982 					int n;
1983 					int min_d = dev->res_list[dev->res_list_size - 1];
1984 					int v     = *(SANE_Word *)value;
1985 					int best  = v;
1986 
1987 					for( n = 0; n < dev->res_list_size; n++ ) {
1988 						int d = abs(v - dev->res_list[n]);
1989 
1990 						if( d < min_d ) {
1991 							min_d = d;
1992 							best  = dev->res_list[n];
1993 						}
1994 					}
1995 
1996 					s->val[option].w = (SANE_Word)best;
1997 
1998 					if( v != best )
1999 						*(SANE_Word *)value = best;
2000 
2001 					if( NULL != info ) {
2002 						if( v != best )
2003 							*info |= SANE_INFO_INEXACT;
2004 						*info |= SANE_INFO_RELOAD_PARAMS;
2005 					}
2006 					break;
2007 				}
2008 
2009 				case OPT_PREVIEW:
2010 				case OPT_BIT_DEPTH:
2011 				case OPT_TL_X:
2012 				case OPT_TL_Y:
2013 				case OPT_BR_X:
2014 				case OPT_BR_Y:
2015 					s->val[option].w = *(SANE_Word *)value;
2016 					if( NULL != info )
2017 						*info |= SANE_INFO_RELOAD_PARAMS;
2018 					break;
2019 
2020 				case OPT_CACHECAL:
2021 					s->val[option].w = *(SANE_Word *)value;
2022 					dev->adj.cacheCalData = s->val[option].w;
2023 					if( !dev->adj.cacheCalData )
2024 						_DISABLE(OPT_CALIBRATE);
2025 					else {
2026 						if( usb_IsCISDevice(dev) || dev->adj.altCalibrate)
2027 							_ENABLE(OPT_CALIBRATE);
2028 					}
2029 					if( NULL != info )
2030 						*info |= SANE_INFO_RELOAD_OPTIONS;
2031 					break;
2032 
2033 				case OPT_CALIBRATE:
2034 					if (s->calibrating) {
2035 						do_cancel( s, SANE_FALSE );
2036 						s->calibrating = SANE_FALSE;
2037 					} else {
2038 						sc = s;
2039 						s->r_pipe      = -1;
2040 						s->w_pipe      = -1;
2041 						s->reader_pid  = sanei_thread_begin(do_calibration, s);
2042 						s->calibrating = SANE_TRUE;
2043 						signal( SIGCHLD, sig_chldhandler );
2044 					}
2045 					if (NULL != info)
2046 						*info |= SANE_INFO_RELOAD_OPTIONS;
2047 					break;
2048 
2049 				case OPT_SPEEDUP:
2050 					s->val[option].w = *(SANE_Word *)value;
2051 					dev->adj.disableSpeedup = !(s->val[option].w);
2052 					break;
2053 
2054 				case OPT_LOFF4DARK:
2055 					s->val[option].w = *(SANE_Word *)value;
2056 					dev->adj.skipDarkStrip = !(s->val[option].w);
2057 					break;
2058 
2059 				case OPT_LAMPSWITCH:
2060 					s->val[option].w = *(SANE_Word *)value;
2061 					usb_LampSwitch( dev, s->val[option].w );
2062 					if( s->val[option].w == 0 )
2063 						usb_StopLampTimer( dev );
2064 					else
2065 						usb_StartLampTimer( dev );
2066 					break;
2067 
2068 				case OPT_LAMPOFF_ONEND:
2069 					s->val[option].w = *(SANE_Word *)value;
2070 					dev->adj.lampOffOnEnd = s->val[option].w;
2071 					usb_CheckAndCopyAdjs( dev );
2072 					break;
2073 
2074 				case OPT_CUSTOM_GAMMA:
2075 					s->val[option].w = *(SANE_Word *)value;
2076 					if( NULL != info )
2077 						*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
2078 
2079 					scanmode = getScanMode( s );
2080 
2081 					_DISABLE(OPT_GAMMA_VECTOR);
2082 					_DISABLE(OPT_GAMMA_VECTOR_R);
2083 					_DISABLE(OPT_GAMMA_VECTOR_G);
2084 					_DISABLE(OPT_GAMMA_VECTOR_B);
2085 
2086 					if( SANE_TRUE == s->val[option].w ) {
2087 						DBG( _DBG_INFO, "Using custom gamma settings.\n" );
2088 						if((scanmode == COLOR_256GRAY) ||
2089 						   (scanmode == COLOR_GRAY16)) {
2090 							_ENABLE(OPT_GAMMA_VECTOR);
2091 						} else {
2092 							_ENABLE(OPT_GAMMA_VECTOR_R);
2093 							_ENABLE(OPT_GAMMA_VECTOR_G);
2094 							_ENABLE(OPT_GAMMA_VECTOR_B);
2095 						}
2096 					} else {
2097 
2098 						DBG( _DBG_INFO, "NOT using custom gamma settings.\n" );
2099 						initGammaSettings( s );
2100 
2101 						if((scanmode == COLOR_256GRAY) ||
2102 						   (scanmode == COLOR_GRAY16)) {
2103 							_DISABLE(OPT_GAMMA_VECTOR);
2104 						} else {
2105 							_DISABLE(OPT_GAMMA_VECTOR_R);
2106 							_DISABLE(OPT_GAMMA_VECTOR_G);
2107 							_DISABLE(OPT_GAMMA_VECTOR_B);
2108 						}
2109 					}
2110 					break;
2111 
2112 				case OPT_LAMPOFF_TIMER:
2113 					s->val[option].w = (*(SANE_Word *)value);
2114 					adj->lampOff     = (*(SANE_Word *)value);
2115 					usb_CheckAndCopyAdjs( dev );
2116 					break;
2117 
2118 				case OPT_WARMUPTIME:
2119 					s->val[option].w = (*(SANE_Word *)value);
2120 					adj->warmup      = (*(SANE_Word *)value);
2121 					usb_CheckAndCopyAdjs( dev );
2122 					break;
2123 
2124 				case OPT_OVR_REDGAIN:
2125 					s->val[option].w = (*(SANE_Word *)value);
2126 					adj->rgain       = (*(SANE_Word *)value);
2127 					break;
2128 				case OPT_OVR_GREENGAIN:
2129 					s->val[option].w = (*(SANE_Word *)value);
2130 					adj->ggain       = (*(SANE_Word *)value);
2131 					break;
2132 				case OPT_OVR_BLUEGAIN:
2133 					s->val[option].w = (*(SANE_Word *)value);
2134 					adj->bgain       = (*(SANE_Word *)value);
2135 					break;
2136 				case OPT_OVR_REDOFS:
2137 					s->val[option].w = (*(SANE_Word *)value);
2138 					adj->rofs        = (*(SANE_Word *)value);
2139 					break;
2140 				case OPT_OVR_GREENOFS:
2141 					s->val[option].w = (*(SANE_Word *)value);
2142 					adj->gofs       = (*(SANE_Word *)value);
2143 					break;
2144 				case OPT_OVR_BLUEOFS:
2145 					s->val[option].w = (*(SANE_Word *)value);
2146 					adj->bofs        = (*(SANE_Word *)value);
2147 					break;
2148 				case OPT_OVR_RED_LOFF:
2149 					s->val[option].w = (*(SANE_Word *)value);
2150 					adj->rlampoff    = (*(SANE_Word *)value);
2151 					break;
2152 				case OPT_OVR_GREEN_LOFF:
2153 					s->val[option].w = (*(SANE_Word *)value);
2154 					adj->glampoff    = (*(SANE_Word *)value);
2155 					break;
2156 				case OPT_OVR_BLUE_LOFF:
2157 					s->val[option].w = (*(SANE_Word *)value);
2158 					adj->blampoff    = (*(SANE_Word *)value);
2159 					break;
2160 
2161 				case OPT_CONTRAST:
2162 				case OPT_BRIGHTNESS:
2163 					s->val[option].w =
2164 					     ((*(SANE_Word *)value) >> SANE_FIXED_SCALE_SHIFT);
2165 					break;
2166 
2167 				case OPT_MODE:
2168 					s->val[option].w = optval - s->opt[option].constraint.string_list;
2169 					scanmode = getScanMode( s );
2170 
2171 					_ENABLE(OPT_CONTRAST);
2172 					_ENABLE(OPT_BIT_DEPTH);
2173 					_ENABLE(OPT_CUSTOM_GAMMA);
2174 					if (scanmode == COLOR_BW) {
2175 						_DISABLE(OPT_CONTRAST);
2176 						_DISABLE(OPT_CUSTOM_GAMMA);
2177 						_DISABLE(OPT_BIT_DEPTH);
2178 					}
2179 
2180 					if (caps->workaroundFlag & _WAF_ONLY_8BIT)
2181 						_DISABLE(OPT_BIT_DEPTH);
2182 
2183 					_DISABLE(OPT_GAMMA_VECTOR);
2184 					_DISABLE(OPT_GAMMA_VECTOR_R);
2185 					_DISABLE(OPT_GAMMA_VECTOR_G);
2186 					_DISABLE(OPT_GAMMA_VECTOR_B);
2187 
2188 					if( s->val[OPT_CUSTOM_GAMMA].w &&
2189 						!(s->opt[OPT_CUSTOM_GAMMA].cap & SANE_CAP_INACTIVE)) {
2190 
2191 						if((scanmode == COLOR_256GRAY) ||
2192 						   (scanmode == COLOR_GRAY16)) {
2193 							_ENABLE(OPT_GAMMA_VECTOR);
2194 						} else {
2195 							_ENABLE(OPT_GAMMA_VECTOR_R);
2196 							_ENABLE(OPT_GAMMA_VECTOR_G);
2197 							_ENABLE(OPT_GAMMA_VECTOR_B);
2198 						}
2199 					}
2200 					if( NULL != info )
2201 						*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2202 					break;
2203 
2204 				case OPT_EXT_MODE: {
2205 					s->val[option].w = optval - s->opt[option].constraint.string_list;
2206 
2207 					/* change the area and mode_list when changing the source
2208 					 */
2209 					if( s->val[option].w == 0 ) {
2210 						dev->scanning.sParam.bSource = SOURCE_Reflection;
2211 
2212 						dev->dpi_range.min = _DEF_DPI;
2213 
2214 						dev->x_range.max = SANE_FIX(dev->max_x);
2215 						dev->y_range.max = SANE_FIX(dev->max_y);
2216 						s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
2217 						s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
2218 						s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
2219 						s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
2220 
2221 						s->opt[OPT_MODE].constraint.string_list = mode_list;
2222 						s->val[OPT_MODE].w = 2; /* HEINER COLOR_TRUE24;*/
2223 
2224 					} else {
2225 
2226 						dev->dpi_range.min = _TPAMinDpi;
2227 
2228 						if( s->val[option].w == 1 ) {
2229 
2230 							dev->scanning.sParam.bSource = SOURCE_Transparency;
2231 							if( dev->usbDev.Caps.wFlags & DEVCAPSFLAG_LargeTPA ) {
2232 								dev->x_range.max = SANE_FIX(_SCALE(_TPALargePageWidth));
2233 								dev->y_range.max = SANE_FIX(_SCALE(_TPALargePageHeight));
2234 							} else {
2235 								dev->x_range.max = SANE_FIX(_SCALE(_TPAPageWidth));
2236 								dev->y_range.max = SANE_FIX(_SCALE(_TPAPageHeight));
2237 							}
2238 							s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TP_TLX);
2239 							s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TP_TLY);
2240 							s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_TP_BRX);
2241 							s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_TP_BRY);
2242 
2243 						} else {
2244 							dev->scanning.sParam.bSource = SOURCE_Negative;
2245 							if( dev->usbDev.Caps.wFlags & DEVCAPSFLAG_LargeTPA ) {
2246 								dev->x_range.max = SANE_FIX(_SCALE(_NegLargePageWidth));
2247 								dev->y_range.max = SANE_FIX(_SCALE(_NegLargePageHeight));
2248 							} else {
2249 								dev->x_range.max = SANE_FIX(_SCALE(_NegPageWidth));
2250 								dev->y_range.max = SANE_FIX(_SCALE(_NegPageHeight));
2251 							}
2252 							s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_NEG_TLX);
2253 							s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_NEG_TLY);
2254 							s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_NEG_BRX);
2255 							s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_NEG_BRY);
2256 						}
2257 						s->opt[OPT_MODE].constraint.string_list = &mode_list[2];
2258 						s->val[OPT_MODE].w = 0;  /* COLOR_24 is the default */
2259 					}
2260 					if( s->val[OPT_LAMPSWITCH].w != 0 ) {
2261 						usb_LampSwitch( dev, s->val[OPT_LAMPSWITCH].w );
2262 						if( s->val[OPT_LAMPSWITCH].w == 0 )
2263 							usb_StopLampTimer( dev );
2264 						else
2265 							usb_StartLampTimer( dev );
2266 					}
2267 
2268 					_ENABLE(OPT_CONTRAST);
2269 					if( NULL != info )
2270 						*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
2271 					break;
2272 				}
2273 				case OPT_GAMMA_VECTOR:
2274 					DBG( _DBG_INFO, "Setting MASTER gamma.\n" );
2275 					memcpy( s->val[option].wa, value, s->opt[option].size );
2276 					checkGammaSettings(s);
2277 					if( NULL != info )
2278 						*info |= SANE_INFO_RELOAD_PARAMS;
2279 					break;
2280 
2281 				case OPT_GAMMA_VECTOR_R:
2282 					DBG( _DBG_INFO, "Setting RED gamma.\n" );
2283 					memcpy( s->val[option].wa, value, s->opt[option].size );
2284 					checkGammaSettings(s);
2285 					if( NULL != info )
2286 						*info |= SANE_INFO_RELOAD_PARAMS;
2287 					break;
2288 
2289 				case OPT_GAMMA_VECTOR_G:
2290 					DBG( _DBG_INFO, "Setting GREEN gamma.\n" );
2291 					memcpy( s->val[option].wa, value, s->opt[option].size );
2292 					checkGammaSettings(s);
2293 					if( NULL != info )
2294 						*info |= SANE_INFO_RELOAD_PARAMS;
2295 					break;
2296 
2297 				case OPT_GAMMA_VECTOR_B:
2298 					DBG( _DBG_INFO, "Setting BLUE gamma.\n" );
2299 					memcpy( s->val[option].wa, value, s->opt[option].size );
2300 					checkGammaSettings(s);
2301 					if( NULL != info )
2302 						*info |= SANE_INFO_RELOAD_PARAMS;
2303 					break;
2304 				default:
2305 					return SANE_STATUS_INVAL;
2306 			}
2307 			break;
2308 
2309 		default:
2310 			return SANE_STATUS_INVAL;
2311 	}
2312 
2313 	return SANE_STATUS_GOOD;
2314 }
2315 
2316 /** according to the option number, return a pointer to a descriptor
2317  */
2318 const SANE_Option_Descriptor*
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)2319 sane_get_option_descriptor( SANE_Handle handle, SANE_Int option )
2320 {
2321 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2322 
2323 	if((option < 0) || (option >= NUM_OPTIONS))
2324 		return NULL;
2325 
2326 	return &(s->opt[option]);
2327 }
2328 
2329 /** return the current parameter settings
2330  */
2331 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)2332 sane_get_parameters( SANE_Handle handle, SANE_Parameters *params )
2333 {
2334 	int ndpi;
2335 	int scanmode;
2336 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2337 
2338 	/* if we're calling from within, calc best guess
2339 	 * do the same, if sane_get_parameters() is called
2340 	 * by a frontend before sane_start() is called
2341 	 */
2342 	if((NULL == params) || (s->scanning != SANE_TRUE)) {
2343 
2344 		memset(&s->params, 0, sizeof (SANE_Parameters));
2345 
2346 		ndpi = s->val[OPT_RESOLUTION].w;
2347 
2348 		s->params.pixels_per_line = SANE_UNFIX(s->val[OPT_BR_X].w -
2349 		                      s->val[OPT_TL_X].w) / MM_PER_INCH * ndpi;
2350 
2351 		s->params.lines = SANE_UNFIX( s->val[OPT_BR_Y].w -
2352 		                      s->val[OPT_TL_Y].w) / MM_PER_INCH * ndpi;
2353 
2354 		/* pixels_per_line seems to be 8 * n.  */
2355 		/* s->params.pixels_per_line = s->params.pixels_per_line & ~7; debug only */
2356 
2357 		s->params.last_frame = SANE_TRUE;
2358 		scanmode = getScanMode( s );
2359 
2360 		if( scanmode == COLOR_TRUE24 || scanmode == COLOR_TRUE48 ) {
2361 			s->params.format = SANE_FRAME_RGB;
2362 			s->params.bytes_per_line = 3 * s->params.pixels_per_line;
2363 		} else {
2364 			s->params.format = SANE_FRAME_GRAY;
2365 			if (s->params.depth == 1)
2366 				s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
2367 			else
2368 				s->params.bytes_per_line = s->params.pixels_per_line *
2369 				                                           s->params.depth / 8;
2370 		}
2371 
2372 		/* if sane_get_parameters() was called before sane_start() */
2373 		/* pass new values to the caller                           */
2374 		if ((NULL != params) && (s->scanning != SANE_TRUE))
2375 			*params = s->params;
2376 	} else {
2377 		*params = s->params;
2378 	}
2379 	return SANE_STATUS_GOOD;
2380 }
2381 
2382 /** initiate the scan process
2383  */
2384 static SANE_Status
local_sane_start(Plustek_Scanner * s,int scanmode)2385 local_sane_start(Plustek_Scanner *s, int scanmode )
2386 {
2387 	Plustek_Device *dev;
2388 
2389 	int       result;
2390 	int       ndpi;
2391 	int       left, top;
2392 	int       width, height;
2393 	double    dpi_x, dpi_y;
2394 	CropInfo  crop;
2395 	ScanInfo  sinfo;
2396 	SANE_Word tmp;
2397 
2398 	/* clear it out just in case */
2399 	memset(&crop, 0, sizeof(crop));
2400 
2401 	dev = s->hw;
2402 
2403 	/* check if we're called from the option dialog! */
2404 	if (usb_InCalibrationMode(dev))
2405 		crop.ImgDef.dwFlag = SCANFLAG_Calibration;
2406 
2407 	/* open the driver and get some information about the scanner
2408 	 */
2409 	dev->fd = usbDev_open( dev, NULL, SANE_TRUE );
2410 	if( dev->fd < 0 ) {
2411 		DBG( _DBG_ERROR, "sane_start: open failed: %d\n", errno);
2412 
2413 		if( errno == EBUSY )
2414 			return SANE_STATUS_DEVICE_BUSY;
2415 
2416 		return SANE_STATUS_IO_ERROR;
2417 	}
2418 
2419 	result = usbDev_getCaps( dev );
2420 	if( result < 0 ) {
2421 		DBG( _DBG_ERROR, "usbDev_getCaps() failed(%d)\n", result);
2422 		sanei_access_unlock( dev->sane.name );
2423 		usbDev_close( dev );
2424 		return SANE_STATUS_IO_ERROR;
2425 	}
2426 
2427 	/* All ready to go.  Set image def and see what the scanner
2428 	 * says for crop info.
2429 	 */
2430 	ndpi = s->val[OPT_RESOLUTION].w;
2431 
2432 	/* exchange the values as we can't deal with
2433 	 * negative heights and so on...*/
2434 	tmp = s->val[OPT_TL_X].w;
2435 	if( tmp > s->val[OPT_BR_X].w ) {
2436 		DBG( _DBG_INFO, "exchanging BR-X - TL-X\n" );
2437 		s->val[OPT_TL_X].w = s->val[OPT_BR_X].w;
2438 		s->val[OPT_BR_X].w = tmp;
2439 	}
2440 
2441 	tmp = s->val[OPT_TL_Y].w;
2442 	if( tmp > s->val[OPT_BR_Y].w ) {
2443 		DBG( _DBG_INFO, "exchanging BR-Y - TL-Y\n" );
2444 		s->val[OPT_TL_Y].w = s->val[OPT_BR_Y].w;
2445 		s->val[OPT_BR_Y].w = tmp;
2446 	}
2447 
2448 	/* position and extent are always relative to 300 dpi */
2449 	dpi_x = (double)dev->usbDev.Caps.OpticDpi.x;
2450 	dpi_y = (double)dev->usbDev.Caps.OpticDpi.x * 2;
2451 
2452 	left   = (int)(SANE_UNFIX (s->val[OPT_TL_X].w)*dpi_x/
2453 	                                            (MM_PER_INCH*(dpi_x/300.0)));
2454 	top    = (int)(SANE_UNFIX (s->val[OPT_TL_Y].w)*dpi_y/
2455 	                                            (MM_PER_INCH*(dpi_y/300.0)));
2456 	width  = (int)(SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) *
2457 	                                    dpi_x / (MM_PER_INCH *(dpi_x/300.0)));
2458 	height = (int)(SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) *
2459 	                                    dpi_y / (MM_PER_INCH *(dpi_y/300.0)));
2460 
2461 	/* adjust mode list according to the model we use and the
2462 	 * source we have
2463 	 */
2464 	DBG( _DBG_INFO, "scanmode = %u\n", scanmode );
2465 
2466 	crop.ImgDef.xyDpi.x   = ndpi;
2467 	crop.ImgDef.xyDpi.y   = ndpi;
2468 	crop.ImgDef.crArea.x  = left;  /* offset from left edge to area you want to scan */
2469 	crop.ImgDef.crArea.y  = top;   /* offset from top edge to area you want to scan  */
2470 	crop.ImgDef.crArea.cx = width; /* always relative to 300 dpi */
2471 	crop.ImgDef.crArea.cy = height;
2472 	crop.ImgDef.wDataType = scanmode;
2473 	crop.ImgDef.dwFlag   |= SCANDEF_QualityScan;
2474 
2475 	switch( s->val[OPT_EXT_MODE].w ) {
2476 		case 1: crop.ImgDef.dwFlag |= SCANDEF_Transparency; break;
2477 		case 2: crop.ImgDef.dwFlag |= SCANDEF_Negative;     break;
2478 		default: break;
2479 	}
2480 
2481 	result = usbDev_getCropInfo( dev, &crop );
2482 	if( result < 0 ) {
2483 		DBG( _DBG_ERROR, "usbDev_getCropInfo() failed(%d)\n", result );
2484 		usbDev_close( dev );
2485 		sanei_access_unlock( dev->sane.name );
2486 		return SANE_STATUS_IO_ERROR;
2487 	}
2488 
2489 	/* DataInf.dwAppPixelsPerLine = crop.dwPixelsPerLine;  */
2490 	s->params.pixels_per_line = crop.dwPixelsPerLine;
2491 	s->params.bytes_per_line  = crop.dwBytesPerLine;
2492 	s->params.lines           = crop.dwLinesPerArea;
2493 
2494 	/* build a SCANINFO block and get ready to scan it */
2495 	crop.ImgDef.dwFlag |= SCANDEF_QualityScan;
2496 
2497 	/* remove that for preview scans */
2498 	if( s->val[OPT_PREVIEW].w )
2499 		crop.ImgDef.dwFlag &= (~SCANDEF_QualityScan);
2500 
2501 	/* set adjustments for brightness and contrast */
2502 	sinfo.siBrightness = s->val[OPT_BRIGHTNESS].w;
2503 	sinfo.siContrast   = s->val[OPT_CONTRAST].w;
2504 
2505 	memcpy( &sinfo.ImgDef, &crop.ImgDef, sizeof(ImgDef));
2506 
2507 	DBG( _DBG_SANE_INIT, "brightness %i, contrast %i\n",
2508 	                      sinfo.siBrightness, sinfo.siContrast );
2509 
2510 	result = usbDev_setScanEnv( dev, &sinfo );
2511 	if( result < 0 ) {
2512 		DBG( _DBG_ERROR, "usbDev_setScanEnv() failed(%d)\n", result );
2513 		usbDev_close( dev );
2514 		sanei_access_unlock( dev->sane.name );
2515 		return SANE_STATUS_IO_ERROR;
2516 	}
2517 
2518 	/* download gamma correction tables... */
2519 	if( scanmode <= COLOR_GRAY16 ) {
2520 		usbDev_setMap( dev, s->gamma_table[0], s->gamma_length, _MAP_MASTER);
2521 	} else {
2522 		usbDev_setMap( dev, s->gamma_table[1], s->gamma_length, _MAP_RED   );
2523 		usbDev_setMap( dev, s->gamma_table[2], s->gamma_length, _MAP_GREEN );
2524 		usbDev_setMap( dev, s->gamma_table[3], s->gamma_length, _MAP_BLUE  );
2525 	}
2526 
2527 	tsecs = 0; /* reset timer */
2528 
2529 	result = usbDev_startScan( dev );
2530 	if( result < 0 ) {
2531 		DBG( _DBG_ERROR, "usbDev_startScan() failed(%d)\n", result );
2532 		usbDev_close( dev );
2533 		sanei_access_unlock( dev->sane.name );
2534 		return SANE_STATUS_IO_ERROR;
2535 	}
2536 
2537 	DBG( _DBG_SANE_INIT, "dwflag = 0x%lx dwBytesLine = %ld\n",
2538 	                      dev->scanning.dwFlag, dev->scanning.dwBytesLine );
2539 	DBG( _DBG_SANE_INIT, "Lines          = %d\n", s->params.lines);
2540 	DBG( _DBG_SANE_INIT, "Bytes per Line = %d\n", s->params.bytes_per_line );
2541 	DBG( _DBG_SANE_INIT, "Bitdepth       = %d\n", s->params.depth );
2542 
2543 	if (usb_InCalibrationMode(dev)) {
2544 		if (s->buf)
2545 			free(s->buf);
2546 		s->buf = NULL;
2547 	} else {
2548 
2549 		if (s->params.lines == 0 || s->params.bytes_per_line == 0) {
2550 			DBG( _DBG_ERROR, "nothing to scan!\n" );
2551 			usbDev_close( dev );
2552 			sanei_access_unlock( dev->sane.name );
2553 			return SANE_STATUS_INVAL;
2554 		}
2555 
2556 		s->buf = realloc( s->buf, (s->params.lines) * s->params.bytes_per_line );
2557 		if( NULL == s->buf ) {
2558 			DBG( _DBG_ERROR, "realloc failed\n" );
2559 			usbDev_close( dev );
2560 			sanei_access_unlock( dev->sane.name );
2561 			return SANE_STATUS_NO_MEM;
2562 		}
2563 	}
2564 
2565 	tsecs = (unsigned long)time(NULL);
2566 	DBG( _DBG_INFO, "TIME START\n" );
2567 
2568 	DBG( _DBG_SANE_INIT, "local_sane_start done\n" );
2569 	return SANE_STATUS_GOOD;
2570 }
2571 
2572 /** initiate the scan process
2573  */
2574 SANE_Status
sane_start(SANE_Handle handle)2575 sane_start( SANE_Handle handle )
2576 {
2577 	Plustek_Scanner *s   = (Plustek_Scanner *)handle;
2578 	Plustek_Device  *dev = s->hw;
2579 	SANE_Status      status;
2580 	int              fds[2];
2581 
2582 	DBG( _DBG_SANE_INIT, "sane_start\n" );
2583 
2584 	if (s->scanning)
2585 		return SANE_STATUS_DEVICE_BUSY;
2586 
2587 	/* in the end we wait until the calibration is done... */
2588 	if (s->calibrating) {
2589 		while (s->calibrating) {
2590 			sleep(1);
2591 		}
2592 
2593 		/* we have been cancelled? */
2594 		if (cancelRead)
2595 			return SANE_STATUS_CANCELLED;
2596 	}
2597 
2598 	status = sane_get_parameters (handle, NULL);
2599 	if (status != SANE_STATUS_GOOD) {
2600 		DBG( _DBG_ERROR, "sane_get_parameters failed\n" );
2601 		return status;
2602 	}
2603 
2604 	status = local_sane_start(s, getScanMode(s));
2605 	if (status != SANE_STATUS_GOOD) {
2606 		return status;
2607 	}
2608 
2609 	s->scanning = SANE_TRUE;
2610 
2611 	/*
2612 	 * everything prepared, so start the child process and a pipe to communicate
2613 	 * pipe --> fds[0]=read-fd, fds[1]=write-fd
2614 	 */
2615 	if( pipe(fds) < 0 ) {
2616 		DBG( _DBG_ERROR, "ERROR: could not create pipe\n" );
2617 	    s->scanning = SANE_FALSE;
2618 		usbDev_close( dev );
2619 		return SANE_STATUS_IO_ERROR;
2620 	}
2621 
2622 	/* create reader routine as new process */
2623 	s->bytes_read    = 0;
2624 	s->r_pipe        = fds[0];
2625 	s->w_pipe        = fds[1];
2626 	s->ipc_read_done = SANE_FALSE;
2627 	s->reader_pid    = sanei_thread_begin( reader_process, s );
2628 
2629 	cancelRead = SANE_FALSE;
2630 
2631 	if( !sanei_thread_is_valid (s->reader_pid) ) {
2632 		DBG( _DBG_ERROR, "ERROR: could not start reader task\n" );
2633 		s->scanning = SANE_FALSE;
2634 		usbDev_close( dev );
2635 		return SANE_STATUS_IO_ERROR;
2636 	}
2637 
2638 	signal( SIGCHLD, sig_chldhandler );
2639 
2640 	if( sanei_thread_is_forked()) {
2641 		close( s->w_pipe );
2642 		s->w_pipe = -1;
2643 	}
2644 
2645 	DBG( _DBG_SANE_INIT, "sane_start done\n" );
2646 	return SANE_STATUS_GOOD;
2647 }
2648 
2649 /** function to read the data from our child process
2650  */
2651 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * data,SANE_Int max_length,SANE_Int * length)2652 sane_read( SANE_Handle handle, SANE_Byte *data,
2653            SANE_Int max_length, SANE_Int *length )
2654 {
2655 	Plustek_Scanner *s = (Plustek_Scanner*)handle;
2656 	ssize_t          nread;
2657 #ifdef USE_IPC
2658 	static	 IPCDef       ipc;
2659 	unsigned char        *buf;
2660 	static unsigned long  c = 0;
2661 #endif
2662 
2663 	*length = 0;
2664 
2665 #ifdef USE_IPC
2666 	/* first try and read IPC... */
2667 	if( !s->ipc_read_done ) {
2668 
2669 		buf = (unsigned char*)&ipc;
2670 		for( c = 0; c < sizeof(ipc); ) {
2671 			nread = read( s->r_pipe, buf, sizeof(ipc));
2672 			if( nread < 0 ) {
2673 				if( EAGAIN != errno ) {
2674 					do_cancel( s, SANE_TRUE );
2675 					return SANE_STATUS_IO_ERROR;
2676 				} else {
2677 					return SANE_STATUS_GOOD;
2678 				}
2679 			} else {
2680 				c   += nread;
2681 				buf += nread;
2682 				if( c == sizeof(ipc)) {
2683 					s->ipc_read_done = SANE_TRUE;
2684 					break;
2685 				}
2686 			}
2687 		}
2688 		s->hw->transferRate = ipc.transferRate;
2689 		DBG( _DBG_INFO, "IPC: Transferrate = %lu Bytes/s\n",
2690 		     ipc.transferRate );
2691 	}
2692 #endif
2693 	/* here we read all data from the driver... */
2694 	nread = read( s->r_pipe, data, max_length );
2695 	DBG( _DBG_READ, "sane_read - read %ld bytes\n", (long)nread );
2696 	if (!(s->scanning)) {
2697 		return do_cancel( s, SANE_TRUE );
2698 	}
2699 
2700 	if( nread < 0 ) {
2701 
2702 		if( EAGAIN == errno ) {
2703 
2704 			/* if we already had red the picture, so it's okay and stop */
2705 			if( s->bytes_read ==
2706 				(unsigned long)(s->params.lines * s->params.bytes_per_line)) {
2707 				sanei_thread_waitpid( s->reader_pid, 0 );
2708 				sanei_thread_invalidate( s->reader_pid );
2709 				s->scanning = SANE_FALSE;
2710 				drvclose( s->hw );
2711 				return close_pipe(s);
2712 			}
2713 
2714 			/* else force the frontend to try again*/
2715 			return SANE_STATUS_GOOD;
2716 
2717 		} else {
2718 			DBG( _DBG_ERROR, "ERROR: errno=%d\n", errno );
2719 			do_cancel( s, SANE_TRUE );
2720 			return SANE_STATUS_IO_ERROR;
2721 		}
2722 	}
2723 
2724 	*length        = nread;
2725 	s->bytes_read += nread;
2726 
2727 	/* nothing red means that we're finished OR we had a problem... */
2728 	if( 0 == nread ) {
2729 
2730 		drvclose( s->hw );
2731 		s->exit_code = sanei_thread_get_status( s->reader_pid );
2732 
2733 		if( SANE_STATUS_GOOD != s->exit_code ) {
2734 			close_pipe(s);
2735 			return s->exit_code;
2736 		}
2737 		sanei_thread_invalidate( s->reader_pid );
2738 		s->scanning = SANE_FALSE;
2739 		return close_pipe(s);
2740 	}
2741 	return SANE_STATUS_GOOD;
2742 }
2743 
2744 /** cancel the scanning process
2745  */
2746 void
sane_cancel(SANE_Handle handle)2747 sane_cancel( SANE_Handle handle )
2748 {
2749 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2750 
2751 	DBG( _DBG_SANE_INIT, "sane_cancel\n" );
2752 
2753 	if (s->scanning || s->calibrating)
2754 		do_cancel( s, SANE_FALSE );
2755 }
2756 
2757 /** set the pipe to blocking/non blocking mode
2758  */
2759 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)2760 sane_set_io_mode( SANE_Handle handle, SANE_Bool non_blocking )
2761 {
2762 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2763 
2764 	DBG( _DBG_SANE_INIT, "sane_set_io_mode: non_blocking=%d\n",non_blocking );
2765 
2766 	if ( !s->scanning ) {
2767 		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2768 		return SANE_STATUS_INVAL;
2769 	}
2770 
2771 	if( -1 == s->r_pipe ) {
2772 		DBG( _DBG_ERROR, "ERROR: not supported !\n" );
2773 		return SANE_STATUS_UNSUPPORTED;
2774 	}
2775 
2776 	if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) {
2777 		DBG( _DBG_ERROR, "ERROR: could not set to non-blocking mode !\n" );
2778 		return SANE_STATUS_IO_ERROR;
2779 	}
2780 
2781 	DBG( _DBG_SANE_INIT, "sane_set_io_mode done\n" );
2782 	return SANE_STATUS_GOOD;
2783 }
2784 
2785 /** return the descriptor if available
2786  */
2787 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)2788 sane_get_select_fd( SANE_Handle handle, SANE_Int * fd )
2789 {
2790 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2791 
2792 	DBG( _DBG_SANE_INIT, "sane_get_select_fd\n" );
2793 
2794 	if( !s->scanning ) {
2795 		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2796 		return SANE_STATUS_INVAL;
2797 	}
2798 
2799 	*fd = s->r_pipe;
2800 
2801 	DBG( _DBG_SANE_INIT, "sane_get_select_fd done\n" );
2802 	return SANE_STATUS_GOOD;
2803 }
2804 
2805 /* END PLUSTEK.C ............................................................*/
2806