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