1141cc406Sopenharmony_ci/** @file plustek_pp.c
2141cc406Sopenharmony_ci *  @brief SANE backend for Plustek parallelport scanner
3141cc406Sopenharmony_ci *
4141cc406Sopenharmony_ci * Based on Kazuhiro Sasayama previous work on
5141cc406Sopenharmony_ci * plustek.[ch] file from the SANE package.<br>
6141cc406Sopenharmony_ci * Original code taken from sane-0.71<br>
7141cc406Sopenharmony_ci * Copyright (C) 1997 Hypercore Software Design, Ltd.<br>
8141cc406Sopenharmony_ci * Also based on the work done by Rick Bronson<br>
9141cc406Sopenharmony_ci * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de><br>
10141cc406Sopenharmony_ci *
11141cc406Sopenharmony_ci * History:
12141cc406Sopenharmony_ci * - 0.01 - initial version, imported from the kernel-module 0.42-11
13141cc406Sopenharmony_ci * - 0.43 - bumped up version to reflect the former module code version
14141cc406Sopenharmony_ci * - 0.44 - bumped up version to reflect the recent changes
15141cc406Sopenharmony_ci *        - minor cleanup
16141cc406Sopenharmony_ci *.
17141cc406Sopenharmony_ci * <hr>
18141cc406Sopenharmony_ci * This file is part of the SANE package.
19141cc406Sopenharmony_ci *
20141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
21141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
22141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the
23141cc406Sopenharmony_ci * License, or (at your option) any later version.
24141cc406Sopenharmony_ci *
25141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
26141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
27141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28141cc406Sopenharmony_ci * General Public License for more details.
29141cc406Sopenharmony_ci *
30141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License
31141cc406Sopenharmony_ci * along with this program.  If not, see <https://www.gnu.org/licenses/>.
32141cc406Sopenharmony_ci *
33141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for
34141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE.
35141cc406Sopenharmony_ci *
36141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files
37141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the
38141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public
39141cc406Sopenharmony_ci * License.  Your use of that executable is in no way restricted on
40141cc406Sopenharmony_ci * account of linking the SANE library code into it.
41141cc406Sopenharmony_ci *
42141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why
43141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public
44141cc406Sopenharmony_ci * License.
45141cc406Sopenharmony_ci *
46141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in
47141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that
48141cc406Sopenharmony_ci * those changes may be distributed with this exception intact.
49141cc406Sopenharmony_ci *
50141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice
51141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications.
52141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice.
53141cc406Sopenharmony_ci * <hr>
54141cc406Sopenharmony_ci */
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci/** @mainpage
57141cc406Sopenharmony_ci *  @verbinclude Plustek-PARPORT.txt
58141cc406Sopenharmony_ci */
59141cc406Sopenharmony_ci
60141cc406Sopenharmony_ci#ifdef _AIX
61141cc406Sopenharmony_ci# include "../include/lalloca.h"  /* MUST come first for AIX! */
62141cc406Sopenharmony_ci#endif
63141cc406Sopenharmony_ci
64141cc406Sopenharmony_ci#include "../include/sane/config.h"
65141cc406Sopenharmony_ci#include "../include/lalloca.h"
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci#include <errno.h>
68141cc406Sopenharmony_ci#include <fcntl.h>
69141cc406Sopenharmony_ci#include <limits.h>
70141cc406Sopenharmony_ci#include <signal.h>
71141cc406Sopenharmony_ci#include <stdlib.h>
72141cc406Sopenharmony_ci#include <string.h>
73141cc406Sopenharmony_ci#include <ctype.h>
74141cc406Sopenharmony_ci#include <unistd.h>
75141cc406Sopenharmony_ci#include <time.h>
76141cc406Sopenharmony_ci#include <math.h>
77141cc406Sopenharmony_ci#include <stdint.h>
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci#include <sys/time.h>
80141cc406Sopenharmony_ci#include <sys/types.h>
81141cc406Sopenharmony_ci#include <sys/ioctl.h>
82141cc406Sopenharmony_ci
83141cc406Sopenharmony_ci#include "../include/sane/sane.h"
84141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
85141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci#define BACKEND_VERSION "0.44-1"
88141cc406Sopenharmony_ci#define BACKEND_NAME	plustek_pp
89141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
90141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
91141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
92141cc406Sopenharmony_ci#include "../include/sane/sanei_pp.h"
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_ci#define _BACKEND_ENABLED
95141cc406Sopenharmony_ci#define _USER_MODE
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci#include "plustek-pp.h"
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci/*********************** the debug levels ************************************/
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci#define _DBG_FATAL      0
102141cc406Sopenharmony_ci#define _DBG_ERROR      1
103141cc406Sopenharmony_ci#define _DBG_WARNING    3
104141cc406Sopenharmony_ci#define _DBG_INFO       5
105141cc406Sopenharmony_ci#define _DBG_PROC       7
106141cc406Sopenharmony_ci#define _DBG_SANE_INIT 10
107141cc406Sopenharmony_ci#define _DBG_INFO2     13
108141cc406Sopenharmony_ci#define _DBG_DUMP      20
109141cc406Sopenharmony_ci#define _DBG_READ      25
110141cc406Sopenharmony_ci
111141cc406Sopenharmony_ci/*****************************************************************************/
112141cc406Sopenharmony_ci
113141cc406Sopenharmony_ci/*
114141cc406Sopenharmony_ci * see plustek-share.h
115141cc406Sopenharmony_ci */
116141cc406Sopenharmony_ciMODELSTR;
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci#ifdef _BACKEND_ENABLED
119141cc406Sopenharmony_ci#ifndef NDEBUG
120141cc406Sopenharmony_ci# define DEBUG
121141cc406Sopenharmony_ci#endif
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci/* I know this is in general no good idea, but it works */
124141cc406Sopenharmony_ci# include "plustek-pp_io.c"
125141cc406Sopenharmony_ci# include "plustek-pp_dac.c"
126141cc406Sopenharmony_ci# include "plustek-pp_detect.c"
127141cc406Sopenharmony_ci# include "plustek-pp_genericio.c"
128141cc406Sopenharmony_ci# include "plustek-pp_image.c"
129141cc406Sopenharmony_ci# include "plustek-pp_map.c"
130141cc406Sopenharmony_ci# include "plustek-pp_misc.c"
131141cc406Sopenharmony_ci# include "plustek-pp_models.c"
132141cc406Sopenharmony_ci# include "plustek-pp_motor.c"
133141cc406Sopenharmony_ci# include "plustek-pp_p12.c"
134141cc406Sopenharmony_ci# include "plustek-pp_p12ccd.c"
135141cc406Sopenharmony_ci# include "plustek-pp_p48xx.c"
136141cc406Sopenharmony_ci# include "plustek-pp_p9636.c"
137141cc406Sopenharmony_ci# include "plustek-pp_procfs.c"
138141cc406Sopenharmony_ci# include "plustek-pp_scale.c"
139141cc406Sopenharmony_ci# include "plustek-pp_tpa.c"
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci#define _DEFAULT_DEVICE "0x378"
142141cc406Sopenharmony_ci#else
143141cc406Sopenharmony_ci#define _DEFAULT_DEVICE "/dev/pt_drv"
144141cc406Sopenharmony_ci#endif
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci#ifdef _BACKEND_ENABLED
147141cc406Sopenharmony_ci# include "plustek-pp_ptdrv.c"
148141cc406Sopenharmony_ci#endif
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci#include "plustek-pp_wrapper.c"
151141cc406Sopenharmony_ci
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci/************************** global vars **************************************/
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_cistatic int                 num_devices;
156141cc406Sopenharmony_cistatic Plustek_Device     *first_dev;
157141cc406Sopenharmony_cistatic Plustek_Scanner    *first_handle;
158141cc406Sopenharmony_cistatic const SANE_Device **devlist = 0;
159141cc406Sopenharmony_cistatic unsigned long       tsecs   = 0;
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_cistatic ModeParam mode_params[] =
162141cc406Sopenharmony_ci{
163141cc406Sopenharmony_ci  {0, 1, COLOR_BW},
164141cc406Sopenharmony_ci  {0, 1, COLOR_HALFTONE},
165141cc406Sopenharmony_ci  {0, 8, COLOR_256GRAY},
166141cc406Sopenharmony_ci  {1, 8, COLOR_TRUE24},
167141cc406Sopenharmony_ci  {1, 16, COLOR_TRUE32},
168141cc406Sopenharmony_ci  {1, 16, COLOR_TRUE36}
169141cc406Sopenharmony_ci};
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_cistatic ModeParam mode_9800x_params[] =
172141cc406Sopenharmony_ci{
173141cc406Sopenharmony_ci  {0, 1,  COLOR_BW},
174141cc406Sopenharmony_ci  {0, 1,  COLOR_HALFTONE},
175141cc406Sopenharmony_ci  {0, 8,  COLOR_256GRAY},
176141cc406Sopenharmony_ci  {1, 8,  COLOR_TRUE24},
177141cc406Sopenharmony_ci  {1, 16, COLOR_TRUE48}
178141cc406Sopenharmony_ci};
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_cistatic const SANE_String_Const mode_list[] =
181141cc406Sopenharmony_ci{
182141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_LINEART,
183141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_HALFTONE,
184141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_GRAY,
185141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_COLOR,
186141cc406Sopenharmony_ci	NULL
187141cc406Sopenharmony_ci};
188141cc406Sopenharmony_ci
189141cc406Sopenharmony_cistatic const SANE_String_Const mode_9800x_list[] =
190141cc406Sopenharmony_ci{
191141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_LINEART,
192141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_HALFTONE,
193141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_GRAY,
194141cc406Sopenharmony_ci	SANE_VALUE_SCAN_MODE_COLOR,
195141cc406Sopenharmony_ci	SANE_I18N("Color36"),
196141cc406Sopenharmony_ci	NULL
197141cc406Sopenharmony_ci};
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_cistatic const SANE_String_Const ext_mode_list[] =
200141cc406Sopenharmony_ci{
201141cc406Sopenharmony_ci	SANE_I18N("Normal"),
202141cc406Sopenharmony_ci	SANE_I18N("Transparency"),
203141cc406Sopenharmony_ci	SANE_I18N("Negative"),
204141cc406Sopenharmony_ci	NULL
205141cc406Sopenharmony_ci};
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_cistatic const SANE_String_Const halftone_list[] =
208141cc406Sopenharmony_ci{
209141cc406Sopenharmony_ci	SANE_I18N("Dithermap 1"),
210141cc406Sopenharmony_ci	SANE_I18N("Dithermap 2"),
211141cc406Sopenharmony_ci	SANE_I18N("Randomize"),
212141cc406Sopenharmony_ci	NULL
213141cc406Sopenharmony_ci};
214141cc406Sopenharmony_ci
215141cc406Sopenharmony_cistatic const SANE_Range percentage_range =
216141cc406Sopenharmony_ci{
217141cc406Sopenharmony_ci	SANE_FIX(-100),         /* minimum      */
218141cc406Sopenharmony_ci	SANE_FIX( 100),         /* maximum      */
219141cc406Sopenharmony_ci	SANE_FIX(   1)          /* quantization */
220141cc406Sopenharmony_ci};
221141cc406Sopenharmony_ci
222141cc406Sopenharmony_ci/*
223141cc406Sopenharmony_ci * lens info
224141cc406Sopenharmony_ci */
225141cc406Sopenharmony_cistatic LensInfo lens = {{0,0,0,0,},{0,0,0,0,},{0,0,0,0,},{0,0,0,0,},0,0};
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci/* authorization stuff */
228141cc406Sopenharmony_cistatic SANE_Auth_Callback auth = NULL;
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci/****************************** the backend... *******************************/
231141cc406Sopenharmony_ci
232141cc406Sopenharmony_ci#define _YN(x) (x?"yes":"no")
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci/**
235141cc406Sopenharmony_ci * function to display the configuration options for the current device
236141cc406Sopenharmony_ci * @param cnf - pointer to the configuration structure whose content should be
237141cc406Sopenharmony_ci *              displayed
238141cc406Sopenharmony_ci */
239141cc406Sopenharmony_cistatic void show_cnf( pCnfDef cnf )
240141cc406Sopenharmony_ci{
241141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"Device configuration:\n" );
242141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"device name   : >%s<\n", cnf->devName               );
243141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"direct I/O    : %s\n",   _YN(cnf->adj.direct_io    ));
244141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"warmup        : %ds\n",  cnf->adj.warmup            );
245141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"lampOff       : %d\n",   cnf->adj.lampOff           );
246141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"lampOffOnEnd  : %s\n",   _YN(cnf->adj.lampOffOnEnd ));
247141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"model override: %d\n",   cnf->adj.mov               );
248141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT,"---------------------\n" );
249141cc406Sopenharmony_ci}
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci/** open the device specific driver and reset the internal timing stuff
252141cc406Sopenharmony_ci * @param  dev - pointer to the device specific structure
253141cc406Sopenharmony_ci * @return the function returns the result of the open call, on success
254141cc406Sopenharmony_ci *         of course the handle
255141cc406Sopenharmony_ci */
256141cc406Sopenharmony_cistatic int drvopen(	Plustek_Device *dev )
257141cc406Sopenharmony_ci{
258141cc406Sopenharmony_ci	int handle;
259141cc406Sopenharmony_ci
260141cc406Sopenharmony_ci    DBG( _DBG_INFO, "drvopen()\n" );
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci	handle = dev->open((const char*)dev->name, (void *)dev );
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci	tsecs = 0;
265141cc406Sopenharmony_ci
266141cc406Sopenharmony_ci	return handle;
267141cc406Sopenharmony_ci}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ci/** Calls the device specific stop and close functions.
270141cc406Sopenharmony_ci * @param  dev - pointer to the device specific structure
271141cc406Sopenharmony_ci * @return The function always returns SANE_STATUS_GOOD
272141cc406Sopenharmony_ci */
273141cc406Sopenharmony_cistatic SANE_Status drvclose( Plustek_Device *dev )
274141cc406Sopenharmony_ci{
275141cc406Sopenharmony_ci	short int_cnt;
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci	if( dev->fd >= 0 ) {
278141cc406Sopenharmony_ci
279141cc406Sopenharmony_ci	    DBG( _DBG_INFO, "drvclose()\n" );
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci		if( 0 != tsecs ) {
282141cc406Sopenharmony_ci			DBG( _DBG_INFO, "TIME END 1: %lus\n", time(NULL)-tsecs);
283141cc406Sopenharmony_ci		}
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci		/*
286141cc406Sopenharmony_ci		 * don't check the return values, simply do it and close the driver
287141cc406Sopenharmony_ci		 */
288141cc406Sopenharmony_ci		int_cnt = 0;
289141cc406Sopenharmony_ci		dev->stopScan( dev, &int_cnt );
290141cc406Sopenharmony_ci		dev->close( dev );
291141cc406Sopenharmony_ci	}
292141cc406Sopenharmony_ci	dev->fd = -1;
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
295141cc406Sopenharmony_ci}
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci/** according to the mode and source we return the corresponding mode list
298141cc406Sopenharmony_ci */
299141cc406Sopenharmony_cistatic pModeParam getModeList( Plustek_Scanner *scanner )
300141cc406Sopenharmony_ci{
301141cc406Sopenharmony_ci	pModeParam mp;
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci	if((_ASIC_IS_98003 == scanner->hw->caps.AsicID) ||
304141cc406Sopenharmony_ci   	   (_ASIC_IS_98001 == scanner->hw->caps.AsicID)) {
305141cc406Sopenharmony_ci		mp = mode_9800x_params;
306141cc406Sopenharmony_ci	} else {
307141cc406Sopenharmony_ci		mp = mode_params;
308141cc406Sopenharmony_ci	}
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci	/*
311141cc406Sopenharmony_ci	 * the transparency/negative mode supports only GRAY/COLOR/COLOR32/COLOR48
312141cc406Sopenharmony_ci	 */
313141cc406Sopenharmony_ci	if( 0 != scanner->val[OPT_EXT_MODE].w ) {
314141cc406Sopenharmony_ci		mp = &mp[_TPAModeSupportMin];
315141cc406Sopenharmony_ci	}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci	return mp;
318141cc406Sopenharmony_ci}
319141cc406Sopenharmony_ci
320141cc406Sopenharmony_ci/**
321141cc406Sopenharmony_ci */
322141cc406Sopenharmony_cistatic SANE_Status close_pipe( Plustek_Scanner *scanner )
323141cc406Sopenharmony_ci{
324141cc406Sopenharmony_ci	if( scanner->r_pipe >= 0 ) {
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci		DBG( _DBG_PROC, "close r_pipe\n" );
327141cc406Sopenharmony_ci		close( scanner->r_pipe );
328141cc406Sopenharmony_ci		scanner->r_pipe = -1;
329141cc406Sopenharmony_ci	}
330141cc406Sopenharmony_ci	if( scanner->w_pipe >= 0 ) {
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci		DBG( _DBG_PROC, "close w_pipe\n" );
333141cc406Sopenharmony_ci		close( scanner->w_pipe );
334141cc406Sopenharmony_ci		scanner->w_pipe = -1;
335141cc406Sopenharmony_ci	}
336141cc406Sopenharmony_ci
337141cc406Sopenharmony_ci	return SANE_STATUS_EOF;
338141cc406Sopenharmony_ci}
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_ci/**
341141cc406Sopenharmony_ci */
342141cc406Sopenharmony_cistatic void sig_chldhandler( int signo )
343141cc406Sopenharmony_ci{
344141cc406Sopenharmony_ci	DBG( _DBG_PROC, "Child is down (signal=%d)\n", signo );
345141cc406Sopenharmony_ci}
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci/** signal handler to kill the child process
348141cc406Sopenharmony_ci */
349141cc406Sopenharmony_cistatic void reader_process_sigterm_handler( int signo )
350141cc406Sopenharmony_ci{
351141cc406Sopenharmony_ci	DBG( _DBG_PROC, "reader_process: terminated by signal %d\n", signo );
352141cc406Sopenharmony_ci	_exit( SANE_STATUS_GOOD );
353141cc406Sopenharmony_ci}
354141cc406Sopenharmony_ci
355141cc406Sopenharmony_cistatic void sigalarm_handler( int signo )
356141cc406Sopenharmony_ci{
357141cc406Sopenharmony_ci	_VAR_NOT_USED( signo );
358141cc406Sopenharmony_ci	DBG( _DBG_PROC, "ALARM!!!\n" );
359141cc406Sopenharmony_ci}
360141cc406Sopenharmony_ci
361141cc406Sopenharmony_ci/** executed as a child process
362141cc406Sopenharmony_ci * read the data from the driver and send them to the parent process
363141cc406Sopenharmony_ci */
364141cc406Sopenharmony_cistatic int reader_process( void *args )
365141cc406Sopenharmony_ci{
366141cc406Sopenharmony_ci	int              line;
367141cc406Sopenharmony_ci	unsigned long    status;
368141cc406Sopenharmony_ci	unsigned long    data_length;
369141cc406Sopenharmony_ci	struct SIGACTION act;
370141cc406Sopenharmony_ci	sigset_t         ignore_set;
371141cc406Sopenharmony_ci	Plustek_Scanner *scanner = (Plustek_Scanner *)args;
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci	if( sanei_thread_is_forked()) {
374141cc406Sopenharmony_ci		DBG( _DBG_PROC, "reader_process started (forked)\n" );
375141cc406Sopenharmony_ci		close( scanner->r_pipe );
376141cc406Sopenharmony_ci		scanner->r_pipe = -1;
377141cc406Sopenharmony_ci	} else {
378141cc406Sopenharmony_ci		DBG( _DBG_PROC, "reader_process started (as thread)\n" );
379141cc406Sopenharmony_ci	}
380141cc406Sopenharmony_ci
381141cc406Sopenharmony_ci	sigfillset ( &ignore_set );
382141cc406Sopenharmony_ci	sigdelset  ( &ignore_set, SIGTERM );
383141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__)
384141cc406Sopenharmony_ci	sigdelset  ( &ignore_set, SIGUSR2 );
385141cc406Sopenharmony_ci#endif
386141cc406Sopenharmony_ci	sigprocmask( SIG_SETMASK, &ignore_set, 0 );
387141cc406Sopenharmony_ci
388141cc406Sopenharmony_ci	memset   ( &act, 0, sizeof (act));
389141cc406Sopenharmony_ci	sigaction( SIGTERM, &act, 0 );
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci	/* install the signal handler */
392141cc406Sopenharmony_ci    sigemptyset(&(act.sa_mask));
393141cc406Sopenharmony_ci    act.sa_flags = 0;
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_ci	act.sa_handler = reader_process_sigterm_handler;
396141cc406Sopenharmony_ci	sigaction( SIGTERM, &act, 0 );
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci	data_length = scanner->params.lines * scanner->params.bytes_per_line;
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci	DBG( _DBG_PROC, "reader_process:"
401141cc406Sopenharmony_ci					"starting to READ data (%lu bytes)\n", data_length );
402141cc406Sopenharmony_ci	DBG( _DBG_PROC, "buf = 0x%08lx\n", (unsigned long)scanner->buf );
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci	if( NULL == scanner->buf ) {
405141cc406Sopenharmony_ci		DBG( _DBG_FATAL, "NULL Pointer !!!!\n" );
406141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
407141cc406Sopenharmony_ci	}
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci	/* here we read all data from the driver... */
410141cc406Sopenharmony_ci	if( scanner->hw->readImage ) {
411141cc406Sopenharmony_ci
412141cc406Sopenharmony_ci		status = (unsigned long)scanner->hw->readImage( scanner->hw,
413141cc406Sopenharmony_ci                                                    scanner->buf, data_length);
414141cc406Sopenharmony_ci	} else {
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci		unsigned char *buf = scanner->buf;
417141cc406Sopenharmony_ci
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci		status = scanner->hw->prepare( scanner->hw, buf );
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci        if( 0 == status ) {
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci			for( line = 0; line < scanner->params.lines; line++ ) {
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci				status = scanner->hw->readLine( scanner->hw );
426141cc406Sopenharmony_ci				if((int)status < 0 ) {
427141cc406Sopenharmony_ci					break;
428141cc406Sopenharmony_ci				}
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci			    write( scanner->w_pipe, buf, scanner->params.bytes_per_line );
431141cc406Sopenharmony_ci
432141cc406Sopenharmony_ci				buf += scanner->params.bytes_per_line;
433141cc406Sopenharmony_ci			}
434141cc406Sopenharmony_ci		}
435141cc406Sopenharmony_ci	}
436141cc406Sopenharmony_ci
437141cc406Sopenharmony_ci	/* on error, there's no need to clean up, as this is done by the parent */
438141cc406Sopenharmony_ci	if((int)status < 0 ) {
439141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "read failed, status = %i, errno %i\n",
440141cc406Sopenharmony_ci                                                          (int)status, errno );
441141cc406Sopenharmony_ci		if( -9009 == (int)status )
442141cc406Sopenharmony_ci			return SANE_STATUS_CANCELLED;
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci		if( errno == EBUSY )
445141cc406Sopenharmony_ci			return SANE_STATUS_DEVICE_BUSY;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
448141cc406Sopenharmony_ci    }
449141cc406Sopenharmony_ci
450141cc406Sopenharmony_ci	/* send to parent */
451141cc406Sopenharmony_ci	if( scanner->hw->readImage ) {
452141cc406Sopenharmony_ci		DBG( _DBG_PROC, "sending %lu bytes to parent\n", status );
453141cc406Sopenharmony_ci	    write( scanner->w_pipe, scanner->buf, status );
454141cc406Sopenharmony_ci	}
455141cc406Sopenharmony_ci
456141cc406Sopenharmony_ci	DBG( _DBG_PROC, "reader_process: finished reading data\n" );
457141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
458141cc406Sopenharmony_ci}
459141cc406Sopenharmony_ci
460141cc406Sopenharmony_ci/** stop the current scan process
461141cc406Sopenharmony_ci */
462141cc406Sopenharmony_cistatic SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe  )
463141cc406Sopenharmony_ci{
464141cc406Sopenharmony_ci	struct SIGACTION act;
465141cc406Sopenharmony_ci	SANE_Pid         res;
466141cc406Sopenharmony_ci	short            int_cnt;
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci	DBG( _DBG_PROC,"do_cancel\n" );
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_ci	scanner->scanning = SANE_FALSE;
471141cc406Sopenharmony_ci
472141cc406Sopenharmony_ci	if( sanei_thread_is_valid( scanner->reader_pid )) {
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci                DBG( _DBG_PROC, "---- killing reader_process ----\n" );
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci		/* tell the driver to stop scanning */
477141cc406Sopenharmony_ci		if( -1 != scanner->hw->fd ) {
478141cc406Sopenharmony_ci			int_cnt = 1;
479141cc406Sopenharmony_ci			scanner->hw->stopScan( scanner->hw, &int_cnt );
480141cc406Sopenharmony_ci		}
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci	    sigemptyset(&(act.sa_mask));
483141cc406Sopenharmony_ci    	act.sa_flags = 0;
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci		act.sa_handler = sigalarm_handler;
486141cc406Sopenharmony_ci		sigaction( SIGALRM, &act, 0 );
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci		/* kill our child process and wait until done */
489141cc406Sopenharmony_ci		sanei_thread_kill( scanner->reader_pid );
490141cc406Sopenharmony_ci
491141cc406Sopenharmony_ci		/* give'em 10 seconds 'til done...*/
492141cc406Sopenharmony_ci		alarm(10);
493141cc406Sopenharmony_ci		res = sanei_thread_waitpid( scanner->reader_pid, 0 );
494141cc406Sopenharmony_ci		alarm(0);
495141cc406Sopenharmony_ci
496141cc406Sopenharmony_ci		if( res != scanner->reader_pid ) {
497141cc406Sopenharmony_ci			DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n");
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci			/* do it the hard way...*/
500141cc406Sopenharmony_ci#ifdef USE_PTHREAD
501141cc406Sopenharmony_ci			sanei_thread_kill( scanner->reader_pid );
502141cc406Sopenharmony_ci#else
503141cc406Sopenharmony_ci			sanei_thread_sendsig( scanner->reader_pid, SIGKILL );
504141cc406Sopenharmony_ci#endif
505141cc406Sopenharmony_ci		}
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci		sanei_thread_invalidate( scanner->reader_pid );
508141cc406Sopenharmony_ci		DBG( _DBG_PROC,"reader_process killed\n");
509141cc406Sopenharmony_ci	}
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci	if( SANE_TRUE == closepipe ) {
512141cc406Sopenharmony_ci		close_pipe( scanner );
513141cc406Sopenharmony_ci	}
514141cc406Sopenharmony_ci
515141cc406Sopenharmony_ci	drvclose( scanner->hw );
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_ci	if( tsecs != 0 ) {
518141cc406Sopenharmony_ci		DBG( _DBG_INFO, "TIME END 2: %lus\n", time(NULL)-tsecs);
519141cc406Sopenharmony_ci		tsecs = 0;
520141cc406Sopenharmony_ci	}
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci	return SANE_STATUS_CANCELLED;
523141cc406Sopenharmony_ci}
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci/** because of some internal problems (inside the parport driver), we have to
526141cc406Sopenharmony_ci * limit the max resolution to optical resolution. This is done by this
527141cc406Sopenharmony_ci * function
528141cc406Sopenharmony_ci * @param  dev - pointer to the device specific structure
529141cc406Sopenharmony_ci * @return The function always returns SANE_STATUS_GOOD
530141cc406Sopenharmony_ci */
531141cc406Sopenharmony_cistatic void limitResolution( Plustek_Device *dev )
532141cc406Sopenharmony_ci{
533141cc406Sopenharmony_ci	dev->dpi_range.min = _DEF_DPI;
534141cc406Sopenharmony_ci 	if( dev->dpi_range.min < _DEF_DPI )
535141cc406Sopenharmony_ci		dev->dpi_range.min = _DEF_DPI;
536141cc406Sopenharmony_ci
537141cc406Sopenharmony_ci	/*
538141cc406Sopenharmony_ci	 * CHANGE: limit resolution to max. physical available one
539141cc406Sopenharmony_ci	 *		   Note: the resolution for the Asic 96001/3 models is limited to
540141cc406Sopenharmony_ci	 *               the X-Resolution
541141cc406Sopenharmony_ci	 */
542141cc406Sopenharmony_ci	if((_ASIC_IS_96003 == dev->caps.AsicID) ||
543141cc406Sopenharmony_ci       (_ASIC_IS_96001 == dev->caps.AsicID)) {
544141cc406Sopenharmony_ci		dev->dpi_range.max = lens.rDpiX.wPhyMax;
545141cc406Sopenharmony_ci	} else {
546141cc406Sopenharmony_ci		dev->dpi_range.max = lens.rDpiY.wPhyMax;
547141cc406Sopenharmony_ci	}
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci	dev->dpi_range.quant = 0;
550141cc406Sopenharmony_ci	dev->x_range.min 	 = 0;
551141cc406Sopenharmony_ci	dev->x_range.max 	 = SANE_FIX(dev->max_x);
552141cc406Sopenharmony_ci	dev->x_range.quant 	 = 0;
553141cc406Sopenharmony_ci	dev->y_range.min 	 = 0;
554141cc406Sopenharmony_ci	dev->y_range.max 	 = SANE_FIX(dev->max_y);
555141cc406Sopenharmony_ci	dev->y_range.quant 	 = 0;
556141cc406Sopenharmony_ci}
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci/** Currently we support only LM9831/2/3 chips and these use the same
559141cc406Sopenharmony_ci * sizes...
560141cc406Sopenharmony_ci * @param  s - pointer to the scanner specific structure
561141cc406Sopenharmony_ci * @return The function always returns SANE_STATUS_GOOD
562141cc406Sopenharmony_ci */
563141cc406Sopenharmony_cistatic SANE_Status initGammaSettings( Plustek_Scanner *s )
564141cc406Sopenharmony_ci{
565141cc406Sopenharmony_ci	int    i, j, val;
566141cc406Sopenharmony_ci	double gamma;
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci	/*
569141cc406Sopenharmony_ci     * this setting is common to the ASIC98001/3 and
570141cc406Sopenharmony_ci     * LM9831/2/3 based devices
571141cc406Sopenharmony_ci     * older parallelport devices use 256 entries
572141cc406Sopenharmony_ci     */
573141cc406Sopenharmony_ci	s->gamma_length      = 4096;
574141cc406Sopenharmony_ci  	s->gamma_range.min   = 0;
575141cc406Sopenharmony_ci  	s->gamma_range.max   = 255;
576141cc406Sopenharmony_ci  	s->gamma_range.quant = 0;
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci	if((_ASIC_IS_96003 == s->hw->caps.AsicID) ||
579141cc406Sopenharmony_ci       (_ASIC_IS_96001 == s->hw->caps.AsicID)) {
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci		s->gamma_length = 256;
582141cc406Sopenharmony_ci	}
583141cc406Sopenharmony_ci
584141cc406Sopenharmony_ci  	DBG( _DBG_INFO, "Presetting Gamma tables (len=%u)\n", s->gamma_length );
585141cc406Sopenharmony_ci  	DBG( _DBG_INFO, "----------------------------------\n" );
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ci  	/*
588141cc406Sopenharmony_ci  	 * preset the gamma maps
589141cc406Sopenharmony_ci  	 */
590141cc406Sopenharmony_ci  	for( i = 0; i < 4; i++ ) {
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci		switch( i ) {
593141cc406Sopenharmony_ci			case 1:  gamma = s->hw->adj.rgamma;    break;
594141cc406Sopenharmony_ci			case 2:  gamma = s->hw->adj.ggamma;    break;
595141cc406Sopenharmony_ci			case 3:  gamma = s->hw->adj.bgamma;    break;
596141cc406Sopenharmony_ci			default: gamma = s->hw->adj.graygamma; break;
597141cc406Sopenharmony_ci		}
598141cc406Sopenharmony_ci
599141cc406Sopenharmony_ci		for( j = 0; j < s->gamma_length; j++ ) {
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci			val = (s->gamma_range.max *
602141cc406Sopenharmony_ci					    pow((double) j / ((double)s->gamma_length - 1.0),
603141cc406Sopenharmony_ci						1.0 / gamma ));
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci			if( val > s->gamma_range.max )
606141cc406Sopenharmony_ci				val = s->gamma_range.max;
607141cc406Sopenharmony_ci
608141cc406Sopenharmony_ci			s->gamma_table[i][j] = val;
609141cc406Sopenharmony_ci		}
610141cc406Sopenharmony_ci	}
611141cc406Sopenharmony_ci
612141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
613141cc406Sopenharmony_ci}
614141cc406Sopenharmony_ci
615141cc406Sopenharmony_ci/** Check the gamma vectors we got back and limit if necessary
616141cc406Sopenharmony_ci * @param  s - pointer to the scanner specific structure
617141cc406Sopenharmony_ci * @return nothing
618141cc406Sopenharmony_ci */
619141cc406Sopenharmony_cistatic void checkGammaSettings( Plustek_Scanner *s )
620141cc406Sopenharmony_ci{
621141cc406Sopenharmony_ci	int i, j;
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci	for( i = 0; i < 4 ; i++ ) {
624141cc406Sopenharmony_ci		for( j = 0; j < s->gamma_length; j++ ) {
625141cc406Sopenharmony_ci			if( s->gamma_table[i][j] > s->gamma_range.max ) {
626141cc406Sopenharmony_ci				s->gamma_table[i][j] = s->gamma_range.max;
627141cc406Sopenharmony_ci			}
628141cc406Sopenharmony_ci		}
629141cc406Sopenharmony_ci	}
630141cc406Sopenharmony_ci}
631141cc406Sopenharmony_ci
632141cc406Sopenharmony_ci/** initialize the options for the backend according to the device we have
633141cc406Sopenharmony_ci */
634141cc406Sopenharmony_cistatic SANE_Status init_options( Plustek_Scanner *s )
635141cc406Sopenharmony_ci{
636141cc406Sopenharmony_ci	int i;
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci	memset( s->opt, 0, sizeof(s->opt));
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci	for( i = 0; i < NUM_OPTIONS; ++i ) {
641141cc406Sopenharmony_ci		s->opt[i].size = sizeof (SANE_Word);
642141cc406Sopenharmony_ci		s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
643141cc406Sopenharmony_ci	}
644141cc406Sopenharmony_ci
645141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].name  = SANE_NAME_NUM_OPTIONS;
646141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
647141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].desc  = SANE_DESC_NUM_OPTIONS;
648141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].type  = SANE_TYPE_INT;
649141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].unit  = SANE_UNIT_NONE;
650141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].cap   = SANE_CAP_SOFT_DETECT;
651141cc406Sopenharmony_ci	s->opt[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
652141cc406Sopenharmony_ci	s->val[OPT_NUM_OPTS].w 	   = NUM_OPTIONS;
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci	/* "Scan Mode" group: */
655141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].name  = "scanmode-group";
656141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].title = SANE_I18N("Scan Mode");
657141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].desc  = "";
658141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].type  = SANE_TYPE_GROUP;
659141cc406Sopenharmony_ci	s->opt[OPT_MODE_GROUP].cap   = 0;
660141cc406Sopenharmony_ci
661141cc406Sopenharmony_ci	/* scan mode */
662141cc406Sopenharmony_ci	s->opt[OPT_MODE].name  = SANE_NAME_SCAN_MODE;
663141cc406Sopenharmony_ci	s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
664141cc406Sopenharmony_ci	s->opt[OPT_MODE].desc  = SANE_DESC_SCAN_MODE;
665141cc406Sopenharmony_ci	s->opt[OPT_MODE].type  = SANE_TYPE_STRING;
666141cc406Sopenharmony_ci	s->opt[OPT_MODE].size  = 32;
667141cc406Sopenharmony_ci	s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_ci	if((_ASIC_IS_98001  == s->hw->caps.AsicID) ||
670141cc406Sopenharmony_ci	   (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
671141cc406Sopenharmony_ci		s->opt[OPT_MODE].constraint.string_list = mode_9800x_list;
672141cc406Sopenharmony_ci	} else {
673141cc406Sopenharmony_ci		s->opt[OPT_MODE].constraint.string_list = mode_list;
674141cc406Sopenharmony_ci	}
675141cc406Sopenharmony_ci	s->val[OPT_MODE].w = 3; /* Color */
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci	/* scan source */
678141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].name  = SANE_NAME_SCAN_SOURCE;
679141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].title = SANE_TITLE_SCAN_SOURCE;
680141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].desc  = SANE_DESC_SCAN_SOURCE;
681141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].type  = SANE_TYPE_STRING;
682141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].size  = 32;
683141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
684141cc406Sopenharmony_ci	s->opt[OPT_EXT_MODE].constraint.string_list = ext_mode_list;
685141cc406Sopenharmony_ci	s->val[OPT_EXT_MODE].w = 0; /* Normal */
686141cc406Sopenharmony_ci
687141cc406Sopenharmony_ci	/* halftone */
688141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].name  = SANE_NAME_HALFTONE_PATTERN;
689141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
690141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].desc  = SANE_DESC_HALFTONE_PATTERN;
691141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].type  = SANE_TYPE_STRING;
692141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].size  = 32;
693141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
694141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].constraint.string_list = halftone_list;
695141cc406Sopenharmony_ci	s->val[OPT_HALFTONE].w = 0;	/* Standard dithermap */
696141cc406Sopenharmony_ci	s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
697141cc406Sopenharmony_ci
698141cc406Sopenharmony_ci	/* brightness */
699141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].name  = SANE_NAME_BRIGHTNESS;
700141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
701141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].desc  = SANE_DESC_BRIGHTNESS;
702141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].type  = SANE_TYPE_FIXED;
703141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].unit  = SANE_UNIT_PERCENT;
704141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
705141cc406Sopenharmony_ci	s->opt[OPT_BRIGHTNESS].constraint.range = &percentage_range;
706141cc406Sopenharmony_ci	s->val[OPT_BRIGHTNESS].w     = 0;
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci	/* contrast */
709141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].name  = SANE_NAME_CONTRAST;
710141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
711141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].desc  = SANE_DESC_CONTRAST;
712141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].type  = SANE_TYPE_FIXED;
713141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].unit  = SANE_UNIT_PERCENT;
714141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
715141cc406Sopenharmony_ci	s->opt[OPT_CONTRAST].constraint.range = &percentage_range;
716141cc406Sopenharmony_ci	s->val[OPT_CONTRAST].w     = 0;
717141cc406Sopenharmony_ci
718141cc406Sopenharmony_ci	/* resolution */
719141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].name  = SANE_NAME_SCAN_RESOLUTION;
720141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
721141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].desc  = SANE_DESC_SCAN_RESOLUTION;
722141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].type  = SANE_TYPE_INT;
723141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].unit  = SANE_UNIT_DPI;
724141cc406Sopenharmony_ci
725141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].constraint_type  = SANE_CONSTRAINT_RANGE;
726141cc406Sopenharmony_ci	s->opt[OPT_RESOLUTION].constraint.range = &s->hw->dpi_range;
727141cc406Sopenharmony_ci	s->val[OPT_RESOLUTION].w = s->hw->dpi_range.min;
728141cc406Sopenharmony_ci
729141cc406Sopenharmony_ci	/* custom-gamma table */
730141cc406Sopenharmony_ci  	s->opt[OPT_CUSTOM_GAMMA].name  = SANE_NAME_CUSTOM_GAMMA;
731141cc406Sopenharmony_ci  	s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA;
732141cc406Sopenharmony_ci  	s->opt[OPT_CUSTOM_GAMMA].desc  = SANE_DESC_CUSTOM_GAMMA;
733141cc406Sopenharmony_ci  	s->opt[OPT_CUSTOM_GAMMA].type  = SANE_TYPE_BOOL;
734141cc406Sopenharmony_ci  	s->val[OPT_CUSTOM_GAMMA].w     = SANE_FALSE;
735141cc406Sopenharmony_ci
736141cc406Sopenharmony_ci	/* preview */
737141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
738141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
739141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
740141cc406Sopenharmony_ci	s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
741141cc406Sopenharmony_ci	s->val[OPT_PREVIEW].w = 0;
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci	/* "Geometry" group: */
744141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].name  = "geometry-group";
745141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N("Geometry");
746141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].desc  = "";
747141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].type  = SANE_TYPE_GROUP;
748141cc406Sopenharmony_ci	s->opt[OPT_GEOMETRY_GROUP].cap   = SANE_CAP_ADVANCED;
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci	/* top-left x */
751141cc406Sopenharmony_ci	s->opt[OPT_TL_X].name  = SANE_NAME_SCAN_TL_X;
752141cc406Sopenharmony_ci	s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
753141cc406Sopenharmony_ci	s->opt[OPT_TL_X].desc  = SANE_DESC_SCAN_TL_X;
754141cc406Sopenharmony_ci	s->opt[OPT_TL_X].type  = SANE_TYPE_FIXED;
755141cc406Sopenharmony_ci	s->opt[OPT_TL_X].unit  = SANE_UNIT_MM;
756141cc406Sopenharmony_ci	s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
757141cc406Sopenharmony_ci	s->opt[OPT_TL_X].constraint.range = &s->hw->x_range;
758141cc406Sopenharmony_ci	s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
759141cc406Sopenharmony_ci
760141cc406Sopenharmony_ci	/* top-left y */
761141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].name  = SANE_NAME_SCAN_TL_Y;
762141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
763141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].desc  = SANE_DESC_SCAN_TL_Y;
764141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].type  = SANE_TYPE_FIXED;
765141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].unit  = SANE_UNIT_MM;
766141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
767141cc406Sopenharmony_ci	s->opt[OPT_TL_Y].constraint.range = &s->hw->y_range;
768141cc406Sopenharmony_ci	s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
769141cc406Sopenharmony_ci
770141cc406Sopenharmony_ci	/* bottom-right x */
771141cc406Sopenharmony_ci	s->opt[OPT_BR_X].name  = SANE_NAME_SCAN_BR_X;
772141cc406Sopenharmony_ci	s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
773141cc406Sopenharmony_ci	s->opt[OPT_BR_X].desc  = SANE_DESC_SCAN_BR_X;
774141cc406Sopenharmony_ci	s->opt[OPT_BR_X].type  = SANE_TYPE_FIXED;
775141cc406Sopenharmony_ci	s->opt[OPT_BR_X].unit  = SANE_UNIT_MM;
776141cc406Sopenharmony_ci	s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
777141cc406Sopenharmony_ci	s->opt[OPT_BR_X].constraint.range = &s->hw->x_range;
778141cc406Sopenharmony_ci	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
779141cc406Sopenharmony_ci
780141cc406Sopenharmony_ci	/* bottom-right y */
781141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].name  = SANE_NAME_SCAN_BR_Y;
782141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
783141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].desc  = SANE_DESC_SCAN_BR_Y;
784141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].type  = SANE_TYPE_FIXED;
785141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].unit  = SANE_UNIT_MM;
786141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
787141cc406Sopenharmony_ci	s->opt[OPT_BR_Y].constraint.range = &s->hw->y_range;
788141cc406Sopenharmony_ci	s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
789141cc406Sopenharmony_ci
790141cc406Sopenharmony_ci	/* "Enhancement" group: */
791141cc406Sopenharmony_ci	s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement");
792141cc406Sopenharmony_ci	s->opt[OPT_ENHANCEMENT_GROUP].desc = "";
793141cc406Sopenharmony_ci	s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
794141cc406Sopenharmony_ci	s->opt[OPT_ENHANCEMENT_GROUP].cap = 0;
795141cc406Sopenharmony_ci	s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ci	initGammaSettings( s );
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci 	/* grayscale gamma vector */
800141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].name  = SANE_NAME_GAMMA_VECTOR;
801141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR;
802141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].desc  = SANE_DESC_GAMMA_VECTOR;
803141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].type  = SANE_TYPE_INT;
804141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].unit  = SANE_UNIT_NONE;
805141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].constraint_type = SANE_CONSTRAINT_RANGE;
806141cc406Sopenharmony_ci  	s->val[OPT_GAMMA_VECTOR].wa = &(s->gamma_table[0][0]);
807141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].constraint.range = &(s->gamma_range);
808141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR].size = s->gamma_length * sizeof(SANE_Word);
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci	/* red gamma vector */
811141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].name  = SANE_NAME_GAMMA_VECTOR_R;
812141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R;
813141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].desc  = SANE_DESC_GAMMA_VECTOR_R;
814141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].type  = SANE_TYPE_INT;
815141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].unit  = SANE_UNIT_NONE;
816141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].constraint_type = SANE_CONSTRAINT_RANGE;
817141cc406Sopenharmony_ci  	s->val[OPT_GAMMA_VECTOR_R].wa = &(s->gamma_table[1][0]);
818141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].constraint.range = &(s->gamma_range);
819141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_R].size = s->gamma_length * sizeof(SANE_Word);
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci  	/* green gamma vector */
822141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].name  = SANE_NAME_GAMMA_VECTOR_G;
823141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G;
824141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].desc  = SANE_DESC_GAMMA_VECTOR_G;
825141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].type  = SANE_TYPE_INT;
826141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].unit  = SANE_UNIT_NONE;
827141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].constraint_type = SANE_CONSTRAINT_RANGE;
828141cc406Sopenharmony_ci  	s->val[OPT_GAMMA_VECTOR_G].wa = &(s->gamma_table[2][0]);
829141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].constraint.range = &(s->gamma_range);
830141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_G].size = s->gamma_length * sizeof(SANE_Word);
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci  	/* blue gamma vector */
833141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].name  = SANE_NAME_GAMMA_VECTOR_B;
834141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B;
835141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].desc  = SANE_DESC_GAMMA_VECTOR_B;
836141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].type  = SANE_TYPE_INT;
837141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].unit  = SANE_UNIT_NONE;
838141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE;
839141cc406Sopenharmony_ci  	s->val[OPT_GAMMA_VECTOR_B].wa = &(s->gamma_table[3][0]);
840141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range);
841141cc406Sopenharmony_ci  	s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof(SANE_Word);
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci	/* GAMMA stuff is disabled per default */
844141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
845141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
846141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
847141cc406Sopenharmony_ci    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
848141cc406Sopenharmony_ci
849141cc406Sopenharmony_ci	/* disable extended mode list for devices without TPA */
850141cc406Sopenharmony_ci	if( 0 == (s->hw->caps.dwFlag & SFLAG_TPA)) {
851141cc406Sopenharmony_ci		s->opt[OPT_EXT_MODE].cap |= SANE_CAP_INACTIVE;
852141cc406Sopenharmony_ci	}
853141cc406Sopenharmony_ci
854141cc406Sopenharmony_ci  	/* disable custom gamma, if not supported by the driver... */
855141cc406Sopenharmony_ci	if( 0 == (s->hw->caps.dwFlag & SFLAG_CUSTOM_GAMMA)) {
856141cc406Sopenharmony_ci	  	s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
857141cc406Sopenharmony_ci	}
858141cc406Sopenharmony_ci
859141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
860141cc406Sopenharmony_ci}
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci#define _INT   0
863141cc406Sopenharmony_ci#define _FLOAT 1
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci/** function to decode an value and give it back to the caller.
866141cc406Sopenharmony_ci * @param src    -  pointer to the source string to check
867141cc406Sopenharmony_ci * @param opt    -  string that keeps the option name to check src for
868141cc406Sopenharmony_ci * @param what   - _FLOAT or _INT
869141cc406Sopenharmony_ci * @param result -  pointer to the var that should receive our result
870141cc406Sopenharmony_ci * @param def    - default value that result should be in case of any error
871141cc406Sopenharmony_ci * @return The function returns SANE_TRUE if the option has been found,
872141cc406Sopenharmony_ci *         if not, it returns SANE_FALSE
873141cc406Sopenharmony_ci */
874141cc406Sopenharmony_cistatic SANE_Bool decodeVal( char *src, char *opt,
875141cc406Sopenharmony_ci							int what, void *result, void *def )
876141cc406Sopenharmony_ci{
877141cc406Sopenharmony_ci	char       *tmp, *tmp2;
878141cc406Sopenharmony_ci	const char *name;
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci	/* skip the option string */
881141cc406Sopenharmony_ci	name = (const char*)&src[strlen("option")];
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci	/* get the name of the option */
884141cc406Sopenharmony_ci	name = sanei_config_get_string( name, &tmp );
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ci	if( tmp ) {
887141cc406Sopenharmony_ci
888141cc406Sopenharmony_ci		/* on success, compare with the given one */
889141cc406Sopenharmony_ci		if( 0 == strcmp( tmp, opt )) {
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci			DBG( _DBG_SANE_INIT, "Decoding option >%s<\n", opt );
892141cc406Sopenharmony_ci
893141cc406Sopenharmony_ci			if( _INT == what ) {
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci				/* assign the default value for this option... */
896141cc406Sopenharmony_ci				*((int*)result) = *((int*)def);
897141cc406Sopenharmony_ci
898141cc406Sopenharmony_ci				if( *name ) {
899141cc406Sopenharmony_ci
900141cc406Sopenharmony_ci					/* get the configuration value and decode it */
901141cc406Sopenharmony_ci					name = sanei_config_get_string( name, &tmp2 );
902141cc406Sopenharmony_ci
903141cc406Sopenharmony_ci					if( tmp2 ) {
904141cc406Sopenharmony_ci		      			*((int*)result) = strtol( tmp2, 0, 0 );
905141cc406Sopenharmony_ci				    	free( tmp2 );
906141cc406Sopenharmony_ci					}
907141cc406Sopenharmony_ci				}
908141cc406Sopenharmony_ci				free( tmp );
909141cc406Sopenharmony_ci				return SANE_TRUE;
910141cc406Sopenharmony_ci
911141cc406Sopenharmony_ci			} else if( _FLOAT == what ) {
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci				/* assign the default value for this option... */
914141cc406Sopenharmony_ci				*((double*)result) = *((double*)def);
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci				if( *name ) {
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci					/* get the configuration value and decode it */
919141cc406Sopenharmony_ci					name = sanei_config_get_string( name, &tmp2 );
920141cc406Sopenharmony_ci
921141cc406Sopenharmony_ci					if( tmp2 ) {
922141cc406Sopenharmony_ci		      			*((double*)result) = strtod( tmp2, 0 );
923141cc406Sopenharmony_ci				    	free( tmp2 );
924141cc406Sopenharmony_ci					}
925141cc406Sopenharmony_ci				}
926141cc406Sopenharmony_ci				free( tmp );
927141cc406Sopenharmony_ci				return SANE_TRUE;
928141cc406Sopenharmony_ci			}
929141cc406Sopenharmony_ci		}
930141cc406Sopenharmony_ci		free( tmp );
931141cc406Sopenharmony_ci	}
932141cc406Sopenharmony_ci
933141cc406Sopenharmony_ci   	return SANE_FALSE;
934141cc406Sopenharmony_ci}
935141cc406Sopenharmony_ci
936141cc406Sopenharmony_ci/** function to retrieve the device name of a given string
937141cc406Sopenharmony_ci * @param src  -  string that keeps the option name to check src for
938141cc406Sopenharmony_ci * @param dest -  pointer to the string, that should receive the detected
939141cc406Sopenharmony_ci *                devicename
940141cc406Sopenharmony_ci * @return The function returns SANE_TRUE if the devicename has been found,
941141cc406Sopenharmony_ci *         if not, it returns SANE_FALSE
942141cc406Sopenharmony_ci */
943141cc406Sopenharmony_cistatic SANE_Bool decodeDevName( char *src, char *dest )
944141cc406Sopenharmony_ci{
945141cc406Sopenharmony_ci	char       *tmp;
946141cc406Sopenharmony_ci	const char *name;
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci	if( 0 == strncmp( "device", src, 6 )) {
949141cc406Sopenharmony_ci
950141cc406Sopenharmony_ci		name = (const char*)&src[strlen("device")];
951141cc406Sopenharmony_ci		name = sanei_config_skip_whitespace( name );
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci		DBG( _DBG_SANE_INIT, "Decoding device name >%s<\n", name );
954141cc406Sopenharmony_ci
955141cc406Sopenharmony_ci		if( *name ) {
956141cc406Sopenharmony_ci			name = sanei_config_get_string( name, &tmp );
957141cc406Sopenharmony_ci			if( tmp ) {
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci				strcpy( dest, tmp );
960141cc406Sopenharmony_ci		    	free( tmp );
961141cc406Sopenharmony_ci		    	return SANE_TRUE;
962141cc406Sopenharmony_ci		    }
963141cc406Sopenharmony_ci		}
964141cc406Sopenharmony_ci	}
965141cc406Sopenharmony_ci
966141cc406Sopenharmony_ci   	return SANE_FALSE;
967141cc406Sopenharmony_ci}
968141cc406Sopenharmony_ci
969141cc406Sopenharmony_ci/** attach a device to the backend
970141cc406Sopenharmony_ci */
971141cc406Sopenharmony_cistatic SANE_Status attach( const char *dev_name, pCnfDef cnf,
972141cc406Sopenharmony_ci										                Plustek_Device **devp )
973141cc406Sopenharmony_ci{
974141cc406Sopenharmony_ci	int 		    cntr;
975141cc406Sopenharmony_ci	int			    result;
976141cc406Sopenharmony_ci	int			    handle;
977141cc406Sopenharmony_ci	Plustek_Device *dev;
978141cc406Sopenharmony_ci
979141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "attach (%s, %p, %p)\n",
980141cc406Sopenharmony_ci	                                      dev_name, (void *)cnf, (void *)devp);
981141cc406Sopenharmony_ci
982141cc406Sopenharmony_ci	/* already attached ?*/
983141cc406Sopenharmony_ci	for( dev = first_dev; dev; dev = dev->next ) {
984141cc406Sopenharmony_ci
985141cc406Sopenharmony_ci		if( 0 == strcmp( dev->sane.name, dev_name )) {
986141cc406Sopenharmony_ci			if( devp )
987141cc406Sopenharmony_ci        		*devp = dev;
988141cc406Sopenharmony_ci
989141cc406Sopenharmony_ci    		return SANE_STATUS_GOOD;
990141cc406Sopenharmony_ci        }
991141cc406Sopenharmony_ci    }
992141cc406Sopenharmony_ci
993141cc406Sopenharmony_ci	/* allocate some memory for the device */
994141cc406Sopenharmony_ci	dev = malloc( sizeof (*dev));
995141cc406Sopenharmony_ci	if( NULL == dev )
996141cc406Sopenharmony_ci    	return SANE_STATUS_NO_MEM;
997141cc406Sopenharmony_ci
998141cc406Sopenharmony_ci	/* assign all the stuff we need for this device... */
999141cc406Sopenharmony_ci
1000141cc406Sopenharmony_ci	memset(dev, 0, sizeof (*dev));
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci	dev->fd			 = -1;
1003141cc406Sopenharmony_ci    dev->name        = strdup(dev_name);    /* hold it double to avoid  */
1004141cc406Sopenharmony_ci	dev->sane.name   = dev->name;           /* compiler warnings        */
1005141cc406Sopenharmony_ci	dev->sane.vendor = "Plustek";
1006141cc406Sopenharmony_ci	dev->initialized = -1;                  /* will be used as index too */
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci	memcpy( &dev->adj, &cnf->adj, sizeof(AdjDef));
1009141cc406Sopenharmony_ci
1010141cc406Sopenharmony_ci	show_cnf( cnf );
1011141cc406Sopenharmony_ci
1012141cc406Sopenharmony_ci	dev->sane.type   = SANE_I18N ("flatbed scanner");
1013141cc406Sopenharmony_ci	dev->open        = ppDev_open;
1014141cc406Sopenharmony_ci	dev->close       = ppDev_close;
1015141cc406Sopenharmony_ci	dev->getCaps     = ppDev_getCaps;
1016141cc406Sopenharmony_ci	dev->getLensInfo = ppDev_getLensInfo;
1017141cc406Sopenharmony_ci	dev->getCropInfo = ppDev_getCropInfo;
1018141cc406Sopenharmony_ci	dev->putImgInfo  = ppDev_putImgInfo;
1019141cc406Sopenharmony_ci	dev->setScanEnv  = ppDev_setScanEnv;
1020141cc406Sopenharmony_ci	dev->startScan   = ppDev_startScan;
1021141cc406Sopenharmony_ci	dev->stopScan    = ppDev_stopScan;
1022141cc406Sopenharmony_ci	dev->setMap      = ppDev_setMap;
1023141cc406Sopenharmony_ci	dev->readImage   = ppDev_readImage;
1024141cc406Sopenharmony_ci	dev->shutdown    = NULL;
1025141cc406Sopenharmony_ci	dev->readLine    = NULL;
1026141cc406Sopenharmony_ci	dev->prepare     = NULL;
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci	/*
1029141cc406Sopenharmony_ci	 * go ahead and open the scanner device
1030141cc406Sopenharmony_ci	 */
1031141cc406Sopenharmony_ci	handle = drvopen( dev );
1032141cc406Sopenharmony_ci	if( handle < 0 ) {
1033141cc406Sopenharmony_ci		DBG( _DBG_ERROR,"open failed: %d\n", handle );
1034141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1035141cc406Sopenharmony_ci    }
1036141cc406Sopenharmony_ci
1037141cc406Sopenharmony_ci	/* okay, so assign the handle... */
1038141cc406Sopenharmony_ci	dev->fd = handle;
1039141cc406Sopenharmony_ci
1040141cc406Sopenharmony_ci 	result = dev->getCaps( dev );
1041141cc406Sopenharmony_ci	if( result < 0 ) {
1042141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->getCaps() failed(%d)\n", result);
1043141cc406Sopenharmony_ci		dev->close(dev);
1044141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1045141cc406Sopenharmony_ci    }
1046141cc406Sopenharmony_ci
1047141cc406Sopenharmony_ci	result = dev->getLensInfo( dev, &lens );
1048141cc406Sopenharmony_ci	if( result < 0 ) {
1049141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->getLensInfo() failed(%d)\n", result );
1050141cc406Sopenharmony_ci		dev->close(dev);
1051141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1052141cc406Sopenharmony_ci	}
1053141cc406Sopenharmony_ci
1054141cc406Sopenharmony_ci	/* did we fail on connection? */
1055141cc406Sopenharmony_ci	if( _NO_BASE == dev->caps.wIOBase ) {
1056141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "failed to find Plustek scanner\n" );
1057141cc406Sopenharmony_ci		dev->close(dev);
1058141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1059141cc406Sopenharmony_ci	}
1060141cc406Sopenharmony_ci
1061141cc406Sopenharmony_ci	/* save the info we got from the driver */
1062141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Scanner information:\n" );
1063141cc406Sopenharmony_ci	if( dev->caps.Model < MODEL_UNKNOWN ) {
1064141cc406Sopenharmony_ci		dev->sane.model = ModelStr[dev->caps.Model];
1065141cc406Sopenharmony_ci	} else {
1066141cc406Sopenharmony_ci		dev->sane.model = ModelStr[0];
1067141cc406Sopenharmony_ci	}
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Vendor : %s\n",      dev->sane.vendor  );
1070141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Model  : %s\n",      dev->sane.model   );
1071141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Asic   : 0x%02x\n",  dev->caps.AsicID  );
1072141cc406Sopenharmony_ci	DBG( _DBG_INFO, "Flags  : 0x%08lx\n", dev->caps.dwFlag  );
1073141cc406Sopenharmony_ci
1074141cc406Sopenharmony_ci	dev->max_x = dev->caps.wMaxExtentX*MM_PER_INCH/_MEASURE_BASE;
1075141cc406Sopenharmony_ci	dev->max_y = dev->caps.wMaxExtentY*MM_PER_INCH/_MEASURE_BASE;
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci	dev->res_list = (SANE_Int *)calloc(((lens.rDpiX.wMax -_DEF_DPI)/25 + 1),
1078141cc406Sopenharmony_ci			     sizeof (SANE_Int));  /* one more to avoid a buffer overflow */
1079141cc406Sopenharmony_ci
1080141cc406Sopenharmony_ci	if (NULL == dev->res_list) {
1081141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "alloc fail, resolution problem\n" );
1082141cc406Sopenharmony_ci		dev->close(dev);
1083141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1084141cc406Sopenharmony_ci	}
1085141cc406Sopenharmony_ci
1086141cc406Sopenharmony_ci	/* build up the resolution table */
1087141cc406Sopenharmony_ci	dev->res_list_size = 0;
1088141cc406Sopenharmony_ci	for( cntr = _DEF_DPI; cntr <= lens.rDpiX.wMax; cntr += 25 ) {
1089141cc406Sopenharmony_ci		dev->res_list_size++;
1090141cc406Sopenharmony_ci		dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr;
1091141cc406Sopenharmony_ci	}
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci	limitResolution( dev );
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci	dev->fd = handle;
1096141cc406Sopenharmony_ci	drvclose( dev );
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "attach: model = >%s<\n", dev->sane.model );
1099141cc406Sopenharmony_ci
1100141cc406Sopenharmony_ci	++num_devices;
1101141cc406Sopenharmony_ci	dev->next = first_dev;
1102141cc406Sopenharmony_ci	first_dev = dev;
1103141cc406Sopenharmony_ci
1104141cc406Sopenharmony_ci	if (devp)
1105141cc406Sopenharmony_ci		*devp = dev;
1106141cc406Sopenharmony_ci
1107141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1108141cc406Sopenharmony_ci}
1109141cc406Sopenharmony_ci
1110141cc406Sopenharmony_ci/** function to preset a configuration structure
1111141cc406Sopenharmony_ci * @param cnf - pointer to the structure that should be initialized
1112141cc406Sopenharmony_ci */
1113141cc406Sopenharmony_cistatic void init_config_struct( pCnfDef cnf, SANE_Bool direct_io )
1114141cc406Sopenharmony_ci{
1115141cc406Sopenharmony_ci    memset( cnf, 0, sizeof(CnfDef));
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci	cnf->adj.direct_io    = direct_io;
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci	cnf->adj.warmup       = -1;
1120141cc406Sopenharmony_ci	cnf->adj.lampOff      = -1;
1121141cc406Sopenharmony_ci	cnf->adj.lampOffOnEnd = -1;
1122141cc406Sopenharmony_ci
1123141cc406Sopenharmony_ci	cnf->adj.graygamma = 1.0;
1124141cc406Sopenharmony_ci	cnf->adj.rgamma    = 1.0;
1125141cc406Sopenharmony_ci	cnf->adj.ggamma    = 1.0;
1126141cc406Sopenharmony_ci	cnf->adj.bgamma    = 1.0;
1127141cc406Sopenharmony_ci}
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci/** initialize the backend
1130141cc406Sopenharmony_ci */
1131141cc406Sopenharmony_ciSANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize )
1132141cc406Sopenharmony_ci{
1133141cc406Sopenharmony_ci	char     str[PATH_MAX] = _DEFAULT_DEVICE;
1134141cc406Sopenharmony_ci    CnfDef   config;
1135141cc406Sopenharmony_ci	size_t   len;
1136141cc406Sopenharmony_ci	FILE    *fp;
1137141cc406Sopenharmony_ci	SANE_Status res;
1138141cc406Sopenharmony_ci
1139141cc406Sopenharmony_ci	DBG_INIT();
1140141cc406Sopenharmony_ci	sanei_thread_init();
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci	res = sanei_pp_init();
1143141cc406Sopenharmony_ci	if( SANE_STATUS_GOOD != res ) {
1144141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "Could not initialize Parport library!\n" );
1145141cc406Sopenharmony_ci		return res;
1146141cc406Sopenharmony_ci	}
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci#if defined PACKAGE && defined VERSION
1149141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "PlustekPP backend V"BACKEND_VERSION", part of "
1150141cc406Sopenharmony_ci												 PACKAGE " " VERSION "\n");
1151141cc406Sopenharmony_ci#else
1152141cc406Sopenharmony_ci	DBG( _DBG_INFO, "PlustekPP backend V"BACKEND_VERSION"\n" );
1153141cc406Sopenharmony_ci#endif
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci	/* do some presettings... */
1156141cc406Sopenharmony_ci	auth         = authorize;
1157141cc406Sopenharmony_ci	first_dev    = NULL;
1158141cc406Sopenharmony_ci	first_handle = NULL;
1159141cc406Sopenharmony_ci	num_devices  = 0;
1160141cc406Sopenharmony_ci
1161141cc406Sopenharmony_ci	/* initialize the configuration structure */
1162141cc406Sopenharmony_ci#ifdef _BACKEND_ENABLED
1163141cc406Sopenharmony_ci	init_config_struct( &config, SANE_TRUE );
1164141cc406Sopenharmony_ci#else
1165141cc406Sopenharmony_ci	init_config_struct( &config, SANE_FALSE );
1166141cc406Sopenharmony_ci#endif
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci	if( version_code != NULL )
1169141cc406Sopenharmony_ci		*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
1170141cc406Sopenharmony_ci
1171141cc406Sopenharmony_ci	fp = sanei_config_open( PLUSTEK_CONFIG_FILE );
1172141cc406Sopenharmony_ci
1173141cc406Sopenharmony_ci	/* default to _DEFAULT_DEVICE instead of insisting on config file */
1174141cc406Sopenharmony_ci	if( NULL == fp ) {
1175141cc406Sopenharmony_ci		return attach( _DEFAULT_DEVICE, &config, 0 );
1176141cc406Sopenharmony_ci	}
1177141cc406Sopenharmony_ci
1178141cc406Sopenharmony_ci	while( sanei_config_read( str, sizeof(str), fp)) {
1179141cc406Sopenharmony_ci
1180141cc406Sopenharmony_ci		DBG( _DBG_SANE_INIT, ">%s<\n", str );
1181141cc406Sopenharmony_ci		if( str[0] == '#')		/* ignore line comments */
1182141cc406Sopenharmony_ci    		continue;
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci		len = strlen(str);
1185141cc406Sopenharmony_ci		if( 0 == len )
1186141cc406Sopenharmony_ci           	continue;			    /* ignore empty lines */
1187141cc406Sopenharmony_ci
1188141cc406Sopenharmony_ci		/* check for options */
1189141cc406Sopenharmony_ci		if( 0 == strncmp(str, "option", 6)) {
1190141cc406Sopenharmony_ci
1191141cc406Sopenharmony_ci			int ival;
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci			ival = -1;
1194141cc406Sopenharmony_ci			decodeVal( str, "warmup",    _INT, &config.adj.warmup,      &ival);
1195141cc406Sopenharmony_ci			decodeVal( str, "lampOff",   _INT, &config.adj.lampOff,     &ival);
1196141cc406Sopenharmony_ci			decodeVal( str, "lOffOnEnd", _INT, &config.adj.lampOffOnEnd,&ival);
1197141cc406Sopenharmony_ci
1198141cc406Sopenharmony_ci			ival = 0;
1199141cc406Sopenharmony_ci			decodeVal( str, "mov", _INT, &config.adj.mov, &ival );
1200141cc406Sopenharmony_ci			continue;
1201141cc406Sopenharmony_ci
1202141cc406Sopenharmony_ci		/* check for sections: */
1203141cc406Sopenharmony_ci		} else if( 0 == strncmp( str, "[direct]", 8)) {
1204141cc406Sopenharmony_ci
1205141cc406Sopenharmony_ci		    /* new section, try and attach previous device */
1206141cc406Sopenharmony_ci		    if( config.devName[0] != '\0' )
1207141cc406Sopenharmony_ci				attach( config.devName, &config, 0 );
1208141cc406Sopenharmony_ci
1209141cc406Sopenharmony_ci			/* re-initialize the configuration structure */
1210141cc406Sopenharmony_ci			init_config_struct( &config, SANE_TRUE );
1211141cc406Sopenharmony_ci			continue;
1212141cc406Sopenharmony_ci
1213141cc406Sopenharmony_ci		} else if( 0 == strncmp( str, "[kernel]", 8 )) {
1214141cc406Sopenharmony_ci
1215141cc406Sopenharmony_ci		    /* new section, try and attach previous device */
1216141cc406Sopenharmony_ci		    if( config.devName[0] != '\0' )
1217141cc406Sopenharmony_ci				attach( config.devName, &config, 0 );
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_ci			/* re-initialize the configuration structure */
1220141cc406Sopenharmony_ci			init_config_struct( &config, SANE_FALSE );
1221141cc406Sopenharmony_ci			continue;
1222141cc406Sopenharmony_ci
1223141cc406Sopenharmony_ci		} else if( SANE_TRUE == decodeDevName( str, config.devName )) {
1224141cc406Sopenharmony_ci			continue;
1225141cc406Sopenharmony_ci		}
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci		/* ignore other stuff... */
1228141cc406Sopenharmony_ci		DBG( _DBG_SANE_INIT, "ignoring >%s<\n", str );
1229141cc406Sopenharmony_ci	}
1230141cc406Sopenharmony_ci   	fclose (fp);
1231141cc406Sopenharmony_ci
1232141cc406Sopenharmony_ci    /* try to attach the last device in the config file... */
1233141cc406Sopenharmony_ci    if( config.devName[0] != '\0' )
1234141cc406Sopenharmony_ci		attach( config.devName, &config, 0 );
1235141cc406Sopenharmony_ci
1236141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1237141cc406Sopenharmony_ci}
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci/** cleanup the backend...
1240141cc406Sopenharmony_ci */
1241141cc406Sopenharmony_civoid sane_exit( void )
1242141cc406Sopenharmony_ci{
1243141cc406Sopenharmony_ci	Plustek_Device *dev, *next;
1244141cc406Sopenharmony_ci
1245141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_exit\n" );
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci	for( dev = first_dev; dev; ) {
1248141cc406Sopenharmony_ci
1249141cc406Sopenharmony_ci    	next = dev->next;
1250141cc406Sopenharmony_ci
1251141cc406Sopenharmony_ci		/* call the shutdown function of each device... */
1252141cc406Sopenharmony_ci		if( dev->shutdown )
1253141cc406Sopenharmony_ci			dev->shutdown( dev );
1254141cc406Sopenharmony_ci
1255141cc406Sopenharmony_ci        /*
1256141cc406Sopenharmony_ci         * we're doin' this to avoid compiler warnings as dev->sane.name
1257141cc406Sopenharmony_ci         * is defined as const char*
1258141cc406Sopenharmony_ci         */
1259141cc406Sopenharmony_ci		if( dev->sane.name )
1260141cc406Sopenharmony_ci			free( dev->name );
1261141cc406Sopenharmony_ci
1262141cc406Sopenharmony_ci        if( dev->res_list )
1263141cc406Sopenharmony_ci			free( dev->res_list );
1264141cc406Sopenharmony_ci		free( dev );
1265141cc406Sopenharmony_ci
1266141cc406Sopenharmony_ci		dev = next;
1267141cc406Sopenharmony_ci	}
1268141cc406Sopenharmony_ci
1269141cc406Sopenharmony_ci	if( devlist )
1270141cc406Sopenharmony_ci    	free( devlist );
1271141cc406Sopenharmony_ci
1272141cc406Sopenharmony_ci    /* call driver specific shutdown function... */
1273141cc406Sopenharmony_ci	PtDrvShutdown();
1274141cc406Sopenharmony_ci
1275141cc406Sopenharmony_ci    devlist      = NULL;
1276141cc406Sopenharmony_ci	auth         = NULL;
1277141cc406Sopenharmony_ci	first_dev    = NULL;
1278141cc406Sopenharmony_ci	first_handle = NULL;
1279141cc406Sopenharmony_ci}
1280141cc406Sopenharmony_ci
1281141cc406Sopenharmony_ci/** return a list of all devices
1282141cc406Sopenharmony_ci */
1283141cc406Sopenharmony_ciSANE_Status sane_get_devices(const SANE_Device ***device_list,
1284141cc406Sopenharmony_ci														SANE_Bool local_only )
1285141cc406Sopenharmony_ci{
1286141cc406Sopenharmony_ci	int             i;
1287141cc406Sopenharmony_ci	Plustek_Device *dev;
1288141cc406Sopenharmony_ci
1289141cc406Sopenharmony_ci	DBG(_DBG_SANE_INIT, "sane_get_devices (%p, %ld)\n",
1290141cc406Sopenharmony_ci                                       (void *)device_list, (long) local_only);
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci	/* already called, so cleanup */
1293141cc406Sopenharmony_ci	if( devlist )
1294141cc406Sopenharmony_ci    	free( devlist );
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci	devlist = malloc((num_devices + 1) * sizeof (devlist[0]));
1297141cc406Sopenharmony_ci	if ( NULL == devlist )
1298141cc406Sopenharmony_ci    	return SANE_STATUS_NO_MEM;
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_ci	i = 0;
1301141cc406Sopenharmony_ci	for (dev = first_dev; i < num_devices; dev = dev->next)
1302141cc406Sopenharmony_ci    	devlist[i++] = &dev->sane;
1303141cc406Sopenharmony_ci	devlist[i++] = 0;
1304141cc406Sopenharmony_ci
1305141cc406Sopenharmony_ci	*device_list = devlist;
1306141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1307141cc406Sopenharmony_ci}
1308141cc406Sopenharmony_ci
1309141cc406Sopenharmony_ci/** open the sane device
1310141cc406Sopenharmony_ci */
1311141cc406Sopenharmony_ciSANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle )
1312141cc406Sopenharmony_ci{
1313141cc406Sopenharmony_ci	SANE_Status      status;
1314141cc406Sopenharmony_ci	Plustek_Device  *dev;
1315141cc406Sopenharmony_ci	Plustek_Scanner *s;
1316141cc406Sopenharmony_ci    CnfDef           config;
1317141cc406Sopenharmony_ci
1318141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_open - %s\n", devicename );
1319141cc406Sopenharmony_ci
1320141cc406Sopenharmony_ci	if( devicename[0] ) {
1321141cc406Sopenharmony_ci    	for( dev = first_dev; dev; dev = dev->next ) {
1322141cc406Sopenharmony_ci			if( strcmp( dev->sane.name, devicename ) == 0 )
1323141cc406Sopenharmony_ci				break;
1324141cc406Sopenharmony_ci        }
1325141cc406Sopenharmony_ci
1326141cc406Sopenharmony_ci		if( !dev ) {
1327141cc406Sopenharmony_ci
1328141cc406Sopenharmony_ci			memset( &config, 0, sizeof(CnfDef));
1329141cc406Sopenharmony_ci
1330141cc406Sopenharmony_ci			/* check if a valid parport-device is meant... */
1331141cc406Sopenharmony_ci			status = attach( devicename, &config, &dev );
1332141cc406Sopenharmony_ci			if( SANE_STATUS_GOOD != status )
1333141cc406Sopenharmony_ci				return status;
1334141cc406Sopenharmony_ci		}
1335141cc406Sopenharmony_ci	} else {
1336141cc406Sopenharmony_ci		/* empty devicename -> use first device */
1337141cc406Sopenharmony_ci		dev = first_dev;
1338141cc406Sopenharmony_ci	}
1339141cc406Sopenharmony_ci
1340141cc406Sopenharmony_ci	if( !dev )
1341141cc406Sopenharmony_ci    	return SANE_STATUS_INVAL;
1342141cc406Sopenharmony_ci
1343141cc406Sopenharmony_ci	s = malloc (sizeof (*s));
1344141cc406Sopenharmony_ci	if( NULL == s )
1345141cc406Sopenharmony_ci    	return SANE_STATUS_NO_MEM;
1346141cc406Sopenharmony_ci
1347141cc406Sopenharmony_ci	memset(s, 0, sizeof (*s));
1348141cc406Sopenharmony_ci	s->r_pipe   = -1;
1349141cc406Sopenharmony_ci	s->w_pipe   = -1;
1350141cc406Sopenharmony_ci	s->hw       = dev;
1351141cc406Sopenharmony_ci	s->scanning = SANE_FALSE;
1352141cc406Sopenharmony_ci
1353141cc406Sopenharmony_ci	init_options(s);
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci	/* insert newly opened handle into list of open handles: */
1356141cc406Sopenharmony_ci	s->next      = first_handle;
1357141cc406Sopenharmony_ci	first_handle = s;
1358141cc406Sopenharmony_ci
1359141cc406Sopenharmony_ci	*handle = s;
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1362141cc406Sopenharmony_ci}
1363141cc406Sopenharmony_ci
1364141cc406Sopenharmony_ci/**
1365141cc406Sopenharmony_ci */
1366141cc406Sopenharmony_civoid sane_close (SANE_Handle handle)
1367141cc406Sopenharmony_ci{
1368141cc406Sopenharmony_ci	Plustek_Scanner *prev, *s;
1369141cc406Sopenharmony_ci
1370141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_close\n" );
1371141cc406Sopenharmony_ci
1372141cc406Sopenharmony_ci	/* remove handle from list of open handles: */
1373141cc406Sopenharmony_ci	prev = 0;
1374141cc406Sopenharmony_ci
1375141cc406Sopenharmony_ci	for( s = first_handle; s; s = s->next ) {
1376141cc406Sopenharmony_ci		if( s == handle )
1377141cc406Sopenharmony_ci			break;
1378141cc406Sopenharmony_ci		prev = s;
1379141cc406Sopenharmony_ci	}
1380141cc406Sopenharmony_ci
1381141cc406Sopenharmony_ci	if (!s) {
1382141cc406Sopenharmony_ci    	DBG( _DBG_ERROR, "close: invalid handle %p\n", handle);
1383141cc406Sopenharmony_ci		return;
1384141cc406Sopenharmony_ci	}
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci	close_pipe( s );
1387141cc406Sopenharmony_ci
1388141cc406Sopenharmony_ci	if( NULL != s->buf )
1389141cc406Sopenharmony_ci		free(s->buf);
1390141cc406Sopenharmony_ci
1391141cc406Sopenharmony_ci	drvclose( s->hw );
1392141cc406Sopenharmony_ci
1393141cc406Sopenharmony_ci	if (prev)
1394141cc406Sopenharmony_ci    	prev->next = s->next;
1395141cc406Sopenharmony_ci	else
1396141cc406Sopenharmony_ci    	first_handle = s->next;
1397141cc406Sopenharmony_ci
1398141cc406Sopenharmony_ci	free(s);
1399141cc406Sopenharmony_ci}
1400141cc406Sopenharmony_ci
1401141cc406Sopenharmony_ci/** goes through a string list and returns the start-address of the string
1402141cc406Sopenharmony_ci * that has been found, or NULL on error
1403141cc406Sopenharmony_ci */
1404141cc406Sopenharmony_cistatic const SANE_String_Const *search_string_list(
1405141cc406Sopenharmony_ci                            const SANE_String_Const *list, SANE_String value )
1406141cc406Sopenharmony_ci{
1407141cc406Sopenharmony_ci	while( *list != NULL && strcmp(value, *list) != 0 )
1408141cc406Sopenharmony_ci		++list;
1409141cc406Sopenharmony_ci
1410141cc406Sopenharmony_ci	if( *list == NULL )
1411141cc406Sopenharmony_ci		return NULL;
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci	return list;
1414141cc406Sopenharmony_ci}
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci/** return or set the parameter values, also do some checks
1417141cc406Sopenharmony_ci */
1418141cc406Sopenharmony_ciSANE_Status sane_control_option( SANE_Handle handle, SANE_Int option,
1419141cc406Sopenharmony_ci							     SANE_Action action, void *value,
1420141cc406Sopenharmony_ci							     SANE_Int * info)
1421141cc406Sopenharmony_ci{
1422141cc406Sopenharmony_ci	Plustek_Scanner         *s = (Plustek_Scanner *)handle;
1423141cc406Sopenharmony_ci	SANE_Status              status;
1424141cc406Sopenharmony_ci	const SANE_String_Const *optval;
1425141cc406Sopenharmony_ci	pModeParam               mp;
1426141cc406Sopenharmony_ci	int                      scanmode;
1427141cc406Sopenharmony_ci
1428141cc406Sopenharmony_ci	if ( s->scanning )
1429141cc406Sopenharmony_ci		return SANE_STATUS_DEVICE_BUSY;
1430141cc406Sopenharmony_ci
1431141cc406Sopenharmony_ci	if((option < 0) || (option >= NUM_OPTIONS))
1432141cc406Sopenharmony_ci    	return SANE_STATUS_INVAL;
1433141cc406Sopenharmony_ci
1434141cc406Sopenharmony_ci	if( NULL != info )
1435141cc406Sopenharmony_ci		*info = 0;
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci	switch( action ) {
1438141cc406Sopenharmony_ci
1439141cc406Sopenharmony_ci		case SANE_ACTION_GET_VALUE:
1440141cc406Sopenharmony_ci			switch (option) {
1441141cc406Sopenharmony_ci			case OPT_PREVIEW:
1442141cc406Sopenharmony_ci			case OPT_NUM_OPTS:
1443141cc406Sopenharmony_ci			case OPT_RESOLUTION:
1444141cc406Sopenharmony_ci			case OPT_TL_X:
1445141cc406Sopenharmony_ci			case OPT_TL_Y:
1446141cc406Sopenharmony_ci			case OPT_BR_X:
1447141cc406Sopenharmony_ci			case OPT_BR_Y:
1448141cc406Sopenharmony_ci			case OPT_CUSTOM_GAMMA:
1449141cc406Sopenharmony_ci			  *(SANE_Word *)value = s->val[option].w;
1450141cc406Sopenharmony_ci			  break;
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_ci			case OPT_CONTRAST:
1453141cc406Sopenharmony_ci			case OPT_BRIGHTNESS:
1454141cc406Sopenharmony_ci				*(SANE_Word *)value =
1455141cc406Sopenharmony_ci								(s->val[option].w << SANE_FIXED_SCALE_SHIFT);
1456141cc406Sopenharmony_ci				break;
1457141cc406Sopenharmony_ci
1458141cc406Sopenharmony_ci			case OPT_MODE:
1459141cc406Sopenharmony_ci			case OPT_EXT_MODE:
1460141cc406Sopenharmony_ci			case OPT_HALFTONE:
1461141cc406Sopenharmony_ci				strcpy ((char *) value,
1462141cc406Sopenharmony_ci					  s->opt[option].constraint.string_list[s->val[option].w]);
1463141cc406Sopenharmony_ci				break;
1464141cc406Sopenharmony_ci
1465141cc406Sopenharmony_ci	  		/* word array options: */
1466141cc406Sopenharmony_ci	  		case OPT_GAMMA_VECTOR:
1467141cc406Sopenharmony_ci			case OPT_GAMMA_VECTOR_R:
1468141cc406Sopenharmony_ci			case OPT_GAMMA_VECTOR_G:
1469141cc406Sopenharmony_ci			case OPT_GAMMA_VECTOR_B:
1470141cc406Sopenharmony_ci				memcpy( value, s->val[option].wa, s->opt[option].size );
1471141cc406Sopenharmony_ci				break;
1472141cc406Sopenharmony_ci
1473141cc406Sopenharmony_ci			default:
1474141cc406Sopenharmony_ci				return SANE_STATUS_INVAL;
1475141cc406Sopenharmony_ci		}
1476141cc406Sopenharmony_ci		break;
1477141cc406Sopenharmony_ci
1478141cc406Sopenharmony_ci    	case SANE_ACTION_SET_VALUE:
1479141cc406Sopenharmony_ci        	status = sanei_constrain_value( s->opt + option, value, info );
1480141cc406Sopenharmony_ci		    if( SANE_STATUS_GOOD != status )
1481141cc406Sopenharmony_ci			    return status;
1482141cc406Sopenharmony_ci
1483141cc406Sopenharmony_ci    		optval = NULL;
1484141cc406Sopenharmony_ci	    	if( SANE_CONSTRAINT_STRING_LIST == s->opt[option].constraint_type ) {
1485141cc406Sopenharmony_ci
1486141cc406Sopenharmony_ci		    	optval = search_string_list( s->opt[option].constraint.string_list,
1487141cc406Sopenharmony_ci								         (char *) value);
1488141cc406Sopenharmony_ci    			if( NULL == optval )
1489141cc406Sopenharmony_ci	        		return SANE_STATUS_INVAL;
1490141cc406Sopenharmony_ci		    }
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_ci          	switch (option) {
1493141cc406Sopenharmony_ci
1494141cc406Sopenharmony_ci	    		case OPT_RESOLUTION: {
1495141cc406Sopenharmony_ci		    	    int n;
1496141cc406Sopenharmony_ci	    	    	int min_d = s->hw->res_list[s->hw->res_list_size - 1];
1497141cc406Sopenharmony_ci			        int v     = *(SANE_Word *)value;
1498141cc406Sopenharmony_ci    	    		int best  = v;
1499141cc406Sopenharmony_ci
1500141cc406Sopenharmony_ci	    		    for( n = 0; n < s->hw->res_list_size; n++ ) {
1501141cc406Sopenharmony_ci		    			int d = abs(v - s->hw->res_list[n]);
1502141cc406Sopenharmony_ci
1503141cc406Sopenharmony_ci					    if( d < min_d ) {
1504141cc406Sopenharmony_ci				    	    min_d = d;
1505141cc406Sopenharmony_ci				    	    best  = s->hw->res_list[n];
1506141cc406Sopenharmony_ci    					}
1507141cc406Sopenharmony_ci	    			}
1508141cc406Sopenharmony_ci
1509141cc406Sopenharmony_ci	        		s->val[option].w = (SANE_Word)best;
1510141cc406Sopenharmony_ci
1511141cc406Sopenharmony_ci                    if( v != best )
1512141cc406Sopenharmony_ci                        *(SANE_Word *)value = best;
1513141cc406Sopenharmony_ci
1514141cc406Sopenharmony_ci	    			if( NULL != info ) {
1515141cc406Sopenharmony_ci		    			if( v != best )
1516141cc406Sopenharmony_ci                            *info |= SANE_INFO_INEXACT;
1517141cc406Sopenharmony_ci				    	*info |= SANE_INFO_RELOAD_PARAMS;
1518141cc406Sopenharmony_ci         		  	}
1519141cc406Sopenharmony_ci	    		    break;
1520141cc406Sopenharmony_ci
1521141cc406Sopenharmony_ci		      	}
1522141cc406Sopenharmony_ci
1523141cc406Sopenharmony_ci				case OPT_PREVIEW:
1524141cc406Sopenharmony_ci    			case OPT_TL_X:
1525141cc406Sopenharmony_ci	    		case OPT_TL_Y:
1526141cc406Sopenharmony_ci		    	case OPT_BR_X:
1527141cc406Sopenharmony_ci			    case OPT_BR_Y:
1528141cc406Sopenharmony_ci    				s->val[option].w = *(SANE_Word *)value;
1529141cc406Sopenharmony_ci	    			if( NULL != info )
1530141cc406Sopenharmony_ci    					*info |= SANE_INFO_RELOAD_PARAMS;
1531141cc406Sopenharmony_ci	    			break;
1532141cc406Sopenharmony_ci
1533141cc406Sopenharmony_ci				case OPT_CUSTOM_GAMMA:
1534141cc406Sopenharmony_ci    				s->val[option].w = *(SANE_Word *)value;
1535141cc406Sopenharmony_ci	    			if( NULL != info )
1536141cc406Sopenharmony_ci    					*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
1537141cc406Sopenharmony_ci
1538141cc406Sopenharmony_ci	    			mp       = getModeList( s );
1539141cc406Sopenharmony_ci					scanmode = mp[s->val[OPT_MODE].w].scanmode;
1540141cc406Sopenharmony_ci
1541141cc406Sopenharmony_ci				    s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1542141cc406Sopenharmony_ci				    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1543141cc406Sopenharmony_ci				    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1544141cc406Sopenharmony_ci				    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci    				if( SANE_TRUE == s->val[option].w ) {
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci    					if((scanmode == COLOR_256GRAY) ||
1549141cc406Sopenharmony_ci						   (scanmode == COLOR_GRAY16)) {
1550141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE;
1551141cc406Sopenharmony_ci						} else {
1552141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1553141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1554141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1555141cc406Sopenharmony_ci						}
1556141cc406Sopenharmony_ci
1557141cc406Sopenharmony_ci    				} else {
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci						initGammaSettings( s );
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci    					if((scanmode == COLOR_256GRAY) ||
1562141cc406Sopenharmony_ci						   (scanmode == COLOR_GRAY16)) {
1563141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE;
1564141cc406Sopenharmony_ci						} else {
1565141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1566141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1567141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1568141cc406Sopenharmony_ci						}
1569141cc406Sopenharmony_ci    				}
1570141cc406Sopenharmony_ci	    			break;
1571141cc406Sopenharmony_ci
1572141cc406Sopenharmony_ci		    	case OPT_CONTRAST:
1573141cc406Sopenharmony_ci			    case OPT_BRIGHTNESS:
1574141cc406Sopenharmony_ci        			s->val[option].w =
1575141cc406Sopenharmony_ci							((*(SANE_Word *)value) >> SANE_FIXED_SCALE_SHIFT);
1576141cc406Sopenharmony_ci	    			break;
1577141cc406Sopenharmony_ci
1578141cc406Sopenharmony_ci		    	case OPT_MODE: {
1579141cc406Sopenharmony_ci
1580141cc406Sopenharmony_ci                    int idx = (optval - mode_list);
1581141cc406Sopenharmony_ci
1582141cc406Sopenharmony_ci                	if((_ASIC_IS_98001 == s->hw->caps.AsicID) ||
1583141cc406Sopenharmony_ci                                     (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
1584141cc406Sopenharmony_ci                        idx = optval - mode_9800x_list;
1585141cc406Sopenharmony_ci                    }
1586141cc406Sopenharmony_ci
1587141cc406Sopenharmony_ci               		mp = getModeList( s );
1588141cc406Sopenharmony_ci
1589141cc406Sopenharmony_ci	    			if( mp[idx].scanmode != COLOR_HALFTONE ){
1590141cc406Sopenharmony_ci		    			s->opt[OPT_HALFTONE].cap     |= SANE_CAP_INACTIVE;
1591141cc406Sopenharmony_ci			    		s->opt[OPT_CONTRAST].cap     &= ~SANE_CAP_INACTIVE;
1592141cc406Sopenharmony_ci			    		s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE;
1593141cc406Sopenharmony_ci				    } else {
1594141cc406Sopenharmony_ci					    s->opt[OPT_HALFTONE].cap     &= ~SANE_CAP_INACTIVE;
1595141cc406Sopenharmony_ci    					s->opt[OPT_CONTRAST].cap     |= SANE_CAP_INACTIVE;
1596141cc406Sopenharmony_ci			    		s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1597141cc406Sopenharmony_ci	    			}
1598141cc406Sopenharmony_ci
1599141cc406Sopenharmony_ci	    			if( mp[idx].scanmode == COLOR_BW ) {
1600141cc406Sopenharmony_ci			    		s->opt[OPT_CONTRAST].cap     |= SANE_CAP_INACTIVE;
1601141cc406Sopenharmony_ci			    		s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE;
1602141cc406Sopenharmony_ci			    	}
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci			    	s->opt[OPT_GAMMA_VECTOR].cap   |= SANE_CAP_INACTIVE;
1605141cc406Sopenharmony_ci			    	s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE;
1606141cc406Sopenharmony_ci			    	s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE;
1607141cc406Sopenharmony_ci			    	s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE;
1608141cc406Sopenharmony_ci
1609141cc406Sopenharmony_ci					if( s->val[OPT_CUSTOM_GAMMA].w &&
1610141cc406Sopenharmony_ci			    		!(s->opt[OPT_CUSTOM_GAMMA].cap & SANE_CAP_INACTIVE)) {
1611141cc406Sopenharmony_ci
1612141cc406Sopenharmony_ci    					if((mp[idx].scanmode == COLOR_256GRAY) ||
1613141cc406Sopenharmony_ci						   (mp[idx].scanmode == COLOR_GRAY16)) {
1614141cc406Sopenharmony_ci						    s->opt[OPT_GAMMA_VECTOR].cap   &= ~SANE_CAP_INACTIVE;
1615141cc406Sopenharmony_ci						} else {
1616141cc406Sopenharmony_ci					    	s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE;
1617141cc406Sopenharmony_ci					    	s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE;
1618141cc406Sopenharmony_ci					    	s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE;
1619141cc406Sopenharmony_ci						}
1620141cc406Sopenharmony_ci					}
1621141cc406Sopenharmony_ci
1622141cc406Sopenharmony_ci			    	if( NULL != info )
1623141cc406Sopenharmony_ci    					*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1624141cc406Sopenharmony_ci                }
1625141cc406Sopenharmony_ci
1626141cc406Sopenharmony_ci                        // fall through
1627141cc406Sopenharmony_ci	    		case OPT_HALFTONE:
1628141cc406Sopenharmony_ci			    	s->val[option].w = optval - s->opt[option].constraint.string_list;
1629141cc406Sopenharmony_ci				    break;
1630141cc406Sopenharmony_ci
1631141cc406Sopenharmony_ci    			case OPT_EXT_MODE: {
1632141cc406Sopenharmony_ci	    			s->val[option].w = optval - s->opt[option].constraint.string_list;
1633141cc406Sopenharmony_ci
1634141cc406Sopenharmony_ci		    		/*
1635141cc406Sopenharmony_ci			    	 * change the area and mode_list when changing the source
1636141cc406Sopenharmony_ci				     */
1637141cc406Sopenharmony_ci    				if( s->val[option].w == 0 ) {
1638141cc406Sopenharmony_ci
1639141cc406Sopenharmony_ci	    				s->hw->dpi_range.min = _DEF_DPI;
1640141cc406Sopenharmony_ci
1641141cc406Sopenharmony_ci		    			s->hw->x_range.max = SANE_FIX(s->hw->max_x);
1642141cc406Sopenharmony_ci			    		s->hw->y_range.max = SANE_FIX(s->hw->max_y);
1643141cc406Sopenharmony_ci				    	s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TLX);
1644141cc406Sopenharmony_ci					    s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TLY);
1645141cc406Sopenharmony_ci   	    				s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_BRX);
1646141cc406Sopenharmony_ci    					s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY);
1647141cc406Sopenharmony_ci	    				s->val[OPT_MODE].w = 3;		/* COLOR_TRUE24 */
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci                    	if((_ASIC_IS_98001  == s->hw->caps.AsicID) ||
1650141cc406Sopenharmony_ci                           (_ASIC_IS_98003  == s->hw->caps.AsicID)) {
1651141cc406Sopenharmony_ci				    		s->opt[OPT_MODE].constraint.string_list = mode_9800x_list;
1652141cc406Sopenharmony_ci						} else {
1653141cc406Sopenharmony_ci						    s->opt[OPT_MODE].constraint.string_list = mode_list;
1654141cc406Sopenharmony_ci    					}
1655141cc406Sopenharmony_ci
1656141cc406Sopenharmony_ci				    } else {
1657141cc406Sopenharmony_ci
1658141cc406Sopenharmony_ci					    s->hw->dpi_range.min = _TPAMinDpi;
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci    					if( s->val[option].w == 1 ) {
1661141cc406Sopenharmony_ci        					s->hw->x_range.max = SANE_FIX(_TP_X);
1662141cc406Sopenharmony_ci		    				s->hw->y_range.max = SANE_FIX(_TP_Y);
1663141cc406Sopenharmony_ci			    			s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_TP_TLX);
1664141cc406Sopenharmony_ci				    		s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_TP_TLY);
1665141cc406Sopenharmony_ci   					    	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_TP_BRX);
1666141cc406Sopenharmony_ci						    s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_TP_BRY);
1667141cc406Sopenharmony_ci
1668141cc406Sopenharmony_ci    					} else {
1669141cc406Sopenharmony_ci        					s->hw->x_range.max = SANE_FIX(_NEG_X);
1670141cc406Sopenharmony_ci			    			s->hw->y_range.max = SANE_FIX(_NEG_Y);
1671141cc406Sopenharmony_ci		    				s->val[OPT_TL_X].w = SANE_FIX(_DEFAULT_NEG_TLX);
1672141cc406Sopenharmony_ci				    		s->val[OPT_TL_Y].w = SANE_FIX(_DEFAULT_NEG_TLY);
1673141cc406Sopenharmony_ci   					    	s->val[OPT_BR_X].w = SANE_FIX(_DEFAULT_NEG_BRX);
1674141cc406Sopenharmony_ci						    s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_NEG_BRY);
1675141cc406Sopenharmony_ci    					}
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci	    				if( s->hw->caps.dwFlag & SFLAG_TPA ) {
1678141cc406Sopenharmony_ci
1679141cc406Sopenharmony_ci		    				s->opt[OPT_MODE].constraint.string_list =
1680141cc406Sopenharmony_ci											&mode_9800x_list[_TPAModeSupportMin];
1681141cc406Sopenharmony_ci        	    		} else {
1682141cc406Sopenharmony_ci				    		s->opt[OPT_MODE].constraint.string_list =
1683141cc406Sopenharmony_ci												&mode_list[_TPAModeSupportMin];
1684141cc406Sopenharmony_ci					    }
1685141cc406Sopenharmony_ci 						s->val[OPT_MODE].w = 0;		/* COLOR_24 is the default */
1686141cc406Sopenharmony_ci        			}
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci		    		s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
1689141cc406Sopenharmony_ci				    s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
1690141cc406Sopenharmony_ci
1691141cc406Sopenharmony_ci    				if( NULL != info )
1692141cc406Sopenharmony_ci	    				*info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
1693141cc406Sopenharmony_ci		    		break;
1694141cc406Sopenharmony_ci	            }
1695141cc406Sopenharmony_ci				case OPT_GAMMA_VECTOR:
1696141cc406Sopenharmony_ci				case OPT_GAMMA_VECTOR_R:
1697141cc406Sopenharmony_ci				case OPT_GAMMA_VECTOR_G:
1698141cc406Sopenharmony_ci				case OPT_GAMMA_VECTOR_B:
1699141cc406Sopenharmony_ci					memcpy( s->val[option].wa, value, s->opt[option].size );
1700141cc406Sopenharmony_ci					checkGammaSettings(s);
1701141cc406Sopenharmony_ci	    			if( NULL != info )
1702141cc406Sopenharmony_ci		    			*info |= SANE_INFO_RELOAD_PARAMS;
1703141cc406Sopenharmony_ci		    		break;
1704141cc406Sopenharmony_ci
1705141cc406Sopenharmony_ci			    default:
1706141cc406Sopenharmony_ci				    return SANE_STATUS_INVAL;
1707141cc406Sopenharmony_ci    		}
1708141cc406Sopenharmony_ci	    	break;
1709141cc406Sopenharmony_ci
1710141cc406Sopenharmony_ci
1711141cc406Sopenharmony_ci    	default:
1712141cc406Sopenharmony_ci        	return SANE_STATUS_INVAL;
1713141cc406Sopenharmony_ci	}
1714141cc406Sopenharmony_ci
1715141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1716141cc406Sopenharmony_ci}
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_ci/** according to the option number, return a pointer to a descriptor
1719141cc406Sopenharmony_ci */
1720141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
1721141cc406Sopenharmony_ci   			 sane_get_option_descriptor( SANE_Handle handle, SANE_Int option )
1722141cc406Sopenharmony_ci{
1723141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *)handle;
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci	if((option < 0) || (option >= NUM_OPTIONS))
1726141cc406Sopenharmony_ci		return NULL;
1727141cc406Sopenharmony_ci
1728141cc406Sopenharmony_ci	return &(s->opt[option]);
1729141cc406Sopenharmony_ci}
1730141cc406Sopenharmony_ci
1731141cc406Sopenharmony_ci/** return the current parameter settings
1732141cc406Sopenharmony_ci */
1733141cc406Sopenharmony_ciSANE_Status sane_get_parameters( SANE_Handle handle, SANE_Parameters *params )
1734141cc406Sopenharmony_ci{
1735141cc406Sopenharmony_ci	int    			 ndpi;
1736141cc406Sopenharmony_ci	pModeParam  	 mp;
1737141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *)handle;
1738141cc406Sopenharmony_ci
1739141cc406Sopenharmony_ci	/* if we're calling from within, calc best guess
1740141cc406Sopenharmony_ci     * do the same, if sane_get_parameters() is called
1741141cc406Sopenharmony_ci     * by a frontend before sane_start() is called
1742141cc406Sopenharmony_ci     */
1743141cc406Sopenharmony_ci    if((NULL == params) || (s->scanning != SANE_TRUE)) {
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci		mp = getModeList( s );
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci		memset( &s->params, 0, sizeof (SANE_Parameters));
1748141cc406Sopenharmony_ci
1749141cc406Sopenharmony_ci		ndpi = s->val[OPT_RESOLUTION].w;
1750141cc406Sopenharmony_ci
1751141cc406Sopenharmony_ci	    s->params.pixels_per_line =	SANE_UNFIX(s->val[OPT_BR_X].w -
1752141cc406Sopenharmony_ci									  s->val[OPT_TL_X].w) / MM_PER_INCH * ndpi;
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci    	s->params.lines = SANE_UNFIX( s->val[OPT_BR_Y].w -
1755141cc406Sopenharmony_ci									  s->val[OPT_TL_Y].w) / MM_PER_INCH * ndpi;
1756141cc406Sopenharmony_ci
1757141cc406Sopenharmony_ci		/* pixels_per_line seems to be 8 * n.  */
1758141cc406Sopenharmony_ci		/* s->params.pixels_per_line = s->params.pixels_per_line & ~7; debug only */
1759141cc406Sopenharmony_ci
1760141cc406Sopenharmony_ci	    s->params.last_frame = SANE_TRUE;
1761141cc406Sopenharmony_ci    	s->params.depth      = mp[s->val[OPT_MODE].w].depth;
1762141cc406Sopenharmony_ci
1763141cc406Sopenharmony_ci		if( mp[s->val[OPT_MODE].w].color ) {
1764141cc406Sopenharmony_ci			s->params.format = SANE_FRAME_RGB;
1765141cc406Sopenharmony_ci			s->params.bytes_per_line = 3 * s->params.pixels_per_line;
1766141cc406Sopenharmony_ci		} else {
1767141cc406Sopenharmony_ci			s->params.format = SANE_FRAME_GRAY;
1768141cc406Sopenharmony_ci			if (s->params.depth == 1)
1769141cc406Sopenharmony_ci				s->params.bytes_per_line = (s->params.pixels_per_line + 7) / 8;
1770141cc406Sopenharmony_ci			else
1771141cc406Sopenharmony_ci				s->params.bytes_per_line = s->params.pixels_per_line *
1772141cc406Sopenharmony_ci														   s->params.depth / 8;
1773141cc406Sopenharmony_ci		}
1774141cc406Sopenharmony_ci
1775141cc406Sopenharmony_ci        /* if sane_get_parameters() was called before sane_start() */
1776141cc406Sopenharmony_ci	    /* pass new values to the caller                           */
1777141cc406Sopenharmony_ci    	if ((NULL != params) &&	(s->scanning != SANE_TRUE))
1778141cc406Sopenharmony_ci	    	*params = s->params;
1779141cc406Sopenharmony_ci	} else
1780141cc406Sopenharmony_ci		*params = s->params;
1781141cc406Sopenharmony_ci
1782141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
1783141cc406Sopenharmony_ci}
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci/** initiate the scan process
1786141cc406Sopenharmony_ci */
1787141cc406Sopenharmony_ciSANE_Status sane_start( SANE_Handle handle )
1788141cc406Sopenharmony_ci{
1789141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *) handle;
1790141cc406Sopenharmony_ci	pModeParam		 mp;
1791141cc406Sopenharmony_ci
1792141cc406Sopenharmony_ci	int			result;
1793141cc406Sopenharmony_ci	int 		ndpi;
1794141cc406Sopenharmony_ci	int 		left, top;
1795141cc406Sopenharmony_ci	int 		width, height;
1796141cc406Sopenharmony_ci	int			scanmode;
1797141cc406Sopenharmony_ci	int         fds[2];
1798141cc406Sopenharmony_ci	StartScan	start;
1799141cc406Sopenharmony_ci	CropInfo	crop;
1800141cc406Sopenharmony_ci	ScanInfo    sinfo;
1801141cc406Sopenharmony_ci	SANE_Status status;
1802141cc406Sopenharmony_ci    SANE_Word   tmp;
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_start\n" );
1805141cc406Sopenharmony_ci
1806141cc406Sopenharmony_ci	if( s->scanning ) {
1807141cc406Sopenharmony_ci		return SANE_STATUS_DEVICE_BUSY;
1808141cc406Sopenharmony_ci	}
1809141cc406Sopenharmony_ci
1810141cc406Sopenharmony_ci	status = sane_get_parameters (handle, NULL);
1811141cc406Sopenharmony_ci	if (status != SANE_STATUS_GOOD) {
1812141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "sane_get_parameters failed\n" );
1813141cc406Sopenharmony_ci		return status;
1814141cc406Sopenharmony_ci	}
1815141cc406Sopenharmony_ci
1816141cc406Sopenharmony_ci	/*
1817141cc406Sopenharmony_ci	 * open the driver and get some information about the scanner
1818141cc406Sopenharmony_ci	 */
1819141cc406Sopenharmony_ci	s->hw->fd = drvopen( s->hw );
1820141cc406Sopenharmony_ci	if( s->hw->fd < 0 ) {
1821141cc406Sopenharmony_ci		DBG( _DBG_ERROR,"sane_start: open failed: %d\n", errno );
1822141cc406Sopenharmony_ci
1823141cc406Sopenharmony_ci		if( errno == EBUSY )
1824141cc406Sopenharmony_ci			return SANE_STATUS_DEVICE_BUSY;
1825141cc406Sopenharmony_ci
1826141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1827141cc406Sopenharmony_ci	}
1828141cc406Sopenharmony_ci
1829141cc406Sopenharmony_ci	result = s->hw->getCaps( s->hw );
1830141cc406Sopenharmony_ci	if( result < 0 ) {
1831141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->getCaps() failed(%d)\n", result);
1832141cc406Sopenharmony_ci		s->hw->close( s->hw );
1833141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1834141cc406Sopenharmony_ci    }
1835141cc406Sopenharmony_ci
1836141cc406Sopenharmony_ci	result = s->hw->getLensInfo( s->hw, &lens );
1837141cc406Sopenharmony_ci	if( result < 0 ) {
1838141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->getLensInfo() failed(%d)\n", result );
1839141cc406Sopenharmony_ci		s->hw->close( s->hw );
1840141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1841141cc406Sopenharmony_ci    }
1842141cc406Sopenharmony_ci
1843141cc406Sopenharmony_ci	/* did we fail on connection? */
1844141cc406Sopenharmony_ci	if ( s->hw->caps.wIOBase == _NO_BASE ) {
1845141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "failed to find Plustek scanner\n" );
1846141cc406Sopenharmony_ci		s->hw->close( s->hw );
1847141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
1848141cc406Sopenharmony_ci	}
1849141cc406Sopenharmony_ci
1850141cc406Sopenharmony_ci	/* All ready to go.  Set image def and see what the scanner
1851141cc406Sopenharmony_ci	 * says for crop info.
1852141cc406Sopenharmony_ci	 */
1853141cc406Sopenharmony_ci	ndpi = s->val[OPT_RESOLUTION].w;
1854141cc406Sopenharmony_ci
1855141cc406Sopenharmony_ci    /* exchange the values as we can't deal with negative heights and so on...*/
1856141cc406Sopenharmony_ci    tmp = s->val[OPT_TL_X].w;
1857141cc406Sopenharmony_ci    if( tmp > s->val[OPT_BR_X].w ) {
1858141cc406Sopenharmony_ci		DBG( _DBG_INFO, "exchanging BR-X - TL-X\n" );
1859141cc406Sopenharmony_ci        s->val[OPT_TL_X].w = s->val[OPT_BR_X].w;
1860141cc406Sopenharmony_ci        s->val[OPT_BR_X].w = tmp;
1861141cc406Sopenharmony_ci    }
1862141cc406Sopenharmony_ci
1863141cc406Sopenharmony_ci    tmp = s->val[OPT_TL_Y].w;
1864141cc406Sopenharmony_ci    if( tmp > s->val[OPT_BR_Y].w ) {
1865141cc406Sopenharmony_ci		DBG( _DBG_INFO, "exchanging BR-Y - TL-Y\n" );
1866141cc406Sopenharmony_ci        s->val[OPT_TL_Y].w = s->val[OPT_BR_Y].w;
1867141cc406Sopenharmony_ci        s->val[OPT_BR_Y].w = tmp;
1868141cc406Sopenharmony_ci    }
1869141cc406Sopenharmony_ci
1870141cc406Sopenharmony_ci	/* position and extent are always relative to 300 dpi */
1871141cc406Sopenharmony_ci	left   = (int)(SANE_UNFIX (s->val[OPT_TL_X].w)*(double)lens.rDpiX.wPhyMax/
1872141cc406Sopenharmony_ci							(MM_PER_INCH*((double)lens.rDpiX.wPhyMax/300.0)));
1873141cc406Sopenharmony_ci	top    = (int)(SANE_UNFIX (s->val[OPT_TL_Y].w)*(double)lens.rDpiY.wPhyMax/
1874141cc406Sopenharmony_ci							(MM_PER_INCH*((double)lens.rDpiY.wPhyMax/300.0)));
1875141cc406Sopenharmony_ci	width  = (int)(SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) *
1876141cc406Sopenharmony_ci					(double)lens.rDpiX.wPhyMax /
1877141cc406Sopenharmony_ci							(MM_PER_INCH *((double)lens.rDpiX.wPhyMax/300.0)));
1878141cc406Sopenharmony_ci	height = (int)(SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) *
1879141cc406Sopenharmony_ci					(double)lens.rDpiY.wPhyMax /
1880141cc406Sopenharmony_ci							(MM_PER_INCH *((double)lens.rDpiY.wPhyMax/300.0)));
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_ci	/*
1883141cc406Sopenharmony_ci	 * adjust mode list according to the model we use and the
1884141cc406Sopenharmony_ci	 * source we have
1885141cc406Sopenharmony_ci	 */
1886141cc406Sopenharmony_ci	mp = getModeList( s );
1887141cc406Sopenharmony_ci
1888141cc406Sopenharmony_ci	scanmode = mp[s->val[OPT_MODE].w].scanmode;
1889141cc406Sopenharmony_ci	DBG( _DBG_INFO, "scanmode = %u\n", scanmode );
1890141cc406Sopenharmony_ci
1891141cc406Sopenharmony_ci	/* clear it out just in case */
1892141cc406Sopenharmony_ci	memset (&sinfo, 0, sizeof(sinfo));
1893141cc406Sopenharmony_ci	sinfo.ImgDef.xyDpi.x   = ndpi;
1894141cc406Sopenharmony_ci	sinfo.ImgDef.xyDpi.y   = ndpi;
1895141cc406Sopenharmony_ci	sinfo.ImgDef.crArea.x  = left;  /* offset from left edge to area you want to scan */
1896141cc406Sopenharmony_ci	sinfo.ImgDef.crArea.y  = top;  	/* offset from top edge to area you want to scan  */
1897141cc406Sopenharmony_ci	sinfo.ImgDef.crArea.cx = width; /* always relative to 300 dpi */
1898141cc406Sopenharmony_ci	sinfo.ImgDef.crArea.cy = height;
1899141cc406Sopenharmony_ci	sinfo.ImgDef.wDataType = scanmode;
1900141cc406Sopenharmony_ci
1901141cc406Sopenharmony_ci/*
1902141cc406Sopenharmony_ci * CHECK: what about the 10 bit mode?
1903141cc406Sopenharmony_ci */
1904141cc406Sopenharmony_ci#if 0
1905141cc406Sopenharmony_ci	if( COLOR_TRUE48 == scanmode )
1906141cc406Sopenharmony_ci		sinfo.ImgDef.wBits = OUTPUT_12Bits;
1907141cc406Sopenharmony_ci	else if( COLOR_TRUE32 == scanmode )
1908141cc406Sopenharmony_ci		sinfo.ImgDef.wBits = OUTPUT_10Bits;
1909141cc406Sopenharmony_ci	else
1910141cc406Sopenharmony_ci		sinfo.ImgDef.wBits = OUTPUT_8Bits;
1911141cc406Sopenharmony_ci#endif
1912141cc406Sopenharmony_ci	sinfo.ImgDef.dwFlag = SCANDEF_QualityScan;
1913141cc406Sopenharmony_ci
1914141cc406Sopenharmony_ci	switch( s->val[OPT_EXT_MODE].w ) {
1915141cc406Sopenharmony_ci		case 1: sinfo.ImgDef.dwFlag |= SCANDEF_Transparency; break;
1916141cc406Sopenharmony_ci		case 2: sinfo.ImgDef.dwFlag |= SCANDEF_Negative; 	 break;
1917141cc406Sopenharmony_ci		default: break;
1918141cc406Sopenharmony_ci	}
1919141cc406Sopenharmony_ci
1920141cc406Sopenharmony_ci	/* only for parallel-port devices */
1921141cc406Sopenharmony_ci	if( s->hw->putImgInfo ) {
1922141cc406Sopenharmony_ci		result = s->hw->putImgInfo( s->hw, &sinfo.ImgDef );
1923141cc406Sopenharmony_ci		if( result < 0 ) {
1924141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "dev->putImgInfo failed(%d)\n", result );
1925141cc406Sopenharmony_ci			s->hw->close( s->hw );
1926141cc406Sopenharmony_ci			return SANE_STATUS_IO_ERROR;
1927141cc406Sopenharmony_ci		}
1928141cc406Sopenharmony_ci	} else {
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci		memcpy( &(crop.ImgDef), &sinfo.ImgDef, sizeof(ImgDef));
1931141cc406Sopenharmony_ci
1932141cc406Sopenharmony_ci	}
1933141cc406Sopenharmony_ci
1934141cc406Sopenharmony_ci	result = s->hw->getCropInfo( s->hw, &crop );
1935141cc406Sopenharmony_ci	if( result < 0 ) {
1936141cc406Sopenharmony_ci	    DBG( _DBG_ERROR, "dev->getCropInfo() failed(%d)\n", result );
1937141cc406Sopenharmony_ci		s->hw->close( s->hw );
1938141cc406Sopenharmony_ci    	return SANE_STATUS_IO_ERROR;
1939141cc406Sopenharmony_ci    }
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci	/* DataInf.dwAppPixelsPerLine = crop.dwPixelsPerLine;  */
1942141cc406Sopenharmony_ci	s->params.pixels_per_line = crop.dwPixelsPerLine;
1943141cc406Sopenharmony_ci	s->params.bytes_per_line  = crop.dwBytesPerLine;
1944141cc406Sopenharmony_ci	s->params.lines 		  = crop.dwLinesPerArea;
1945141cc406Sopenharmony_ci
1946141cc406Sopenharmony_ci	/* build a SCANINFO block and get ready to scan it */
1947141cc406Sopenharmony_ci	sinfo.ImgDef.dwFlag |= (SCANDEF_BuildBwMap | SCANDEF_QualityScan);
1948141cc406Sopenharmony_ci
1949141cc406Sopenharmony_ci    /* set adjustments for brightness and contrast */
1950141cc406Sopenharmony_ci	sinfo.siBrightness = s->val[OPT_BRIGHTNESS].w;
1951141cc406Sopenharmony_ci	sinfo.siContrast   = s->val[OPT_CONTRAST].w;
1952141cc406Sopenharmony_ci	sinfo.wDither	   = s->val[OPT_HALFTONE].w;
1953141cc406Sopenharmony_ci
1954141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "bright %i contrast %i\n", sinfo.siBrightness,
1955141cc406Sopenharmony_ci   			 									       sinfo.siContrast);
1956141cc406Sopenharmony_ci
1957141cc406Sopenharmony_ci	result = s->hw->setScanEnv( s->hw, &sinfo );
1958141cc406Sopenharmony_ci	if( result < 0 ) {
1959141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->setEnv() failed(%d)\n", result );
1960141cc406Sopenharmony_ci		s->hw->close( s->hw );
1961141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1962141cc406Sopenharmony_ci    }
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_ci	/* download gamma correction tables... */
1965141cc406Sopenharmony_ci	if( scanmode <= COLOR_256GRAY || scanmode == COLOR_GRAY16 ) {
1966141cc406Sopenharmony_ci	   	s->hw->setMap( s->hw, s->gamma_table[0], s->gamma_length, _MAP_MASTER);
1967141cc406Sopenharmony_ci	} else {
1968141cc406Sopenharmony_ci	   	s->hw->setMap( s->hw, s->gamma_table[1], s->gamma_length, _MAP_RED   );
1969141cc406Sopenharmony_ci   		s->hw->setMap( s->hw, s->gamma_table[2], s->gamma_length, _MAP_GREEN );
1970141cc406Sopenharmony_ci   		s->hw->setMap( s->hw, s->gamma_table[3], s->gamma_length, _MAP_BLUE  );
1971141cc406Sopenharmony_ci    }
1972141cc406Sopenharmony_ci	/* work-around for USB... */
1973141cc406Sopenharmony_ci	start.dwLinesPerScan = s->params.lines;
1974141cc406Sopenharmony_ci
1975141cc406Sopenharmony_ci	result = s->hw->startScan( s->hw, &start );
1976141cc406Sopenharmony_ci	if( result < 0 ) {
1977141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "dev->startScan() failed(%d)\n", result );
1978141cc406Sopenharmony_ci		s->hw->close( s->hw );
1979141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
1980141cc406Sopenharmony_ci    }
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "dwflag = 0x%lx dwBytesPerLine = %ld, "
1983141cc406Sopenharmony_ci		 "dwLinesPerScan = %ld\n",
1984141cc406Sopenharmony_ci					 start.dwFlag, start.dwBytesPerLine, start.dwLinesPerScan);
1985141cc406Sopenharmony_ci
1986141cc406Sopenharmony_ci	s->buf = realloc( s->buf, (s->params.lines) * s->params.bytes_per_line );
1987141cc406Sopenharmony_ci	if( NULL == s->buf ) {
1988141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "realloc failed\n" );
1989141cc406Sopenharmony_ci		s->hw->close( s->hw );
1990141cc406Sopenharmony_ci		return SANE_STATUS_NO_MEM;
1991141cc406Sopenharmony_ci	}
1992141cc406Sopenharmony_ci
1993141cc406Sopenharmony_ci	s->scanning = SANE_TRUE;
1994141cc406Sopenharmony_ci
1995141cc406Sopenharmony_ci	tsecs = (unsigned long)time(NULL);
1996141cc406Sopenharmony_ci	DBG( _DBG_INFO, "TIME START\n" );
1997141cc406Sopenharmony_ci
1998141cc406Sopenharmony_ci	/*
1999141cc406Sopenharmony_ci	 * everything prepared, so start the child process and a pipe to communicate
2000141cc406Sopenharmony_ci	 * pipe --> fds[0]=read-fd, fds[1]=write-fd
2001141cc406Sopenharmony_ci	 */
2002141cc406Sopenharmony_ci	if( pipe(fds) < 0 ) {
2003141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: could not create pipe\n" );
2004141cc406Sopenharmony_ci	    s->scanning = SANE_FALSE;
2005141cc406Sopenharmony_ci		s->hw->close( s->hw );
2006141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
2007141cc406Sopenharmony_ci	}
2008141cc406Sopenharmony_ci
2009141cc406Sopenharmony_ci	/* create reader routine as new process */
2010141cc406Sopenharmony_ci	s->bytes_read = 0;
2011141cc406Sopenharmony_ci	s->r_pipe     = fds[0];
2012141cc406Sopenharmony_ci	s->w_pipe     = fds[1];
2013141cc406Sopenharmony_ci	s->reader_pid = sanei_thread_begin( reader_process, s );
2014141cc406Sopenharmony_ci
2015141cc406Sopenharmony_ci	if(!sanei_thread_is_valid( s->reader_pid )) {
2016141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: could not create child process\n" );
2017141cc406Sopenharmony_ci		s->scanning = SANE_FALSE;
2018141cc406Sopenharmony_ci		s->hw->close( s->hw );
2019141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
2020141cc406Sopenharmony_ci	}
2021141cc406Sopenharmony_ci
2022141cc406Sopenharmony_ci	/* reader_pid = 0 ===> child process */
2023141cc406Sopenharmony_ci#if 0
2024141cc406Sopenharmony_ci	if( 0 == s->reader_pid ) {
2025141cc406Sopenharmony_ci
2026141cc406Sopenharmony_ci		sigset_t 		 ignore_set;
2027141cc406Sopenharmony_ci		struct SIGACTION act;
2028141cc406Sopenharmony_ci
2029141cc406Sopenharmony_ci		DBG( _DBG_SANE_INIT, "reader process...\n" );
2030141cc406Sopenharmony_ci
2031141cc406Sopenharmony_ci		close(fds[0]);
2032141cc406Sopenharmony_ci
2033141cc406Sopenharmony_ci		sigfillset ( &ignore_set );
2034141cc406Sopenharmony_ci		sigdelset  ( &ignore_set, SIGTERM );
2035141cc406Sopenharmony_ci		sigprocmask( SIG_SETMASK, &ignore_set, 0 );
2036141cc406Sopenharmony_ci
2037141cc406Sopenharmony_ci		memset   ( &act, 0, sizeof (act));
2038141cc406Sopenharmony_ci		sigaction( SIGTERM, &act, 0 );
2039141cc406Sopenharmony_ci
2040141cc406Sopenharmony_ci		status = reader_process( s, fds[1] );
2041141cc406Sopenharmony_ci
2042141cc406Sopenharmony_ci		DBG( _DBG_SANE_INIT, "reader process done, status = %i\n", status );
2043141cc406Sopenharmony_ci
2044141cc406Sopenharmony_ci		/* don't use exit() since that would run the atexit() handlers */
2045141cc406Sopenharmony_ci		_exit( status );
2046141cc406Sopenharmony_ci	}
2047141cc406Sopenharmony_ci#endif
2048141cc406Sopenharmony_ci	signal( SIGCHLD, sig_chldhandler );
2049141cc406Sopenharmony_ci
2050141cc406Sopenharmony_ci	if( sanei_thread_is_forked()) {
2051141cc406Sopenharmony_ci		close( s->w_pipe );
2052141cc406Sopenharmony_ci		s->w_pipe = -1;
2053141cc406Sopenharmony_ci	}
2054141cc406Sopenharmony_ci
2055141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_start done\n" );
2056141cc406Sopenharmony_ci
2057141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2058141cc406Sopenharmony_ci}
2059141cc406Sopenharmony_ci
2060141cc406Sopenharmony_ci/** function to read the data from our child process
2061141cc406Sopenharmony_ci */
2062141cc406Sopenharmony_ciSANE_Status sane_read( SANE_Handle handle, SANE_Byte *data,
2063141cc406Sopenharmony_ci									   SANE_Int max_length, SANE_Int *length )
2064141cc406Sopenharmony_ci{
2065141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner*)handle;
2066141cc406Sopenharmony_ci	ssize_t 		 nread;
2067141cc406Sopenharmony_ci
2068141cc406Sopenharmony_ci	*length = 0;
2069141cc406Sopenharmony_ci
2070141cc406Sopenharmony_ci	/* here we read all data from the driver... */
2071141cc406Sopenharmony_ci	nread = read( s->r_pipe, data, max_length );
2072141cc406Sopenharmony_ci	DBG( _DBG_READ, "sane_read - read %ld bytes\n", (long)nread );
2073141cc406Sopenharmony_ci	if (!(s->scanning)) {
2074141cc406Sopenharmony_ci		return do_cancel( s, SANE_TRUE );
2075141cc406Sopenharmony_ci	}
2076141cc406Sopenharmony_ci
2077141cc406Sopenharmony_ci	if( nread < 0 ) {
2078141cc406Sopenharmony_ci
2079141cc406Sopenharmony_ci		if( EAGAIN == errno ) {
2080141cc406Sopenharmony_ci
2081141cc406Sopenharmony_ci            /* if we had already red the picture, so it's okay and stop */
2082141cc406Sopenharmony_ci			if( s->bytes_read ==
2083141cc406Sopenharmony_ci				(unsigned long)(s->params.lines * s->params.bytes_per_line)) {
2084141cc406Sopenharmony_ci				sanei_thread_waitpid( s->reader_pid, 0 );
2085141cc406Sopenharmony_ci				sanei_thread_invalidate( s->reader_pid );
2086141cc406Sopenharmony_ci				drvclose( s->hw );
2087141cc406Sopenharmony_ci				return close_pipe(s);
2088141cc406Sopenharmony_ci			}
2089141cc406Sopenharmony_ci
2090141cc406Sopenharmony_ci            /* else force the frontend to try again*/
2091141cc406Sopenharmony_ci			return SANE_STATUS_GOOD;
2092141cc406Sopenharmony_ci
2093141cc406Sopenharmony_ci		} else {
2094141cc406Sopenharmony_ci			DBG( _DBG_ERROR, "ERROR: errno=%d\n", errno );
2095141cc406Sopenharmony_ci			do_cancel( s, SANE_TRUE );
2096141cc406Sopenharmony_ci			return SANE_STATUS_IO_ERROR;
2097141cc406Sopenharmony_ci		}
2098141cc406Sopenharmony_ci	}
2099141cc406Sopenharmony_ci
2100141cc406Sopenharmony_ci	*length        = nread;
2101141cc406Sopenharmony_ci	s->bytes_read += nread;
2102141cc406Sopenharmony_ci
2103141cc406Sopenharmony_ci    /* nothing red means that we're finished OR we had a problem...*/
2104141cc406Sopenharmony_ci	if( 0 == nread ) {
2105141cc406Sopenharmony_ci
2106141cc406Sopenharmony_ci		drvclose( s->hw );
2107141cc406Sopenharmony_ci		s->exit_code = sanei_thread_get_status( s->reader_pid );
2108141cc406Sopenharmony_ci
2109141cc406Sopenharmony_ci		if( SANE_STATUS_GOOD != s->exit_code ) {
2110141cc406Sopenharmony_ci			close_pipe(s);
2111141cc406Sopenharmony_ci			return s->exit_code;
2112141cc406Sopenharmony_ci		}
2113141cc406Sopenharmony_ci		sanei_thread_invalidate( s->reader_pid );
2114141cc406Sopenharmony_ci		return close_pipe(s);
2115141cc406Sopenharmony_ci	}
2116141cc406Sopenharmony_ci
2117141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2118141cc406Sopenharmony_ci}
2119141cc406Sopenharmony_ci
2120141cc406Sopenharmony_ci/** cancel the scanning process
2121141cc406Sopenharmony_ci */
2122141cc406Sopenharmony_civoid sane_cancel (SANE_Handle handle)
2123141cc406Sopenharmony_ci{
2124141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2125141cc406Sopenharmony_ci
2126141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_cancel\n" );
2127141cc406Sopenharmony_ci
2128141cc406Sopenharmony_ci	if( s->scanning )
2129141cc406Sopenharmony_ci		do_cancel( s, SANE_FALSE );
2130141cc406Sopenharmony_ci}
2131141cc406Sopenharmony_ci
2132141cc406Sopenharmony_ci/** set the pipe to blocking/non blocking mode
2133141cc406Sopenharmony_ci */
2134141cc406Sopenharmony_ciSANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
2135141cc406Sopenharmony_ci{
2136141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2137141cc406Sopenharmony_ci
2138141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_set_io_mode: non_blocking=%d\n",non_blocking );
2139141cc406Sopenharmony_ci
2140141cc406Sopenharmony_ci	if ( !s->scanning ) {
2141141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2142141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2143141cc406Sopenharmony_ci	}
2144141cc406Sopenharmony_ci
2145141cc406Sopenharmony_ci	if( -1 == s->r_pipe ) {
2146141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: not supported !\n" );
2147141cc406Sopenharmony_ci		return SANE_STATUS_UNSUPPORTED;
2148141cc406Sopenharmony_ci	}
2149141cc406Sopenharmony_ci
2150141cc406Sopenharmony_ci	if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) {
2151141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" );
2152141cc406Sopenharmony_ci		return SANE_STATUS_IO_ERROR;
2153141cc406Sopenharmony_ci	}
2154141cc406Sopenharmony_ci
2155141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_set_io_mode done\n" );
2156141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2157141cc406Sopenharmony_ci}
2158141cc406Sopenharmony_ci
2159141cc406Sopenharmony_ci/** return the descriptor if available
2160141cc406Sopenharmony_ci */
2161141cc406Sopenharmony_ciSANE_Status sane_get_select_fd( SANE_Handle handle, SANE_Int * fd )
2162141cc406Sopenharmony_ci{
2163141cc406Sopenharmony_ci	Plustek_Scanner *s = (Plustek_Scanner *)handle;
2164141cc406Sopenharmony_ci
2165141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_get_select_fd\n" );
2166141cc406Sopenharmony_ci
2167141cc406Sopenharmony_ci	if( !s->scanning ) {
2168141cc406Sopenharmony_ci		DBG( _DBG_ERROR, "ERROR: not scanning !\n" );
2169141cc406Sopenharmony_ci		return SANE_STATUS_INVAL;
2170141cc406Sopenharmony_ci	}
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_ci	*fd = s->r_pipe;
2173141cc406Sopenharmony_ci
2174141cc406Sopenharmony_ci	DBG( _DBG_SANE_INIT, "sane_get_select_fd done\n" );
2175141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
2176141cc406Sopenharmony_ci}
2177141cc406Sopenharmony_ci
2178141cc406Sopenharmony_ci/* END PLUSTEK_PP.C .........................................................*/
2179