1 /** @file plustek_pp.c
2  *  @brief SANE backend for Plustek parallelport scanner
3  *
4  * Based on Kazuhiro Sasayama previous work on
5  * plustek.[ch] file from the SANE package.<br>
6  * Original code taken from sane-0.71<br>
7  * Copyright (C) 1997 Hypercore Software Design, Ltd.<br>
8  * Also based on the work done by Rick Bronson<br>
9  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de><br>
10  *
11  * History:
12  * - 0.01 - initial version, imported from the kernel-module 0.42-11
13  * - 0.43 - bumped up version to reflect the former module code version
14  * - 0.44 - bumped up version to reflect the recent changes
15  *        - minor cleanup
16  *.
17  * <hr>
18  * This file is part of the SANE package.
19  *
20  * This program is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU General Public License as
22  * published by the Free Software Foundation; either version 2 of the
23  * License, or (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful, but
26  * WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28  * General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
32  *
33  * As a special exception, the authors of SANE give permission for
34  * additional uses of the libraries contained in this release of SANE.
35  *
36  * The exception is that, if you link a SANE library with other files
37  * to produce an executable, this does not by itself cause the
38  * resulting executable to be covered by the GNU General Public
39  * License.  Your use of that executable is in no way restricted on
40  * account of linking the SANE library code into it.
41  *
42  * This exception does not, however, invalidate any other reasons why
43  * the executable file might be covered by the GNU General Public
44  * License.
45  *
46  * If you submit changes to SANE to the maintainers to be included in
47  * a subsequent release, you agree by submitting the changes that
48  * those changes may be distributed with this exception intact.
49  *
50  * If you write modifications of your own for SANE, it is your choice
51  * whether to permit this exception to apply to your modifications.
52  * If you do not wish that, delete this exception notice.
53  * <hr>
54  */
55 
56 /** @mainpage
57  *  @verbinclude Plustek-PARPORT.txt
58  */
59 
60 #ifdef _AIX
61 # include "../include/lalloca.h"  /* MUST come first for AIX! */
62 #endif
63 
64 #include "../include/sane/config.h"
65 #include "../include/lalloca.h"
66 
67 #include <errno.h>
68 #include <fcntl.h>
69 #include <limits.h>
70 #include <signal.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <ctype.h>
74 #include <unistd.h>
75 #include <time.h>
76 #include <math.h>
77 #include <stdint.h>
78 
79 #include <sys/time.h>
80 #include <sys/types.h>
81 #include <sys/ioctl.h>
82 
83 #include "../include/sane/sane.h"
84 #include "../include/sane/sanei.h"
85 #include "../include/sane/saneopts.h"
86 
87 #define BACKEND_VERSION "0.44-1"
88 #define BACKEND_NAME	plustek_pp
89 #include "../include/sane/sanei_backend.h"
90 #include "../include/sane/sanei_config.h"
91 #include "../include/sane/sanei_thread.h"
92 #include "../include/sane/sanei_pp.h"
93 
94 #define _BACKEND_ENABLED
95 #define _USER_MODE
96 
97 #include "plustek-pp.h"
98 
99 /*********************** the debug levels ************************************/
100 
101 #define _DBG_FATAL      0
102 #define _DBG_ERROR      1
103 #define _DBG_WARNING    3
104 #define _DBG_INFO       5
105 #define _DBG_PROC       7
106 #define _DBG_SANE_INIT 10
107 #define _DBG_INFO2     13
108 #define _DBG_DUMP      20
109 #define _DBG_READ      25
110 
111 /*****************************************************************************/
112 
113 /*
114  * see plustek-share.h
115  */
116 MODELSTR;
117 
118 #ifdef _BACKEND_ENABLED
119 #ifndef NDEBUG
120 # define DEBUG
121 #endif
122 
123 /* I know this is in general no good idea, but it works */
124 # include "plustek-pp_io.c"
125 # include "plustek-pp_dac.c"
126 # include "plustek-pp_detect.c"
127 # include "plustek-pp_genericio.c"
128 # include "plustek-pp_image.c"
129 # include "plustek-pp_map.c"
130 # include "plustek-pp_misc.c"
131 # include "plustek-pp_models.c"
132 # include "plustek-pp_motor.c"
133 # include "plustek-pp_p12.c"
134 # include "plustek-pp_p12ccd.c"
135 # include "plustek-pp_p48xx.c"
136 # include "plustek-pp_p9636.c"
137 # include "plustek-pp_procfs.c"
138 # include "plustek-pp_scale.c"
139 # include "plustek-pp_tpa.c"
140 
141 #define _DEFAULT_DEVICE "0x378"
142 #else
143 #define _DEFAULT_DEVICE "/dev/pt_drv"
144 #endif
145 
146 #ifdef _BACKEND_ENABLED
147 # include "plustek-pp_ptdrv.c"
148 #endif
149 
150 #include "plustek-pp_wrapper.c"
151 
152 
153 /************************** global vars **************************************/
154 
155 static int                 num_devices;
156 static Plustek_Device     *first_dev;
157 static Plustek_Scanner    *first_handle;
158 static const SANE_Device **devlist = 0;
159 static unsigned long       tsecs   = 0;
160 
161 static ModeParam mode_params[] =
162 {
163   {0, 1, COLOR_BW},
164   {0, 1, COLOR_HALFTONE},
165   {0, 8, COLOR_256GRAY},
166   {1, 8, COLOR_TRUE24},
167   {1, 16, COLOR_TRUE32},
168   {1, 16, COLOR_TRUE36}
169 };
170 
171 static ModeParam mode_9800x_params[] =
172 {
173   {0, 1,  COLOR_BW},
174   {0, 1,  COLOR_HALFTONE},
175   {0, 8,  COLOR_256GRAY},
176   {1, 8,  COLOR_TRUE24},
177   {1, 16, COLOR_TRUE48}
178 };
179 
180 static const SANE_String_Const mode_list[] =
181 {
182 	SANE_VALUE_SCAN_MODE_LINEART,
183 	SANE_VALUE_SCAN_MODE_HALFTONE,
184 	SANE_VALUE_SCAN_MODE_GRAY,
185 	SANE_VALUE_SCAN_MODE_COLOR,
186 	NULL
187 };
188 
189 static const SANE_String_Const mode_9800x_list[] =
190 {
191 	SANE_VALUE_SCAN_MODE_LINEART,
192 	SANE_VALUE_SCAN_MODE_HALFTONE,
193 	SANE_VALUE_SCAN_MODE_GRAY,
194 	SANE_VALUE_SCAN_MODE_COLOR,
195 	SANE_I18N("Color36"),
196 	NULL
197 };
198 
199 static const SANE_String_Const ext_mode_list[] =
200 {
201 	SANE_I18N("Normal"),
202 	SANE_I18N("Transparency"),
203 	SANE_I18N("Negative"),
204 	NULL
205 };
206 
207 static const SANE_String_Const halftone_list[] =
208 {
209 	SANE_I18N("Dithermap 1"),
210 	SANE_I18N("Dithermap 2"),
211 	SANE_I18N("Randomize"),
212 	NULL
213 };
214 
215 static const SANE_Range percentage_range =
216 {
217 	SANE_FIX(-100),         /* minimum      */
218 	SANE_FIX( 100),         /* maximum      */
219 	SANE_FIX(   1)          /* quantization */
220 };
221 
222 /*
223  * lens info
224  */
225 static LensInfo lens = {{0,0,0,0,},{0,0,0,0,},{0,0,0,0,},{0,0,0,0,},0,0};
226 
227 /* authorization stuff */
228 static SANE_Auth_Callback auth = NULL;
229 
230 /****************************** the backend... *******************************/
231 
232 #define _YN(x) (x?"yes":"no")
233 
234 /**
235  * function to display the configuration options for the current device
236  * @param cnf - pointer to the configuration structure whose content should be
237  *              displayed
238  */
show_cnf( pCnfDef cnf )239 static void show_cnf( pCnfDef cnf )
240 {
241 	DBG( _DBG_SANE_INIT,"Device configuration:\n" );
242 	DBG( _DBG_SANE_INIT,"device name   : >%s<\n", cnf->devName               );
243 	DBG( _DBG_SANE_INIT,"direct I/O    : %s\n",   _YN(cnf->adj.direct_io    ));
244 	DBG( _DBG_SANE_INIT,"warmup        : %ds\n",  cnf->adj.warmup            );
245 	DBG( _DBG_SANE_INIT,"lampOff       : %d\n",   cnf->adj.lampOff           );
246 	DBG( _DBG_SANE_INIT,"lampOffOnEnd  : %s\n",   _YN(cnf->adj.lampOffOnEnd ));
247 	DBG( _DBG_SANE_INIT,"model override: %d\n",   cnf->adj.mov               );
248 	DBG( _DBG_SANE_INIT,"---------------------\n" );
249 }
250 
251 /** open the device specific driver and reset the internal timing stuff
252  * @param  dev - pointer to the device specific structure
253  * @return the function returns the result of the open call, on success
254  *         of course the handle
255  */
drvopen( Plustek_Device *dev )256 static int drvopen(	Plustek_Device *dev )
257 {
258 	int handle;
259 
260     DBG( _DBG_INFO, "drvopen()\n" );
261 
262 	handle = dev->open((const char*)dev->name, (void *)dev );
263 
264 	tsecs = 0;
265 
266 	return handle;
267 }
268 
269 /** Calls the device specific stop and close functions.
270  * @param  dev - pointer to the device specific structure
271  * @return The function always returns SANE_STATUS_GOOD
272  */
drvclose( Plustek_Device *dev )273 static SANE_Status drvclose( Plustek_Device *dev )
274 {
275 	short int_cnt;
276 
277 	if( dev->fd >= 0 ) {
278 
279 	    DBG( _DBG_INFO, "drvclose()\n" );
280 
281 		if( 0 != tsecs ) {
282 			DBG( _DBG_INFO, "TIME END 1: %lus\n", time(NULL)-tsecs);
283 		}
284 
285 		/*
286 		 * don't check the return values, simply do it and close the driver
287 		 */
288 		int_cnt = 0;
289 		dev->stopScan( dev, &int_cnt );
290 		dev->close( dev );
291 	}
292 	dev->fd = -1;
293 
294 	return SANE_STATUS_GOOD;
295 }
296 
297 /** according to the mode and source we return the corresponding mode list
298  */
getModeList( Plustek_Scanner *scanner )299 static pModeParam getModeList( Plustek_Scanner *scanner )
300 {
301 	pModeParam mp;
302 
303 	if((_ASIC_IS_98003 == scanner->hw->caps.AsicID) ||
304    	   (_ASIC_IS_98001 == scanner->hw->caps.AsicID)) {
305 		mp = mode_9800x_params;
306 	} else {
307 		mp = mode_params;
308 	}
309 
310 	/*
311 	 * the transparency/negative mode supports only GRAY/COLOR/COLOR32/COLOR48
312 	 */
313 	if( 0 != scanner->val[OPT_EXT_MODE].w ) {
314 		mp = &mp[_TPAModeSupportMin];
315 	}
316 
317 	return mp;
318 }
319 
320 /**
321  */
close_pipe( Plustek_Scanner *scanner )322 static SANE_Status close_pipe( Plustek_Scanner *scanner )
323 {
324 	if( scanner->r_pipe >= 0 ) {
325 
326 		DBG( _DBG_PROC, "close r_pipe\n" );
327 		close( scanner->r_pipe );
328 		scanner->r_pipe = -1;
329 	}
330 	if( scanner->w_pipe >= 0 ) {
331 
332 		DBG( _DBG_PROC, "close w_pipe\n" );
333 		close( scanner->w_pipe );
334 		scanner->w_pipe = -1;
335 	}
336 
337 	return SANE_STATUS_EOF;
338 }
339 
340 /**
341  */
sig_chldhandler( int signo )342 static void sig_chldhandler( int signo )
343 {
344 	DBG( _DBG_PROC, "Child is down (signal=%d)\n", signo );
345 }
346 
347 /** signal handler to kill the child process
348  */
reader_process_sigterm_handler( int signo )349 static void reader_process_sigterm_handler( int signo )
350 {
351 	DBG( _DBG_PROC, "reader_process: terminated by signal %d\n", signo );
352 	_exit( SANE_STATUS_GOOD );
353 }
354 
sigalarm_handler( int signo )355 static void sigalarm_handler( int signo )
356 {
357 	_VAR_NOT_USED( signo );
358 	DBG( _DBG_PROC, "ALARM!!!\n" );
359 }
360 
361 /** executed as a child process
362  * read the data from the driver and send them to the parent process
363  */
reader_process( void *args )364 static int reader_process( void *args )
365 {
366 	int              line;
367 	unsigned long    status;
368 	unsigned long    data_length;
369 	struct SIGACTION act;
370 	sigset_t         ignore_set;
371 	Plustek_Scanner *scanner = (Plustek_Scanner *)args;
372 
373 	if( sanei_thread_is_forked()) {
374 		DBG( _DBG_PROC, "reader_process started (forked)\n" );
375 		close( scanner->r_pipe );
376 		scanner->r_pipe = -1;
377 	} else {
378 		DBG( _DBG_PROC, "reader_process started (as thread)\n" );
379 	}
380 
381 	sigfillset ( &ignore_set );
382 	sigdelset  ( &ignore_set, SIGTERM );
383 #if defined (__APPLE__) && defined (__MACH__)
384 	sigdelset  ( &ignore_set, SIGUSR2 );
385 #endif
386 	sigprocmask( SIG_SETMASK, &ignore_set, 0 );
387 
388 	memset   ( &act, 0, sizeof (act));
389 	sigaction( SIGTERM, &act, 0 );
390 
391 	/* install the signal handler */
392     sigemptyset(&(act.sa_mask));
393     act.sa_flags = 0;
394 
395 	act.sa_handler = reader_process_sigterm_handler;
396 	sigaction( SIGTERM, &act, 0 );
397 
398 	data_length = scanner->params.lines * scanner->params.bytes_per_line;
399 
400 	DBG( _DBG_PROC, "reader_process:"
401 					"starting to READ data (%lu bytes)\n", data_length );
402 	DBG( _DBG_PROC, "buf = 0x%08lx\n", (unsigned long)scanner->buf );
403 
404 	if( NULL == scanner->buf ) {
405 		DBG( _DBG_FATAL, "NULL Pointer !!!!\n" );
406 		return SANE_STATUS_IO_ERROR;
407 	}
408 
409 	/* here we read all data from the driver... */
410 	if( scanner->hw->readImage ) {
411 
412 		status = (unsigned long)scanner->hw->readImage( scanner->hw,
413                                                     scanner->buf, data_length);
414 	} else {
415 
416 		unsigned char *buf = scanner->buf;
417 
418 
419 		status = scanner->hw->prepare( scanner->hw, buf );
420 
421         if( 0 == status ) {
422 
423 			for( line = 0; line < scanner->params.lines; line++ ) {
424 
425 				status = scanner->hw->readLine( scanner->hw );
426 				if((int)status < 0 ) {
427 					break;
428 				}
429 
430 			    write( scanner->w_pipe, buf, scanner->params.bytes_per_line );
431 
432 				buf += scanner->params.bytes_per_line;
433 			}
434 		}
435 	}
436 
437 	/* on error, there's no need to clean up, as this is done by the parent */
438 	if((int)status < 0 ) {
439 		DBG( _DBG_ERROR, "read failed, status = %i, errno %i\n",
440                                                           (int)status, errno );
441 		if( -9009 == (int)status )
442 			return SANE_STATUS_CANCELLED;
443 
444 		if( errno == EBUSY )
445 			return SANE_STATUS_DEVICE_BUSY;
446 
447 		return SANE_STATUS_IO_ERROR;
448     }
449 
450 	/* send to parent */
451 	if( scanner->hw->readImage ) {
452 		DBG( _DBG_PROC, "sending %lu bytes to parent\n", status );
453 	    write( scanner->w_pipe, scanner->buf, status );
454 	}
455 
456 	DBG( _DBG_PROC, "reader_process: finished reading data\n" );
457 	return SANE_STATUS_GOOD;
458 }
459 
460 /** stop the current scan process
461  */
do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe )462 static SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe  )
463 {
464 	struct SIGACTION act;
465 	SANE_Pid         res;
466 	short            int_cnt;
467 
468 	DBG( _DBG_PROC,"do_cancel\n" );
469 
470 	scanner->scanning = SANE_FALSE;
471 
472 	if( sanei_thread_is_valid( scanner->reader_pid )) {
473 
474                 DBG( _DBG_PROC, "---- killing reader_process ----\n" );
475 
476 		/* tell the driver to stop scanning */
477 		if( -1 != scanner->hw->fd ) {
478 			int_cnt = 1;
479 			scanner->hw->stopScan( scanner->hw, &int_cnt );
480 		}
481 
482 	    sigemptyset(&(act.sa_mask));
483     	act.sa_flags = 0;
484 
485 		act.sa_handler = sigalarm_handler;
486 		sigaction( SIGALRM, &act, 0 );
487 
488 		/* kill our child process and wait until done */
489 		sanei_thread_kill( scanner->reader_pid );
490 
491 		/* give'em 10 seconds 'til done...*/
492 		alarm(10);
493 		res = sanei_thread_waitpid( scanner->reader_pid, 0 );
494 		alarm(0);
495 
496 		if( res != scanner->reader_pid ) {
497 			DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
498 
499 			/* do it the hard way...*/
500 #ifdef USE_PTHREAD
501 			sanei_thread_kill( scanner->reader_pid );
502 #else
503 			sanei_thread_sendsig( scanner->reader_pid, SIGKILL );
504 #endif
505 		}
506 
507 		sanei_thread_invalidate( scanner->reader_pid );
508 		DBG( _DBG_PROC,"reader_process killed\n");
509 	}
510 
511 	if( SANE_TRUE == closepipe ) {
512 		close_pipe( scanner );
513 	}
514 
515 	drvclose( scanner->hw );
516 
517 	if( tsecs != 0 ) {
518 		DBG( _DBG_INFO, "TIME END 2: %lus\n", time(NULL)-tsecs);
519 		tsecs = 0;
520 	}
521 
522 	return SANE_STATUS_CANCELLED;
523 }
524 
525 /** because of some internal problems (inside the parport driver), we have to
526  * limit the max resolution to optical resolution. This is done by this
527  * function
528  * @param  dev - pointer to the device specific structure
529  * @return The function always returns SANE_STATUS_GOOD
530  */
limitResolution( Plustek_Device *dev )531 static void limitResolution( Plustek_Device *dev )
532 {
533 	dev->dpi_range.min = _DEF_DPI;
534  	if( dev->dpi_range.min < _DEF_DPI )
535 		dev->dpi_range.min = _DEF_DPI;
536 
537 	/*
538 	 * CHANGE: limit resolution to max. physical available one
539 	 *		   Note: the resolution for the Asic 96001/3 models is limited to
540 	 *               the X-Resolution
541 	 */
542 	if((_ASIC_IS_96003 == dev->caps.AsicID) ||
543        (_ASIC_IS_96001 == dev->caps.AsicID)) {
544 		dev->dpi_range.max = lens.rDpiX.wPhyMax;
545 	} else {
546 		dev->dpi_range.max = lens.rDpiY.wPhyMax;
547 	}
548 
549 	dev->dpi_range.quant = 0;
550 	dev->x_range.min 	 = 0;
551 	dev->x_range.max 	 = SANE_FIX(dev->max_x);
552 	dev->x_range.quant 	 = 0;
553 	dev->y_range.min 	 = 0;
554 	dev->y_range.max 	 = SANE_FIX(dev->max_y);
555 	dev->y_range.quant 	 = 0;
556 }
557 
558 /** Currently we support only LM9831/2/3 chips and these use the same
559  * sizes...
560  * @param  s - pointer to the scanner specific structure
561  * @return The function always returns SANE_STATUS_GOOD
562  */
initGammaSettings( Plustek_Scanner *s )563 static SANE_Status initGammaSettings( Plustek_Scanner *s )
564 {
565 	int    i, j, val;
566 	double gamma;
567 
568 	/*
569      * this setting is common to the ASIC98001/3 and
570      * LM9831/2/3 based devices
571      * older parallelport devices use 256 entries
572      */
573 	s->gamma_length      = 4096;
574   	s->gamma_range.min   = 0;
575   	s->gamma_range.max   = 255;
576   	s->gamma_range.quant = 0;
577 
578 	if((_ASIC_IS_96003 == s->hw->caps.AsicID) ||
579        (_ASIC_IS_96001 == s->hw->caps.AsicID)) {
580 
581 		s->gamma_length = 256;
582 	}
583 
584   	DBG( _DBG_INFO, "Presetting Gamma tables (len=%u)\n", s->gamma_length );
585   	DBG( _DBG_INFO, "----------------------------------\n" );
586 
587   	/*
588   	 * preset the gamma maps
589   	 */
590   	for( i = 0; i < 4; i++ ) {
591 
592 		switch( i ) {
593 			case 1:  gamma = s->hw->adj.rgamma;    break;
594 			case 2:  gamma = s->hw->adj.ggamma;    break;
595 			case 3:  gamma = s->hw->adj.bgamma;    break;
596 			default: gamma = s->hw->adj.graygamma; break;
597 		}
598 
599 		for( j = 0; j < s->gamma_length; j++ ) {
600 
601 			val = (s->gamma_range.max *
602 					    pow((double) j / ((double)s->gamma_length - 1.0),
603 						1.0 / gamma ));
604 
605 			if( val > s->gamma_range.max )
606 				val = s->gamma_range.max;
607 
608 			s->gamma_table[i][j] = val;
609 		}
610 	}
611 
612 	return SANE_STATUS_GOOD;
613 }
614 
615 /** Check the gamma vectors we got back and limit if necessary
616  * @param  s - pointer to the scanner specific structure
617  * @return nothing
618  */
checkGammaSettings( Plustek_Scanner *s )619 static void checkGammaSettings( Plustek_Scanner *s )
620 {
621 	int i, j;
622 
623 	for( i = 0; i < 4 ; i++ ) {
624 		for( j = 0; j < s->gamma_length; j++ ) {
625 			if( s->gamma_table[i][j] > s->gamma_range.max ) {
626 				s->gamma_table[i][j] = s->gamma_range.max;
627 			}
628 		}
629 	}
630 }
631 
632 /** initialize the options for the backend according to the device we have
633  */
init_options( Plustek_Scanner *s )634 static SANE_Status init_options( Plustek_Scanner *s )
635 {
636 	int i;
637 
638 	memset( s->opt, 0, sizeof(s->opt));
639 
640 	for( i = 0; i < NUM_OPTIONS; ++i ) {
641 		s->opt[i].size = sizeof (SANE_Word);
642 		s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
643 	}
644 
645 	s->opt[OPT_NUM_OPTS].name  = SANE_NAME_NUM_OPTIONS;
646 	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
647 	s->opt[OPT_NUM_OPTS].desc  = SANE_DESC_NUM_OPTIONS;
648 	s->opt[OPT_NUM_OPTS].type  = SANE_TYPE_INT;
649 	s->opt[OPT_NUM_OPTS].unit  = SANE_UNIT_NONE;
650 	s->opt[OPT_NUM_OPTS].cap   = SANE_CAP_SOFT_DETECT;
651 	s->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
652 	s->val[OPT_NUM_OPTS].w 	   = NUM_OPTIONS;
653 
654 	/* "Scan Mode" group: */
655 	s->opt[OPT_MODE_GROUP].name  = "scanmode-group";
656 	s->opt[OPT_MODE_GROUP].title = SANE_I18N("Scan Mode");
657 	s->opt[OPT_MODE_GROUP].desc  = "";
658 	s->opt[OPT_MODE_GROUP].type  = SANE_TYPE_GROUP;
659 	s->opt[OPT_MODE_GROUP].cap   = 0;
660 
661 	/* scan mode */
662 	s->opt[OPT_MODE].name  = SANE_NAME_SCAN_MODE;
663 	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
664 	s->opt[OPT_MODE].desc  = SANE_DESC_SCAN_MODE;
665 	s->opt[OPT_MODE].type  = SANE_TYPE_STRING;
666 	s->opt[OPT_MODE].size  = 32;
667 	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
668 
669 	if((_ASIC_IS_98001  == s->hw->caps.AsicID) ||
670 	   (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
671 		s->opt[OPT_MODE].constraint.string_list = mode_9800x_list;
672 	} else {
673 		s->opt[OPT_MODE].constraint.string_list = mode_list;
674 	}
675 	s->val[OPT_MODE].w = 3; /* Color */
676 
677 	/* scan source */
678 	s->opt[OPT_EXT_MODE].name  = SANE_NAME_SCAN_SOURCE;
679 	s->opt[OPT_EXT_MODE].title = SANE_TITLE_SCAN_SOURCE;
680 	s->opt[OPT_EXT_MODE].desc  = SANE_DESC_SCAN_SOURCE;
681 	s->opt[OPT_EXT_MODE].type  = SANE_TYPE_STRING;
682 	s->opt[OPT_EXT_MODE].size  = 32;
683 	s->opt[OPT_EXT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
684 	s->opt[OPT_EXT_MODE].constraint.string_list = ext_mode_list;
685 	s->val[OPT_EXT_MODE].w = 0; /* Normal */
686 
687 	/* halftone */
688 	s->opt[OPT_HALFTONE].name  = SANE_NAME_HALFTONE_PATTERN;
689 	s->opt[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
690 	s->opt[OPT_HALFTONE].desc  = SANE_DESC_HALFTONE_PATTERN;
691 	s->opt[OPT_HALFTONE].type  = SANE_TYPE_STRING;
692 	s->opt[OPT_HALFTONE].size  = 32;
693 	s->opt[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
694 	s->opt[OPT_HALFTONE].constraint.string_list = halftone_list;
695 	s->val[OPT_HALFTONE].w = 0;	/* Standard dithermap */
696 	s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
697 
698 	/* brightness */
699 	s->opt[OPT_BRIGHTNESS].name  = SANE_NAME_BRIGHTNESS;
700 	s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
701 	s->opt[OPT_BRIGHTNESS].desc  = SANE_DESC_BRIGHTNESS;
702 	s->opt[OPT_BRIGHTNESS].type  = SANE_TYPE_FIXED;
703 	s->opt[OPT_BRIGHTNESS].unit  = SANE_UNIT_PERCENT;
704 	s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
705 	s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
706 	s->val[OPT_BRIGHTNESS].w     = 0;
707 
708 	/* contrast */
709 	s->opt[OPT_CONTRAST].name  = SANE_NAME_CONTRAST;
710 	s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
711 	s->opt[OPT_CONTRAST].desc  = SANE_DESC_CONTRAST;
712 	s->opt[OPT_CONTRAST].type  = SANE_TYPE_FIXED;
713 	s->opt[OPT_CONTRAST].unit  = SANE_UNIT_PERCENT;
714 	s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
715 	s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
716 	s->val[OPT_CONTRAST].w     = 0;
717 
718 	/* resolution */
719 	s->opt[OPT_RESOLUTION].name  = SANE_NAME_SCAN_RESOLUTION;
720 	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
721 	s->opt[OPT_RESOLUTION].desc  = SANE_DESC_SCAN_RESOLUTION;
722 	s->opt[OPT_RESOLUTION].type  = SANE_TYPE_INT;
723 	s->opt[OPT_RESOLUTION].unit  = SANE_UNIT_DPI;
724 
725 	s->opt[OPT_RESOLUTION].constraint_type  = SANE_CONSTRAINT_RANGE;
726 	s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
727 	s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
728 
729 	/* custom-gamma table */
730   	s->opt[OPT_CUSTOM_GAMMA].name  = SANE_NAME_CUSTOM_GAMMA;
731   	s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
732   	s->opt[OPT_CUSTOM_GAMMA].desc  = SANE_DESC_CUSTOM_GAMMA;
733   	s->opt[OPT_CUSTOM_GAMMA].type  = SANE_TYPE_BOOL;
734   	s->val[OPT_CUSTOM_GAMMA].w     = SANE_FALSE;
735 
736 	/* preview */
737 	s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
738 	s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
739 	s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
740 	s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
741 	s->val[OPT_PREVIEW].w = 0;
742 
743 	/* "Geometry" group: */
744 	s->opt[OPT_GEOMETRY_GROUP].name  = "geometry-group";
745 	s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N("Geometry");
746 	s->opt[OPT_GEOMETRY_GROUP].desc  = "";
747 	s->opt[OPT_GEOMETRY_GROUP].type  = SANE_TYPE_GROUP;
748 	s->opt[OPT_GEOMETRY_GROUP].cap   = SANE_CAP_ADVANCED;
749 
750 	/* top-left x */
751 	s->opt[OPT_TL_X].name  = SANE_NAME_SCAN_TL_X;
752 	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
753 	s->opt[OPT_TL_X].desc  = SANE_DESC_SCAN_TL_X;
754 	s->opt[OPT_TL_X].type  = SANE_TYPE_FIXED;
755 	s->opt[OPT_TL_X].unit  = SANE_UNIT_MM;
756 	s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
757 	s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
758 	s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
759 
760 	/* top-left y */
761 	s->opt[OPT_TL_Y].name  = SANE_NAME_SCAN_TL_Y;
762 	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
763 	s->opt[OPT_TL_Y].desc  = SANE_DESC_SCAN_TL_Y;
764 	s->opt[OPT_TL_Y].type  = SANE_TYPE_FIXED;
765 	s->opt[OPT_TL_Y].unit  = SANE_UNIT_MM;
766 	s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
767 	s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
768 	s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
769 
770 	/* bottom-right x */
771 	s->opt[OPT_BR_X].name  = SANE_NAME_SCAN_BR_X;
772 	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
773 	s->opt[OPT_BR_X].desc  = SANE_DESC_SCAN_BR_X;
774 	s->opt[OPT_BR_X].type  = SANE_TYPE_FIXED;
775 	s->opt[OPT_BR_X].unit  = SANE_UNIT_MM;
776 	s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
777 	s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
778 	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
779 
780 	/* bottom-right y */
781 	s->opt[OPT_BR_Y].name  = SANE_NAME_SCAN_BR_Y;
782 	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
783 	s->opt[OPT_BR_Y].desc  = SANE_DESC_SCAN_BR_Y;
784 	s->opt[OPT_BR_Y].type  = SANE_TYPE_FIXED;
785 	s->opt[OPT_BR_Y].unit  = SANE_UNIT_MM;
786 	s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
787 	s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
788 	s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
789 
790 	/* "Enhancement" group: */
791 	s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement");
792 	s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
793 	s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
794 	s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
795 	s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
796 
797 	initGammaSettings( s );
798 
799  	/* grayscale gamma vector */
800   	s->opt[OPT_GAMMA_VECTOR].name  = SANE_NAME_GAMMA_VECTOR;
801   	s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
802   	s->opt[OPT_GAMMA_VECTOR].desc  = SANE_DESC_GAMMA_VECTOR;
803   	s->opt[OPT_GAMMA_VECTOR].type  = SANE_TYPE_INT;
804   	s->opt[OPT_GAMMA_VECTOR].unit  = SANE_UNIT_NONE;
805   	s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
806   	s->val[OPT_GAMMA_VECTOR].wa = &(s->gamma_table[0][0]);
807   	s->opt[OPT_GAMMA_VECTOR].constraint.range = &(s->gamma_range);
808   	s->opt[OPT_GAMMA_VECTOR].size = s->gamma_length * sizeof(SANE_Word);
809 
810 	/* red gamma vector */
811   	s->opt[OPT_GAMMA_VECTOR_R].name  = SANE_NAME_GAMMA_VECTOR_R;
812   	s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
813   	s->opt[OPT_GAMMA_VECTOR_R].desc  = SANE_DESC_GAMMA_VECTOR_R;
814   	s->opt[OPT_GAMMA_VECTOR_R].type  = SANE_TYPE_INT;
815   	s->opt[OPT_GAMMA_VECTOR_R].unit  = SANE_UNIT_NONE;
816   	s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
817   	s->val[OPT_GAMMA_VECTOR_R].wa = &(s->gamma_table[1][0]);
818   	s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(s->gamma_range);
819   	s->opt[OPT_GAMMA_VECTOR_R].size = s->gamma_length * sizeof(SANE_Word);
820 
821   	/* green gamma vector */
822   	s->opt[OPT_GAMMA_VECTOR_G].name  = SANE_NAME_GAMMA_VECTOR_G;
823   	s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
824   	s->opt[OPT_GAMMA_VECTOR_G].desc  = SANE_DESC_GAMMA_VECTOR_G;
825   	s->opt[OPT_GAMMA_VECTOR_G].type  = SANE_TYPE_INT;
826   	s->opt[OPT_GAMMA_VECTOR_G].unit  = SANE_UNIT_NONE;
827   	s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
828   	s->val[OPT_GAMMA_VECTOR_G].wa = &(s->gamma_table[2][0]);
829   	s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(s->gamma_range);
830   	s->opt[OPT_GAMMA_VECTOR_G].size = s->gamma_length * sizeof(SANE_Word);
831 
832   	/* blue gamma vector */
833   	s->opt[OPT_GAMMA_VECTOR_B].name  = SANE_NAME_GAMMA_VECTOR_B;
834   	s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
835   	s->opt[OPT_GAMMA_VECTOR_B].desc  = SANE_DESC_GAMMA_VECTOR_B;
836   	s->opt[OPT_GAMMA_VECTOR_B].type  = SANE_TYPE_INT;
837   	s->opt[OPT_GAMMA_VECTOR_B].unit  = SANE_UNIT_NONE;
838   	s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
839   	s->val[OPT_GAMMA_VECTOR_B].wa = &(s->gamma_table[3][0]);
840   	s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range);
841   	s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof(SANE_Word);
842 
843 	/* GAMMA stuff is disabled per default */
844     s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
845     s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
846     s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
847     s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
848 
849 	/* disable extended mode list for devices without TPA */
850 	if( 0 == (s->hw->caps.dwFlag & SFLAG_TPA)) {
851 		s->opt[OPT_EXT_MODE].cap |= SANE_CAP_INACTIVE;
852 	}
853 
854   	/* disable custom gamma, if not supported by the driver... */
855 	if( 0 == (s->hw->caps.dwFlag & SFLAG_CUSTOM_GAMMA)) {
856 	  	s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
857 	}
858 
859 	return SANE_STATUS_GOOD;
860 }
861 
862 #define _INT   0
863 #define _FLOAT 1
864 
865 /** function to decode an value and give it back to the caller.
866  * @param src    -  pointer to the source string to check
867  * @param opt    -  string that keeps the option name to check src for
868  * @param what   - _FLOAT or _INT
869  * @param result -  pointer to the var that should receive our result
870  * @param def    - default value that result should be in case of any error
871  * @return The function returns SANE_TRUE if the option has been found,
872  *         if not, it returns SANE_FALSE
873  */
decodeVal( char *src, char *opt, int what, void *result, void *def )874 static SANE_Bool decodeVal( char *src, char *opt,
875 							int what, void *result, void *def )
876 {
877 	char       *tmp, *tmp2;
878 	const char *name;
879 
880 	/* skip the option string */
881 	name = (const char*)&src[strlen("option")];
882 
883 	/* get the name of the option */
884 	name = sanei_config_get_string( name, &tmp );
885 
886 	if( tmp ) {
887 
888 		/* on success, compare with the given one */
889 		if( 0 == strcmp( tmp, opt )) {
890 
891 			DBG( _DBG_SANE_INIT, "Decoding option >%s<\n", opt );
892 
893 			if( _INT == what ) {
894 
895 				/* assign the default value for this option... */
896 				*((int*)result) = *((int*)def);
897 
898 				if( *name ) {
899 
900 					/* get the configuration value and decode it */
901 					name = sanei_config_get_string( name, &tmp2 );
902 
903 					if( tmp2 ) {
904 		      			*((int*)result) = strtol( tmp2, 0, 0 );
905 				    	free( tmp2 );
906 					}
907 				}
908 				free( tmp );
909 				return SANE_TRUE;
910 
911 			} else if( _FLOAT == what ) {
912 
913 				/* assign the default value for this option... */
914 				*((double*)result) = *((double*)def);
915 
916 				if( *name ) {
917 
918 					/* get the configuration value and decode it */
919 					name = sanei_config_get_string( name, &tmp2 );
920 
921 					if( tmp2 ) {
922 		      			*((double*)result) = strtod( tmp2, 0 );
923 				    	free( tmp2 );
924 					}
925 				}
926 				free( tmp );
927 				return SANE_TRUE;
928 			}
929 		}
930 		free( tmp );
931 	}
932 
933    	return SANE_FALSE;
934 }
935 
936 /** function to retrieve the device name of a given string
937  * @param src  -  string that keeps the option name to check src for
938  * @param dest -  pointer to the string, that should receive the detected
939  *                devicename
940  * @return The function returns SANE_TRUE if the devicename has been found,
941  *         if not, it returns SANE_FALSE
942  */
decodeDevName( char *src, char *dest )943 static SANE_Bool decodeDevName( char *src, char *dest )
944 {
945 	char       *tmp;
946 	const char *name;
947 
948 	if( 0 == strncmp( "device", src, 6 )) {
949 
950 		name = (const char*)&src[strlen("device")];
951 		name = sanei_config_skip_whitespace( name );
952 
953 		DBG( _DBG_SANE_INIT, "Decoding device name >%s<\n", name );
954 
955 		if( *name ) {
956 			name = sanei_config_get_string( name, &tmp );
957 			if( tmp ) {
958 
959 				strcpy( dest, tmp );
960 		    	free( tmp );
961 		    	return SANE_TRUE;
962 		    }
963 		}
964 	}
965 
966    	return SANE_FALSE;
967 }
968 
969 /** attach a device to the backend
970  */
attach( const char *dev_name, pCnfDef cnf, Plustek_Device **devp )971 static SANE_Status attach( const char *dev_name, pCnfDef cnf,
972 										                Plustek_Device **devp )
973 {
974 	int 		    cntr;
975 	int			    result;
976 	int			    handle;
977 	Plustek_Device *dev;
978 
979 	DBG( _DBG_SANE_INIT, "attach (%s, %p, %p)\n",
980 	                                      dev_name, (void *)cnf, (void *)devp);
981 
982 	/* already attached ?*/
983 	for( dev = first_dev; dev; dev = dev->next ) {
984 
985 		if( 0 == strcmp( dev->sane.name, dev_name )) {
986 			if( devp )
987         		*devp = dev;
988 
989     		return SANE_STATUS_GOOD;
990         }
991     }
992 
993 	/* allocate some memory for the device */
994 	dev = malloc( sizeof (*dev));
995 	if( NULL == dev )
996     	return SANE_STATUS_NO_MEM;
997 
998 	/* assign all the stuff we need for this device... */
999 
1000 	memset(dev, 0, sizeof (*dev));
1001 
1002 	dev->fd			 = -1;
1003     dev->name        = strdup(dev_name);    /* hold it double to avoid  */
1004 	dev->sane.name   = dev->name;           /* compiler warnings        */
1005 	dev->sane.vendor = "Plustek";
1006 	dev->initialized = -1;                  /* will be used as index too */
1007 
1008 	memcpy( &dev->adj, &cnf->adj, sizeof(AdjDef));
1009 
1010 	show_cnf( cnf );
1011 
1012 	dev->sane.type   = SANE_I18N ("flatbed scanner");
1013 	dev->open        = ppDev_open;
1014 	dev->close       = ppDev_close;
1015 	dev->getCaps     = ppDev_getCaps;
1016 	dev->getLensInfo = ppDev_getLensInfo;
1017 	dev->getCropInfo = ppDev_getCropInfo;
1018 	dev->putImgInfo  = ppDev_putImgInfo;
1019 	dev->setScanEnv  = ppDev_setScanEnv;
1020 	dev->startScan   = ppDev_startScan;
1021 	dev->stopScan    = ppDev_stopScan;
1022 	dev->setMap      = ppDev_setMap;
1023 	dev->readImage   = ppDev_readImage;
1024 	dev->shutdown    = NULL;
1025 	dev->readLine    = NULL;
1026 	dev->prepare     = NULL;
1027 
1028 	/*
1029 	 * go ahead and open the scanner device
1030 	 */
1031 	handle = drvopen( dev );
1032 	if( handle < 0 ) {
1033 		DBG( _DBG_ERROR,"open failed: %d\n", handle );
1034 		return SANE_STATUS_IO_ERROR;
1035     }
1036 
1037 	/* okay, so assign the handle... */
1038 	dev->fd = handle;
1039 
1040  	result = dev->getCaps( dev );
1041 	if( result < 0 ) {
1042 		DBG( _DBG_ERROR, "dev->getCaps() failed(%d)\n", result);
1043 		dev->close(dev);
1044 		return SANE_STATUS_IO_ERROR;
1045     }
1046 
1047 	result = dev->getLensInfo( dev, &lens );
1048 	if( result < 0 ) {
1049 		DBG( _DBG_ERROR, "dev->getLensInfo() failed(%d)\n", result );
1050 		dev->close(dev);
1051 		return SANE_STATUS_IO_ERROR;
1052 	}
1053 
1054 	/* did we fail on connection? */
1055 	if( _NO_BASE == dev->caps.wIOBase ) {
1056 		DBG( _DBG_ERROR, "failed to find Plustek scanner\n" );
1057 		dev->close(dev);
1058 		return SANE_STATUS_INVAL;
1059 	}
1060 
1061 	/* save the info we got from the driver */
1062 	DBG( _DBG_INFO, "Scanner information:\n" );
1063 	if( dev->caps.Model < MODEL_UNKNOWN ) {
1064 		dev->sane.model = ModelStr[dev->caps.Model];
1065 	} else {
1066 		dev->sane.model = ModelStr[0];
1067 	}
1068 
1069 	DBG( _DBG_INFO, "Vendor : %s\n",      dev->sane.vendor  );
1070 	DBG( _DBG_INFO, "Model  : %s\n",      dev->sane.model   );
1071 	DBG( _DBG_INFO, "Asic   : 0x%02x\n",  dev->caps.AsicID  );
1072 	DBG( _DBG_INFO, "Flags  : 0x%08lx\n", dev->caps.dwFlag  );
1073 
1074 	dev->max_x = dev->caps.wMaxExtentX*MM_PER_INCH/_MEASURE_BASE;
1075 	dev->max_y = dev->caps.wMaxExtentY*MM_PER_INCH/_MEASURE_BASE;
1076 
1077 	dev->res_list = (SANE_Int *)calloc(((lens.rDpiX.wMax -_DEF_DPI)/25 + 1),
1078 			     sizeof (SANE_Int));  /* one more to avoid a buffer overflow */
1079 
1080 	if (NULL == dev->res_list) {
1081 		DBG( _DBG_ERROR, "alloc fail, resolution problem\n" );
1082 		dev->close(dev);
1083 		return SANE_STATUS_INVAL;
1084 	}
1085 
1086 	/* build up the resolution table */
1087 	dev->res_list_size = 0;
1088 	for( cntr = _DEF_DPI; cntr <= lens.rDpiX.wMax; cntr += 25 ) {
1089 		dev->res_list_size++;
1090 		dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr;
1091 	}
1092 
1093 	limitResolution( dev );
1094 
1095 	dev->fd = handle;
1096 	drvclose( dev );
1097 
1098 	DBG( _DBG_SANE_INIT, "attach: model = >%s<\n", dev->sane.model );
1099 
1100 	++num_devices;
1101 	dev->next = first_dev;
1102 	first_dev = dev;
1103 
1104 	if (devp)
1105 		*devp = dev;
1106 
1107 	return SANE_STATUS_GOOD;
1108 }
1109 
1110 /** function to preset a configuration structure
1111  * @param cnf - pointer to the structure that should be initialized
1112  */
init_config_struct( pCnfDef cnf, SANE_Bool direct_io )1113 static void init_config_struct( pCnfDef cnf, SANE_Bool direct_io )
1114 {
1115     memset( cnf, 0, sizeof(CnfDef));
1116 
1117 	cnf->adj.direct_io    = direct_io;
1118 
1119 	cnf->adj.warmup       = -1;
1120 	cnf->adj.lampOff      = -1;
1121 	cnf->adj.lampOffOnEnd = -1;
1122 
1123 	cnf->adj.graygamma = 1.0;
1124 	cnf->adj.rgamma    = 1.0;
1125 	cnf->adj.ggamma    = 1.0;
1126 	cnf->adj.bgamma    = 1.0;
1127 }
1128 
1129 /** initialize the backend
1130  */
sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize )1131 SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize )
1132 {
1133 	char     str[PATH_MAX] = _DEFAULT_DEVICE;
1134     CnfDef   config;
1135 	size_t   len;
1136 	FILE    *fp;
1137 	SANE_Status res;
1138 
1139 	DBG_INIT();
1140 	sanei_thread_init();
1141 
1142 	res = sanei_pp_init();
1143 	if( SANE_STATUS_GOOD != res ) {
1144 		DBG( _DBG_ERROR, "Could not initialize Parport library!\n" );
1145 		return res;
1146 	}
1147 
1148 #if defined PACKAGE && defined VERSION
1149 	DBG( _DBG_SANE_INIT, "PlustekPP backend V"BACKEND_VERSION", part of "
1150 												 PACKAGE " " VERSION "\n");
1151 #else
1152 	DBG( _DBG_INFO, "PlustekPP backend V"BACKEND_VERSION"\n" );
1153 #endif
1154 
1155 	/* do some presettings... */
1156 	auth         = authorize;
1157 	first_dev    = NULL;
1158 	first_handle = NULL;
1159 	num_devices  = 0;
1160 
1161 	/* initialize the configuration structure */
1162 #ifdef _BACKEND_ENABLED
1163 	init_config_struct( &config, SANE_TRUE );
1164 #else
1165 	init_config_struct( &config, SANE_FALSE );
1166 #endif
1167 
1168 	if( version_code != NULL )
1169 		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
1170 
1171 	fp = sanei_config_open( PLUSTEK_CONFIG_FILE );
1172 
1173 	/* default to _DEFAULT_DEVICE instead of insisting on config file */
1174 	if( NULL == fp ) {
1175 		return attach( _DEFAULT_DEVICE, &config, 0 );
1176 	}
1177 
1178 	while( sanei_config_read( str, sizeof(str), fp)) {
1179 
1180 		DBG( _DBG_SANE_INIT, ">%s<\n", str );
1181 		if( str[0] == '#')		/* ignore line comments */
1182     		continue;
1183 
1184 		len = strlen(str);
1185 		if( 0 == len )
1186            	continue;			    /* ignore empty lines */
1187 
1188 		/* check for options */
1189 		if( 0 == strncmp(str, "option", 6)) {
1190 
1191 			int ival;
1192 
1193 			ival = -1;
1194 			decodeVal( str, "warmup",    _INT, &config.adj.warmup,      &ival);
1195 			decodeVal( str, "lampOff",   _INT, &config.adj.lampOff,     &ival);
1196 			decodeVal( str, "lOffOnEnd", _INT, &config.adj.lampOffOnEnd,&ival);
1197 
1198 			ival = 0;
1199 			decodeVal( str, "mov", _INT, &config.adj.mov, &ival );
1200 			continue;
1201 
1202 		/* check for sections: */
1203 		} else if( 0 == strncmp( str, "[direct]", 8)) {
1204 
1205 		    /* new section, try and attach previous device */
1206 		    if( config.devName[0] != '\0' )
1207 				attach( config.devName, &config, 0 );
1208 
1209 			/* re-initialize the configuration structure */
1210 			init_config_struct( &config, SANE_TRUE );
1211 			continue;
1212 
1213 		} else if( 0 == strncmp( str, "[kernel]", 8 )) {
1214 
1215 		    /* new section, try and attach previous device */
1216 		    if( config.devName[0] != '\0' )
1217 				attach( config.devName, &config, 0 );
1218 
1219 			/* re-initialize the configuration structure */
1220 			init_config_struct( &config, SANE_FALSE );
1221 			continue;
1222 
1223 		} else if( SANE_TRUE == decodeDevName( str, config.devName )) {
1224 			continue;
1225 		}
1226 
1227 		/* ignore other stuff... */
1228 		DBG( _DBG_SANE_INIT, "ignoring >%s<\n", str );
1229 	}
1230    	fclose (fp);
1231 
1232     /* try to attach the last device in the config file... */
1233     if( config.devName[0] != '\0' )
1234 		attach( config.devName, &config, 0 );
1235 
1236 	return SANE_STATUS_GOOD;
1237 }
1238 
1239 /** cleanup the backend...
1240  */
sane_exit( void )1241 void sane_exit( void )
1242 {
1243 	Plustek_Device *dev, *next;
1244 
1245 	DBG( _DBG_SANE_INIT, "sane_exit\n" );
1246 
1247 	for( dev = first_dev; dev; ) {
1248 
1249     	next = dev->next;
1250 
1251 		/* call the shutdown function of each device... */
1252 		if( dev->shutdown )
1253 			dev->shutdown( dev );
1254 
1255         /*
1256          * we're doin' this to avoid compiler warnings as dev->sane.name
1257          * is defined as const char*
1258          */
1259 		if( dev->sane.name )
1260 			free( dev->name );
1261 
1262         if( dev->res_list )
1263 			free( dev->res_list );
1264 		free( dev );
1265 
1266 		dev = next;
1267 	}
1268 
1269 	if( devlist )
1270     	free( devlist );
1271 
1272     /* call driver specific shutdown function... */
1273 	PtDrvShutdown();
1274 
1275     devlist      = NULL;
1276 	auth         = NULL;
1277 	first_dev    = NULL;
1278 	first_handle = NULL;
1279 }
1280 
1281 /** return a list of all devices
1282  */
sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only )1283 SANE_Status sane_get_devices(const SANE_Device ***device_list,
1284 														SANE_Bool local_only )
1285 {
1286 	int             i;
1287 	Plustek_Device *dev;
1288 
1289 	DBG(_DBG_SANE_INIT, "sane_get_devices (%p, %ld)\n",
1290                                        (void *)device_list, (long) local_only);
1291 
1292 	/* already called, so cleanup */
1293 	if( devlist )
1294     	free( devlist );
1295 
1296 	devlist = malloc((num_devices + 1) * sizeof (devlist[0]));
1297 	if ( NULL == devlist )
1298     	return SANE_STATUS_NO_MEM;
1299 
1300 	i = 0;
1301 	for (dev = first_dev; i < num_devices; dev = dev->next)
1302     	devlist[i++] = &dev->sane;
1303 	devlist[i++] = 0;
1304 
1305 	*device_list = devlist;
1306 	return SANE_STATUS_GOOD;
1307 }
1308 
1309 /** open the sane device
1310  */
sane_open( SANE_String_Const devicename, SANE_Handle* handle )1311 SANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle )
1312 {
1313 	SANE_Status      status;
1314 	Plustek_Device  *dev;
1315 	Plustek_Scanner *s;
1316     CnfDef           config;
1317 
1318 	DBG( _DBG_SANE_INIT, "sane_open - %s\n", devicename );
1319 
1320 	if( devicename[0] ) {
1321     	for( dev = first_dev; dev; dev = dev->next ) {
1322 			if( strcmp( dev->sane.name, devicename ) == 0 )
1323 				break;
1324         }
1325 
1326 		if( !dev ) {
1327 
1328 			memset( &config, 0, sizeof(CnfDef));
1329 
1330 			/* check if a valid parport-device is meant... */
1331 			status = attach( devicename, &config, &dev );
1332 			if( SANE_STATUS_GOOD != status )
1333 				return status;
1334 		}
1335 	} else {
1336 		/* empty devicename -> use first device */
1337 		dev = first_dev;
1338 	}
1339 
1340 	if( !dev )
1341     	return SANE_STATUS_INVAL;
1342 
1343 	s = malloc (sizeof (*s));
1344 	if( NULL == s )
1345     	return SANE_STATUS_NO_MEM;
1346 
1347 	memset(s, 0, sizeof (*s));
1348 	s->r_pipe   = -1;
1349 	s->w_pipe   = -1;
1350 	s->hw       = dev;
1351 	s->scanning = SANE_FALSE;
1352 
1353 	init_options(s);
1354 
1355 	/* insert newly opened handle into list of open handles: */
1356 	s->next      = first_handle;
1357 	first_handle = s;
1358 
1359 	*handle = s;
1360 
1361 	return SANE_STATUS_GOOD;
1362 }
1363 
1364 /**
1365  */
sane_close(SANE_Handle handle)1366 void sane_close (SANE_Handle handle)
1367 {
1368 	Plustek_Scanner *prev, *s;
1369 
1370 	DBG( _DBG_SANE_INIT, "sane_close\n" );
1371 
1372 	/* remove handle from list of open handles: */
1373 	prev = 0;
1374 
1375 	for( s = first_handle; s; s = s->next ) {
1376 		if( s == handle )
1377 			break;
1378 		prev = s;
1379 	}
1380 
1381 	if (!s) {
1382     	DBG( _DBG_ERROR, "close: invalid handle %p\n", handle);
1383 		return;
1384 	}
1385 
1386 	close_pipe( s );
1387 
1388 	if( NULL != s->buf )
1389 		free(s->buf);
1390 
1391 	drvclose( s->hw );
1392 
1393 	if (prev)
1394     	prev->next = s->next;
1395 	else
1396     	first_handle = s->next;
1397 
1398 	free(s);
1399 }
1400 
1401 /** goes through a string list and returns the start-address of the string
1402  * that has been found, or NULL on error
1403  */
search_string_list( const SANE_String_Const *list, SANE_String value )1404 static const SANE_String_Const *search_string_list(
1405                             const SANE_String_Const *list, SANE_String value )
1406 {
1407 	while( *list != NULL && strcmp(value, *list) != 0 )
1408 		++list;
1409 
1410 	if( *list == NULL )
1411 		return NULL;
1412 
1413 	return list;
1414 }
1415 
1416 /** return or set the parameter values, also do some checks
1417  */
sane_control_option( SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int * info)1418 SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option,
1419 							     SANE_Action action, void *value,
1420 							     SANE_Int * info)
1421 {
1422 	Plustek_Scanner         *s = (Plustek_Scanner *)handle;
1423 	SANE_Status              status;
1424 	const SANE_String_Const *optval;
1425 	pModeParam               mp;
1426 	int                      scanmode;
1427 
1428 	if ( s->scanning )
1429 		return SANE_STATUS_DEVICE_BUSY;
1430 
1431 	if((option < 0) || (option >= NUM_OPTIONS))
1432     	return SANE_STATUS_INVAL;
1433 
1434 	if( NULL != info )
1435 		*info = 0;
1436 
1437 	switch( action ) {
1438 
1439 		case SANE_ACTION_GET_VALUE:
1440 			switch (option) {
1441 			case OPT_PREVIEW:
1442 			case OPT_NUM_OPTS:
1443 			case OPT_RESOLUTION:
1444 			case OPT_TL_X:
1445 			case OPT_TL_Y:
1446 			case OPT_BR_X:
1447 			case OPT_BR_Y:
1448 			case OPT_CUSTOM_GAMMA:
1449 			  *(SANE_Word *)value = s->val[option].w;
1450 			  break;
1451 
1452 			case OPT_CONTRAST:
1453 			case OPT_BRIGHTNESS:
1454 				*(SANE_Word *)value =
1455 								(s->val[option].w << SANE_FIXED_SCALE_SHIFT);
1456 				break;
1457 
1458 			case OPT_MODE:
1459 			case OPT_EXT_MODE:
1460 			case OPT_HALFTONE:
1461 				strcpy ((char *) value,
1462 					  s->opt[option].constraint.string_list[s->val[option].w]);
1463 				break;
1464 
1465 	  		/* word array options: */
1466 	  		case OPT_GAMMA_VECTOR:
1467 			case OPT_GAMMA_VECTOR_R:
1468 			case OPT_GAMMA_VECTOR_G:
1469 			case OPT_GAMMA_VECTOR_B:
1470 				memcpy( value, s->val[option].wa, s->opt[option].size );
1471 				break;
1472 
1473 			default:
1474 				return SANE_STATUS_INVAL;
1475 		}
1476 		break;
1477 
1478     	case SANE_ACTION_SET_VALUE:
1479         	status = sanei_constrain_value( s->opt + option, value, info );
1480 		    if( SANE_STATUS_GOOD != status )
1481 			    return status;
1482 
1483     		optval = NULL;
1484 	    	if( SANE_CONSTRAINT_STRING_LIST == s->opt[option].constraint_type ) {
1485 
1486 		    	optval = search_string_list( s->opt[option].constraint.string_list,
1487 								         (char *) value);
1488     			if( NULL == optval )
1489 	        		return SANE_STATUS_INVAL;
1490 		    }
1491 
1492           	switch (option) {
1493 
1494 	    		case OPT_RESOLUTION: {
1495 		    	    int n;
1496 	    	    	int min_d = s->hw->res_list[s->hw->res_list_size - 1];
1497 			        int v     = *(SANE_Word *)value;
1498     	    		int best  = v;
1499 
1500 	    		    for( n = 0; n < s->hw->res_list_size; n++ ) {
1501 		    			int d = abs(v - s->hw->res_list[n]);
1502 
1503 					    if( d < min_d ) {
1504 				    	    min_d = d;
1505 				    	    best  = s->hw->res_list[n];
1506     					}
1507 	    			}
1508 
1509 	        		s->val[option].w = (SANE_Word)best;
1510 
1511                     if( v != best )
1512                         *(SANE_Word *)value = best;
1513 
1514 	    			if( NULL != info ) {
1515 		    			if( v != best )
1516                             *info |= SANE_INFO_INEXACT;
1517 				    	*info |= SANE_INFO_RELOAD_PARAMS;
1518          		  	}
1519 	    		    break;
1520 
1521 		      	}
1522 
1523 				case OPT_PREVIEW:
1524     			case OPT_TL_X:
1525 	    		case OPT_TL_Y:
1526 		    	case OPT_BR_X:
1527 			    case OPT_BR_Y:
1528     				s->val[option].w = *(SANE_Word *)value;
1529 	    			if( NULL != info )
1530     					*info |= SANE_INFO_RELOAD_PARAMS;
1531 	    			break;
1532 
1533 				case OPT_CUSTOM_GAMMA:
1534     				s->val[option].w = *(SANE_Word *)value;
1535 	    			if( NULL != info )
1536     					*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
1537 
1538 	    			mp       = getModeList( s );
1539 					scanmode = mp[s->val[OPT_MODE].w].scanmode;
1540 
1541 				    s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1542 				    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1543 				    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1544 				    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1545 
1546     				if( SANE_TRUE == s->val[option].w ) {
1547 
1548     					if((scanmode == COLOR_256GRAY) ||
1549 						   (scanmode == COLOR_GRAY16)) {
1550 						    s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1551 						} else {
1552 						    s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1553 						    s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1554 						    s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1555 						}
1556 
1557     				} else {
1558 
1559 						initGammaSettings( s );
1560 
1561     					if((scanmode == COLOR_256GRAY) ||
1562 						   (scanmode == COLOR_GRAY16)) {
1563 						    s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1564 						} else {
1565 						    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1566 						    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1567 						    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1568 						}
1569     				}
1570 	    			break;
1571 
1572 		    	case OPT_CONTRAST:
1573 			    case OPT_BRIGHTNESS:
1574         			s->val[option].w =
1575 							((*(SANE_Word *)value) >> SANE_FIXED_SCALE_SHIFT);
1576 	    			break;
1577 
1578 		    	case OPT_MODE: {
1579 
1580                     int idx = (optval - mode_list);
1581 
1582                 	if((_ASIC_IS_98001 == s->hw->caps.AsicID) ||
1583                                      (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
1584                         idx = optval - mode_9800x_list;
1585                     }
1586 
1587                		mp = getModeList( s );
1588 
1589 	    			if( mp[idx].scanmode != COLOR_HALFTONE ){
1590 		    			s->opt[OPT_HALFTONE].cap     |= SANE_CAP_INACTIVE;
1591 			    		s->opt[OPT_CONTRAST].cap     &= ~SANE_CAP_INACTIVE;
1592 			    		s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1593 				    } else {
1594 					    s->opt[OPT_HALFTONE].cap     &= ~SANE_CAP_INACTIVE;
1595     					s->opt[OPT_CONTRAST].cap     |= SANE_CAP_INACTIVE;
1596 			    		s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1597 	    			}
1598 
1599 	    			if( mp[idx].scanmode == COLOR_BW ) {
1600 			    		s->opt[OPT_CONTRAST].cap     |= SANE_CAP_INACTIVE;
1601 			    		s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1602 			    	}
1603 
1604 			    	s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1605 			    	s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1606 			    	s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1607 			    	s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1608 
1609 					if( s->val[OPT_CUSTOM_GAMMA].w &&
1610 			    		!(s->opt[OPT_CUSTOM_GAMMA].cap & SANE_CAP_INACTIVE)) {
1611 
1612     					if((mp[idx].scanmode == COLOR_256GRAY) ||
1613 						   (mp[idx].scanmode == COLOR_GRAY16)) {
1614 						    s->opt[OPT_GAMMA_VECTOR].cap   &= ~SANE_CAP_INACTIVE;
1615 						} else {
1616 					    	s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1617 					    	s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1618 					    	s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1619 						}
1620 					}
1621 
1622 			    	if( NULL != info )
1623     					*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1624                 }
1625 
1626                         // fall through
1627 	    		case OPT_HALFTONE:
1628 			    	s->val[option].w = optval - s->opt[option].constraint.string_list;
1629 				    break;
1630 
1631     			case OPT_EXT_MODE: {
1632 	    			s->val[option].w = optval - s->opt[option].constraint.string_list;
1633 
1634 		    		/*
1635 			    	 * change the area and mode_list when changing the source
1636 				     */
1637     				if( s->val[option].w == 0 ) {
1638 
1639 	    				s->hw->dpi_range.min = _DEF_DPI;
1640 
1641 		    			s->hw->x_range.max = SANE_FIX(s->hw->max_x);
1642 			    		s->hw->y_range.max = SANE_FIX(s->hw->max_y);
1643 				    	s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
1644 					    s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
1645    	    				s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
1646     					s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
1647 	    				s->val[OPT_MODE].w = 3;		/* COLOR_TRUE24 */
1648 
1649                     	if((_ASIC_IS_98001  == s->hw->caps.AsicID) ||
1650                            (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
1651 				    		s->opt[OPT_MODE].constraint.string_list = mode_9800x_list;
1652 						} else {
1653 						    s->opt[OPT_MODE].constraint.string_list = mode_list;
1654     					}
1655 
1656 				    } else {
1657 
1658 					    s->hw->dpi_range.min = _TPAMinDpi;
1659 
1660     					if( s->val[option].w == 1 ) {
1661         					s->hw->x_range.max = SANE_FIX(_TP_X);
1662 		    				s->hw->y_range.max = SANE_FIX(_TP_Y);
1663 			    			s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TP_TLX);
1664 				    		s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TP_TLY);
1665    					    	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_TP_BRX);
1666 						    s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_TP_BRY);
1667 
1668     					} else {
1669         					s->hw->x_range.max = SANE_FIX(_NEG_X);
1670 			    			s->hw->y_range.max = SANE_FIX(_NEG_Y);
1671 		    				s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_NEG_TLX);
1672 				    		s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_NEG_TLY);
1673    					    	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_NEG_BRX);
1674 						    s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_NEG_BRY);
1675     					}
1676 
1677 	    				if( s->hw->caps.dwFlag & SFLAG_TPA ) {
1678 
1679 		    				s->opt[OPT_MODE].constraint.string_list =
1680 											&mode_9800x_list[_TPAModeSupportMin];
1681         	    		} else {
1682 				    		s->opt[OPT_MODE].constraint.string_list =
1683 												&mode_list[_TPAModeSupportMin];
1684 					    }
1685  						s->val[OPT_MODE].w = 0;		/* COLOR_24 is the default */
1686         			}
1687 
1688 		    		s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
1689 				    s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1690 
1691     				if( NULL != info )
1692 	    				*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1693 		    		break;
1694 	            }
1695 				case OPT_GAMMA_VECTOR:
1696 				case OPT_GAMMA_VECTOR_R:
1697 				case OPT_GAMMA_VECTOR_G:
1698 				case OPT_GAMMA_VECTOR_B:
1699 					memcpy( s->val[option].wa, value, s->opt[option].size );
1700 					checkGammaSettings(s);
1701 	    			if( NULL != info )
1702 		    			*info |= SANE_INFO_RELOAD_PARAMS;
1703 		    		break;
1704 
1705 			    default:
1706 				    return SANE_STATUS_INVAL;
1707     		}
1708 	    	break;
1709 
1710 
1711     	default:
1712         	return SANE_STATUS_INVAL;
1713 	}
1714 
1715 	return SANE_STATUS_GOOD;
1716 }
1717 
1718 /** according to the option number, return a pointer to a descriptor
1719  */
1720 const SANE_Option_Descriptor *
sane_get_option_descriptor( SANE_Handle handle, SANE_Int option )1721    			 sane_get_option_descriptor( SANE_Handle handle, SANE_Int option )
1722 {
1723 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
1724 
1725 	if((option < 0) || (option >= NUM_OPTIONS))
1726 		return NULL;
1727 
1728 	return &(s->opt[option]);
1729 }
1730 
1731 /** return the current parameter settings
1732  */
sane_get_parameters( SANE_Handle handle, SANE_Parameters *params )1733 SANE_Status sane_get_parameters( SANE_Handle handle, SANE_Parameters *params )
1734 {
1735 	int    			 ndpi;
1736 	pModeParam  	 mp;
1737 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
1738 
1739 	/* if we're calling from within, calc best guess
1740      * do the same, if sane_get_parameters() is called
1741      * by a frontend before sane_start() is called
1742      */
1743     if((NULL == params) || (s->scanning != SANE_TRUE)) {
1744 
1745 		mp = getModeList( s );
1746 
1747 		memset( &s->params, 0, sizeof (SANE_Parameters));
1748 
1749 		ndpi = s->val[OPT_RESOLUTION].w;
1750 
1751 	    s->params.pixels_per_line =	SANE_UNFIX(s->val[OPT_BR_X].w -
1752 									  s->val[OPT_TL_X].w) / MM_PER_INCH * ndpi;
1753 
1754     	s->params.lines = SANE_UNFIX( s->val[OPT_BR_Y].w -
1755 									  s->val[OPT_TL_Y].w) / MM_PER_INCH * ndpi;
1756 
1757 		/* pixels_per_line seems to be 8 * n.  */
1758 		/* s->params.pixels_per_line = s->params.pixels_per_line & ~7; debug only */
1759 
1760 	    s->params.last_frame = SANE_TRUE;
1761     	s->params.depth      = mp[s->val[OPT_MODE].w].depth;
1762 
1763 		if( mp[s->val[OPT_MODE].w].color ) {
1764 			s->params.format = SANE_FRAME_RGB;
1765 			s->params.bytes_per_line = 3 * s->params.pixels_per_line;
1766 		} else {
1767 			s->params.format = SANE_FRAME_GRAY;
1768 			if (s->params.depth == 1)
1769 				s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
1770 			else
1771 				s->params.bytes_per_line = s->params.pixels_per_line *
1772 														   s->params.depth / 8;
1773 		}
1774 
1775         /* if sane_get_parameters() was called before sane_start() */
1776 	    /* pass new values to the caller                           */
1777     	if ((NULL != params) &&	(s->scanning != SANE_TRUE))
1778 	    	*params = s->params;
1779 	} else
1780 		*params = s->params;
1781 
1782 	return SANE_STATUS_GOOD;
1783 }
1784 
1785 /** initiate the scan process
1786  */
sane_start( SANE_Handle handle )1787 SANE_Status sane_start( SANE_Handle handle )
1788 {
1789 	Plustek_Scanner *s = (Plustek_Scanner *) handle;
1790 	pModeParam		 mp;
1791 
1792 	int			result;
1793 	int 		ndpi;
1794 	int 		left, top;
1795 	int 		width, height;
1796 	int			scanmode;
1797 	int         fds[2];
1798 	StartScan	start;
1799 	CropInfo	crop;
1800 	ScanInfo    sinfo;
1801 	SANE_Status status;
1802     SANE_Word   tmp;
1803 
1804 	DBG( _DBG_SANE_INIT, "sane_start\n" );
1805 
1806 	if( s->scanning ) {
1807 		return SANE_STATUS_DEVICE_BUSY;
1808 	}
1809 
1810 	status = sane_get_parameters (handle, NULL);
1811 	if (status != SANE_STATUS_GOOD) {
1812 		DBG( _DBG_ERROR, "sane_get_parameters failed\n" );
1813 		return status;
1814 	}
1815 
1816 	/*
1817 	 * open the driver and get some information about the scanner
1818 	 */
1819 	s->hw->fd = drvopen( s->hw );
1820 	if( s->hw->fd < 0 ) {
1821 		DBG( _DBG_ERROR,"sane_start: open failed: %d\n", errno );
1822 
1823 		if( errno == EBUSY )
1824 			return SANE_STATUS_DEVICE_BUSY;
1825 
1826 		return SANE_STATUS_IO_ERROR;
1827 	}
1828 
1829 	result = s->hw->getCaps( s->hw );
1830 	if( result < 0 ) {
1831 		DBG( _DBG_ERROR, "dev->getCaps() failed(%d)\n", result);
1832 		s->hw->close( s->hw );
1833 		return SANE_STATUS_IO_ERROR;
1834     }
1835 
1836 	result = s->hw->getLensInfo( s->hw, &lens );
1837 	if( result < 0 ) {
1838 		DBG( _DBG_ERROR, "dev->getLensInfo() failed(%d)\n", result );
1839 		s->hw->close( s->hw );
1840 		return SANE_STATUS_IO_ERROR;
1841     }
1842 
1843 	/* did we fail on connection? */
1844 	if ( s->hw->caps.wIOBase == _NO_BASE ) {
1845 		DBG( _DBG_ERROR, "failed to find Plustek scanner\n" );
1846 		s->hw->close( s->hw );
1847 		return SANE_STATUS_INVAL;
1848 	}
1849 
1850 	/* All ready to go.  Set image def and see what the scanner
1851 	 * says for crop info.
1852 	 */
1853 	ndpi = s->val[OPT_RESOLUTION].w;
1854 
1855     /* exchange the values as we can't deal with negative heights and so on...*/
1856     tmp = s->val[OPT_TL_X].w;
1857     if( tmp > s->val[OPT_BR_X].w ) {
1858 		DBG( _DBG_INFO, "exchanging BR-X - TL-X\n" );
1859         s->val[OPT_TL_X].w = s->val[OPT_BR_X].w;
1860         s->val[OPT_BR_X].w = tmp;
1861     }
1862 
1863     tmp = s->val[OPT_TL_Y].w;
1864     if( tmp > s->val[OPT_BR_Y].w ) {
1865 		DBG( _DBG_INFO, "exchanging BR-Y - TL-Y\n" );
1866         s->val[OPT_TL_Y].w = s->val[OPT_BR_Y].w;
1867         s->val[OPT_BR_Y].w = tmp;
1868     }
1869 
1870 	/* position and extent are always relative to 300 dpi */
1871 	left   = (int)(SANE_UNFIX (s->val[OPT_TL_X].w)*(double)lens.rDpiX.wPhyMax/
1872 							(MM_PER_INCH*((double)lens.rDpiX.wPhyMax/300.0)));
1873 	top    = (int)(SANE_UNFIX (s->val[OPT_TL_Y].w)*(double)lens.rDpiY.wPhyMax/
1874 							(MM_PER_INCH*((double)lens.rDpiY.wPhyMax/300.0)));
1875 	width  = (int)(SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) *
1876 					(double)lens.rDpiX.wPhyMax /
1877 							(MM_PER_INCH *((double)lens.rDpiX.wPhyMax/300.0)));
1878 	height = (int)(SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) *
1879 					(double)lens.rDpiY.wPhyMax /
1880 							(MM_PER_INCH *((double)lens.rDpiY.wPhyMax/300.0)));
1881 
1882 	/*
1883 	 * adjust mode list according to the model we use and the
1884 	 * source we have
1885 	 */
1886 	mp = getModeList( s );
1887 
1888 	scanmode = mp[s->val[OPT_MODE].w].scanmode;
1889 	DBG( _DBG_INFO, "scanmode = %u\n", scanmode );
1890 
1891 	/* clear it out just in case */
1892 	memset (&sinfo, 0, sizeof(sinfo));
1893 	sinfo.ImgDef.xyDpi.x   = ndpi;
1894 	sinfo.ImgDef.xyDpi.y   = ndpi;
1895 	sinfo.ImgDef.crArea.x  = left;  /* offset from left edge to area you want to scan */
1896 	sinfo.ImgDef.crArea.y  = top;  	/* offset from top edge to area you want to scan  */
1897 	sinfo.ImgDef.crArea.cx = width; /* always relative to 300 dpi */
1898 	sinfo.ImgDef.crArea.cy = height;
1899 	sinfo.ImgDef.wDataType = scanmode;
1900 
1901 /*
1902  * CHECK: what about the 10 bit mode?
1903  */
1904 #if 0
1905 	if( COLOR_TRUE48 == scanmode )
1906 		sinfo.ImgDef.wBits = OUTPUT_12Bits;
1907 	else if( COLOR_TRUE32 == scanmode )
1908 		sinfo.ImgDef.wBits = OUTPUT_10Bits;
1909 	else
1910 		sinfo.ImgDef.wBits = OUTPUT_8Bits;
1911 #endif
1912 	sinfo.ImgDef.dwFlag = SCANDEF_QualityScan;
1913 
1914 	switch( s->val[OPT_EXT_MODE].w ) {
1915 		case 1: sinfo.ImgDef.dwFlag |= SCANDEF_Transparency; break;
1916 		case 2: sinfo.ImgDef.dwFlag |= SCANDEF_Negative; 	 break;
1917 		default: break;
1918 	}
1919 
1920 	/* only for parallel-port devices */
1921 	if( s->hw->putImgInfo ) {
1922 		result = s->hw->putImgInfo( s->hw, &sinfo.ImgDef );
1923 		if( result < 0 ) {
1924 			DBG( _DBG_ERROR, "dev->putImgInfo failed(%d)\n", result );
1925 			s->hw->close( s->hw );
1926 			return SANE_STATUS_IO_ERROR;
1927 		}
1928 	} else {
1929 
1930 		memcpy( &(crop.ImgDef), &sinfo.ImgDef, sizeof(ImgDef));
1931 
1932 	}
1933 
1934 	result = s->hw->getCropInfo( s->hw, &crop );
1935 	if( result < 0 ) {
1936 	    DBG( _DBG_ERROR, "dev->getCropInfo() failed(%d)\n", result );
1937 		s->hw->close( s->hw );
1938     	return SANE_STATUS_IO_ERROR;
1939     }
1940 
1941 	/* DataInf.dwAppPixelsPerLine = crop.dwPixelsPerLine;  */
1942 	s->params.pixels_per_line = crop.dwPixelsPerLine;
1943 	s->params.bytes_per_line  = crop.dwBytesPerLine;
1944 	s->params.lines 		  = crop.dwLinesPerArea;
1945 
1946 	/* build a SCANINFO block and get ready to scan it */
1947 	sinfo.ImgDef.dwFlag |= (SCANDEF_BuildBwMap | SCANDEF_QualityScan);
1948 
1949     /* set adjustments for brightness and contrast */
1950 	sinfo.siBrightness = s->val[OPT_BRIGHTNESS].w;
1951 	sinfo.siContrast   = s->val[OPT_CONTRAST].w;
1952 	sinfo.wDither	   = s->val[OPT_HALFTONE].w;
1953 
1954 	DBG( _DBG_SANE_INIT, "bright %i contrast %i\n", sinfo.siBrightness,
1955    			 									       sinfo.siContrast);
1956 
1957 	result = s->hw->setScanEnv( s->hw, &sinfo );
1958 	if( result < 0 ) {
1959 		DBG( _DBG_ERROR, "dev->setEnv() failed(%d)\n", result );
1960 		s->hw->close( s->hw );
1961 		return SANE_STATUS_IO_ERROR;
1962     }
1963 
1964 	/* download gamma correction tables... */
1965 	if( scanmode <= COLOR_256GRAY || scanmode == COLOR_GRAY16 ) {
1966 	   	s->hw->setMap( s->hw, s->gamma_table[0], s->gamma_length, _MAP_MASTER);
1967 	} else {
1968 	   	s->hw->setMap( s->hw, s->gamma_table[1], s->gamma_length, _MAP_RED   );
1969    		s->hw->setMap( s->hw, s->gamma_table[2], s->gamma_length, _MAP_GREEN );
1970    		s->hw->setMap( s->hw, s->gamma_table[3], s->gamma_length, _MAP_BLUE  );
1971     }
1972 	/* work-around for USB... */
1973 	start.dwLinesPerScan = s->params.lines;
1974 
1975 	result = s->hw->startScan( s->hw, &start );
1976 	if( result < 0 ) {
1977 		DBG( _DBG_ERROR, "dev->startScan() failed(%d)\n", result );
1978 		s->hw->close( s->hw );
1979 		return SANE_STATUS_IO_ERROR;
1980     }
1981 
1982 	DBG( _DBG_SANE_INIT, "dwflag = 0x%lx dwBytesPerLine = %ld, "
1983 		 "dwLinesPerScan = %ld\n",
1984 					 start.dwFlag, start.dwBytesPerLine, start.dwLinesPerScan);
1985 
1986 	s->buf = realloc( s->buf, (s->params.lines) * s->params.bytes_per_line );
1987 	if( NULL == s->buf ) {
1988 		DBG( _DBG_ERROR, "realloc failed\n" );
1989 		s->hw->close( s->hw );
1990 		return SANE_STATUS_NO_MEM;
1991 	}
1992 
1993 	s->scanning = SANE_TRUE;
1994 
1995 	tsecs = (unsigned long)time(NULL);
1996 	DBG( _DBG_INFO, "TIME START\n" );
1997 
1998 	/*
1999 	 * everything prepared, so start the child process and a pipe to communicate
2000 	 * pipe --> fds[0]=read-fd, fds[1]=write-fd
2001 	 */
2002 	if( pipe(fds) < 0 ) {
2003 		DBG( _DBG_ERROR, "ERROR: could not create pipe\n" );
2004 	    s->scanning = SANE_FALSE;
2005 		s->hw->close( s->hw );
2006 		return SANE_STATUS_IO_ERROR;
2007 	}
2008 
2009 	/* create reader routine as new process */
2010 	s->bytes_read = 0;
2011 	s->r_pipe     = fds[0];
2012 	s->w_pipe     = fds[1];
2013 	s->reader_pid = sanei_thread_begin( reader_process, s );
2014 
2015 	if(!sanei_thread_is_valid( s->reader_pid )) {
2016 		DBG( _DBG_ERROR, "ERROR: could not create child process\n" );
2017 		s->scanning = SANE_FALSE;
2018 		s->hw->close( s->hw );
2019 		return SANE_STATUS_IO_ERROR;
2020 	}
2021 
2022 	/* reader_pid = 0 ===> child process */
2023 #if 0
2024 	if( 0 == s->reader_pid ) {
2025 
2026 		sigset_t 		 ignore_set;
2027 		struct SIGACTION act;
2028 
2029 		DBG( _DBG_SANE_INIT, "reader process...\n" );
2030 
2031 		close(fds[0]);
2032 
2033 		sigfillset ( &ignore_set );
2034 		sigdelset  ( &ignore_set, SIGTERM );
2035 		sigprocmask( SIG_SETMASK, &ignore_set, 0 );
2036 
2037 		memset   ( &act, 0, sizeof (act));
2038 		sigaction( SIGTERM, &act, 0 );
2039 
2040 		status = reader_process( s, fds[1] );
2041 
2042 		DBG( _DBG_SANE_INIT, "reader process done, status = %i\n", status );
2043 
2044 		/* don't use exit() since that would run the atexit() handlers */
2045 		_exit( status );
2046 	}
2047 #endif
2048 	signal( SIGCHLD, sig_chldhandler );
2049 
2050 	if( sanei_thread_is_forked()) {
2051 		close( s->w_pipe );
2052 		s->w_pipe = -1;
2053 	}
2054 
2055 	DBG( _DBG_SANE_INIT, "sane_start done\n" );
2056 
2057 	return SANE_STATUS_GOOD;
2058 }
2059 
2060 /** function to read the data from our child process
2061  */
sane_read( SANE_Handle handle, SANE_Byte *data, SANE_Int max_length, SANE_Int *length )2062 SANE_Status sane_read( SANE_Handle handle, SANE_Byte *data,
2063 									   SANE_Int max_length, SANE_Int *length )
2064 {
2065 	Plustek_Scanner *s = (Plustek_Scanner*)handle;
2066 	ssize_t 		 nread;
2067 
2068 	*length = 0;
2069 
2070 	/* here we read all data from the driver... */
2071 	nread = read( s->r_pipe, data, max_length );
2072 	DBG( _DBG_READ, "sane_read - read %ld bytes\n", (long)nread );
2073 	if (!(s->scanning)) {
2074 		return do_cancel( s, SANE_TRUE );
2075 	}
2076 
2077 	if( nread < 0 ) {
2078 
2079 		if( EAGAIN == errno ) {
2080 
2081             /* if we had already red the picture, so it's okay and stop */
2082 			if( s->bytes_read ==
2083 				(unsigned long)(s->params.lines * s->params.bytes_per_line)) {
2084 				sanei_thread_waitpid( s->reader_pid, 0 );
2085 				sanei_thread_invalidate( s->reader_pid );
2086 				drvclose( s->hw );
2087 				return close_pipe(s);
2088 			}
2089 
2090             /* else force the frontend to try again*/
2091 			return SANE_STATUS_GOOD;
2092 
2093 		} else {
2094 			DBG( _DBG_ERROR, "ERROR: errno=%d\n", errno );
2095 			do_cancel( s, SANE_TRUE );
2096 			return SANE_STATUS_IO_ERROR;
2097 		}
2098 	}
2099 
2100 	*length        = nread;
2101 	s->bytes_read += nread;
2102 
2103     /* nothing red means that we're finished OR we had a problem...*/
2104 	if( 0 == nread ) {
2105 
2106 		drvclose( s->hw );
2107 		s->exit_code = sanei_thread_get_status( s->reader_pid );
2108 
2109 		if( SANE_STATUS_GOOD != s->exit_code ) {
2110 			close_pipe(s);
2111 			return s->exit_code;
2112 		}
2113 		sanei_thread_invalidate( s->reader_pid );
2114 		return close_pipe(s);
2115 	}
2116 
2117 	return SANE_STATUS_GOOD;
2118 }
2119 
2120 /** cancel the scanning process
2121  */
sane_cancel(SANE_Handle handle)2122 void sane_cancel (SANE_Handle handle)
2123 {
2124 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2125 
2126 	DBG( _DBG_SANE_INIT, "sane_cancel\n" );
2127 
2128 	if( s->scanning )
2129 		do_cancel( s, SANE_FALSE );
2130 }
2131 
2132 /** set the pipe to blocking/non blocking mode
2133  */
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)2134 SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2135 {
2136 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2137 
2138 	DBG( _DBG_SANE_INIT, "sane_set_io_mode: non_blocking=%d\n",non_blocking );
2139 
2140 	if ( !s->scanning ) {
2141 		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2142 		return SANE_STATUS_INVAL;
2143 	}
2144 
2145 	if( -1 == s->r_pipe ) {
2146 		DBG( _DBG_ERROR, "ERROR: not supported !\n" );
2147 		return SANE_STATUS_UNSUPPORTED;
2148 	}
2149 
2150 	if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) {
2151 		DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" );
2152 		return SANE_STATUS_IO_ERROR;
2153 	}
2154 
2155 	DBG( _DBG_SANE_INIT, "sane_set_io_mode done\n" );
2156 	return SANE_STATUS_GOOD;
2157 }
2158 
2159 /** return the descriptor if available
2160  */
sane_get_select_fd( SANE_Handle handle, SANE_Int * fd )2161 SANE_Status sane_get_select_fd( SANE_Handle handle, SANE_Int * fd )
2162 {
2163 	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2164 
2165 	DBG( _DBG_SANE_INIT, "sane_get_select_fd\n" );
2166 
2167 	if( !s->scanning ) {
2168 		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2169 		return SANE_STATUS_INVAL;
2170 	}
2171 
2172 	*fd = s->r_pipe;
2173 
2174 	DBG( _DBG_SANE_INIT, "sane_get_select_fd done\n" );
2175 	return SANE_STATUS_GOOD;
2176 }
2177 
2178 /* END PLUSTEK_PP.C .........................................................*/
2179