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