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