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