1 /***************************************************************************
2 * SANE - Scanner Access Now Easy.
3
4 microtek2.c
5
6 This file (C) 1998, 1999 Bernd Schroeder
7 modifications 2000, 2001 Karsten Festag
8
9 This file is part of the SANE package.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>.
23
24 As a special exception, the authors of SANE give permission for
25 additional uses of the libraries contained in this release of SANE.
26
27 The exception is that, if you link a SANE library with other files
28 to produce an executable, this does not by itself cause the
29 resulting executable to be covered by the GNU General Public
30 License. Your use of that executable is in no way restricted on
31 account of linking the SANE library code into it.
32
33 This exception does not, however, invalidate any other reasons why
34 the executable file might be covered by the GNU General Public
35 License.
36
37 If you submit changes to SANE to the maintainers to be included in
38 a subsequent release, you agree by submitting the changes that
39 those changes may be distributed with this exception intact.
40
41 If you write modifications of your own for SANE, it is your choice
42 whether to permit this exception to apply to your modifications.
43 If you do not wish that, delete this exception notice.
44
45 ***************************************************************************
46
47 This file implements a SANE backend for Microtek scanners with
48 SCSI-2 command set.
49
50 (feedback to: bernd@aquila.muc.de)
51 ( karsten.festag@t-online.de)
52 ***************************************************************************/
53
54
55 #ifdef _AIX
56 # include <lalloca.h> /* MUST come first for AIX! */
57 #endif
58
59 #include "../include/sane/config.h"
60 #include "../include/lalloca.h"
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <fcntl.h>
67 #include <ctype.h>
68 #include <sys/types.h>
69 #include <signal.h>
70 #include <errno.h>
71 #include <math.h>
72
73 #include "../include/_stdint.h"
74
75 #ifdef HAVE_AUTHORIZATION
76 #include <sys/stat.h>
77 #endif
78
79 #include "../include/sane/sane.h"
80 #include "../include/sane/sanei.h"
81 #include "../include/sane/sanei_config.h"
82 #include "../include/sane/sanei_scsi.h"
83 #include "../include/sane/saneopts.h"
84 #include "../include/sane/sanei_thread.h"
85
86 #ifndef TESTBACKEND
87 #define BACKEND_NAME microtek2
88 #else
89 #define BACKEND_NAME microtek2_test
90 #endif
91
92 /* for testing*/
93 /*#define NO_PHANTOMTYPE_SHADING*/
94
95 #include "../include/sane/sanei_backend.h"
96
97 #include "microtek2.h"
98
99 #ifdef HAVE_AUTHORIZATION
100 static SANE_Auth_Callback auth_callback;
101 #endif
102
103 static int md_num_devices = 0; /* number of devices from config file */
104 static Microtek2_Device *md_first_dev = NULL; /* list of known devices */
105 static Microtek2_Scanner *ms_first_handle = NULL; /* list of open scanners */
106
107 /* options that can be configured in the config file */
108 static Config_Options md_options =
109 { 1.0, "off", "off", "off", "off", "off", "off"};
110 static Config_Temp *md_config_temp = NULL;
111 static int md_dump = 0; /* from config file: */
112 /* 1: inquiry + scanner attributes */
113 /* 2: + all scsi commands and data */
114 /* 3: + all scan data */
115 static int md_dump_clear = 1;
116
117
118 /*---------- sane_cancel() ---------------------------------------------------*/
119
120 void
sane_cancel(SANE_Handle handle)121 sane_cancel (SANE_Handle handle)
122 {
123 Microtek2_Scanner *ms = handle;
124
125 DBG(30, "sane_cancel: handle=%p\n", handle);
126
127 if ( ms->scanning == SANE_TRUE )
128 cleanup_scanner(ms);
129 ms->cancelled = SANE_TRUE;
130 ms->fd[0] = ms->fd[1] = -1;
131 }
132
133
134 /*---------- sane_close() ----------------------------------------------------*/
135
136
137 void
sane_close(SANE_Handle handle)138 sane_close (SANE_Handle handle)
139 {
140 Microtek2_Scanner *ms = handle;
141
142 DBG(30, "sane_close: ms=%p\n", (void *) ms);
143
144 if ( ! ms )
145 return;
146
147 /* free malloc'ed stuff */
148 cleanup_scanner(ms);
149
150 /* remove Scanner from linked list */
151 if ( ms_first_handle == ms )
152 ms_first_handle = ms->next;
153 else
154 {
155 Microtek2_Scanner *ts = ms_first_handle;
156 while ( (ts != NULL) && (ts->next != ms) )
157 ts = ts->next;
158 ts->next = ts->next->next; /* == ms->next */
159 }
160 DBG(100, "free ms at %p\n", (void *) ms);
161 free((void *) ms);
162 ms = NULL;
163 }
164
165
166 /*---------- sane_exit() -----------------------------------------------------*/
167
168 void
sane_exit(void)169 sane_exit (void)
170 {
171 Microtek2_Device *next;
172 int i;
173
174 DBG(30, "sane_exit:\n");
175
176 /* close all leftover Scanners */
177 while (ms_first_handle != NULL)
178 sane_close(ms_first_handle);
179 /* free up device list */
180 while (md_first_dev != NULL)
181 {
182 next = md_first_dev->next;
183
184 for ( i = 0; i < 4; i++ )
185 {
186 if ( md_first_dev->custom_gamma_table[i] )
187 {
188 DBG(100, "free md_first_dev->custom_gamma_table[%d] at %p\n",
189 i, (void *) md_first_dev->custom_gamma_table[i]);
190 free((void *) md_first_dev->custom_gamma_table[i]);
191 md_first_dev->custom_gamma_table[i] = NULL;
192 }
193 }
194
195 if ( md_first_dev->shading_table_w )
196 {
197 DBG(100, "free md_first_dev->shading_table_w at %p\n",
198 (void *) md_first_dev->shading_table_w);
199 free((void *) md_first_dev->shading_table_w);
200 md_first_dev->shading_table_w = NULL;
201 }
202
203 if ( md_first_dev->shading_table_d )
204 {
205 DBG(100, "free md_first_dev->shading_table_d at %p\n",
206 (void *) md_first_dev->shading_table_d);
207 free((void *) md_first_dev->shading_table_d);
208 md_first_dev->shading_table_d = NULL;
209 }
210
211 DBG(100, "free md_first_dev at %p\n", (void *) md_first_dev);
212 free((void *) md_first_dev);
213 md_first_dev = next;
214 }
215 sane_get_devices(NULL, SANE_FALSE); /* free list of SANE_Devices */
216
217 DBG(30, "sane_exit: MICROTEK2 says goodbye.\n");
218 }
219
220
221 /*---------- sane_get_devices()-----------------------------------------------*/
222
223 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)224 sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
225 {
226 /* return a list of available devices; available here means that we get */
227 /* a positive response to an 'INQUIRY' and possibly to a */
228 /* 'READ SCANNER ATTRIBUTE' call */
229
230 static const SANE_Device **sd_list = NULL;
231 Microtek2_Device *md;
232 SANE_Status status;
233 int index;
234
235 DBG(30, "sane_get_devices: local_only=%d\n", local_only);
236
237 /* this is hack to get the list freed with a call from sane_exit() */
238 if ( device_list == NULL )
239 {
240 if ( sd_list )
241 {
242 DBG(100, "free sd_list at %p\n", (void *) sd_list);
243 free(sd_list);
244 sd_list=NULL;
245 }
246 DBG(30, "sane_get_devices: sd_list_freed\n");
247 return SANE_STATUS_GOOD;
248 }
249
250 /* first free old list, if there is one; frontend wants a new list */
251 if ( sd_list )
252 {
253 DBG(100, "free sd_list at %p\n", (void *) sd_list);
254 free(sd_list); /* free array of pointers */
255 }
256
257 sd_list = (const SANE_Device **)
258 malloc( (md_num_devices + 1) * sizeof(SANE_Device **));
259 DBG(100, "sane_get_devices: sd_list=%p, malloc'd %lu bytes\n",
260 (void *) sd_list, (u_long) ((md_num_devices + 1) * sizeof(SANE_Device **)));
261
262 if ( ! sd_list )
263 {
264 DBG(1, "sane_get_devices: malloc() for sd_list failed\n");
265 return SANE_STATUS_NO_MEM;
266 }
267
268 *device_list = sd_list;
269 index = 0;
270 md = md_first_dev;
271 while ( md )
272 {
273 status = attach(md);
274 if ( status != SANE_STATUS_GOOD )
275 {
276 DBG(10, "sane_get_devices: attach status '%s'\n",
277 sane_strstatus(status));
278 md = md->next;
279 continue;
280 }
281
282 /* check whether unit is ready, if so add it to the list */
283 status = scsi_test_unit_ready(md);
284 if ( status != SANE_STATUS_GOOD )
285 {
286 DBG(10, "sane_get_devices: test_unit_ready status '%s'\n",
287 sane_strstatus(status));
288 md = md->next;
289 continue;
290 }
291
292 sd_list[index] = &md->sane;
293
294 ++index;
295 md = md->next;
296 }
297
298 sd_list[index] = NULL;
299 return SANE_STATUS_GOOD;
300 }
301
302
303 /*---------- sane_get_parameters() -------------------------------------------*/
304
305 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)306 sane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
307 {
308 Microtek2_Scanner *ms = handle;
309 Microtek2_Device *md;
310 Option_Value *val;
311 Microtek2_Info *mi;
312 int mode;
313 int depth;
314 int bits_pp_in; /* bits per pixel from scanner */
315 int bits_pp_out; /* bits_per_pixel transferred to frontend */
316 int bytes_per_line;
317 double x_pixel_per_mm;
318 double y_pixel_per_mm;
319 double x1_pixel;
320 double y1_pixel;
321 double width_pixel;
322 double height_pixel;
323
324
325 DBG(40, "sane_get_parameters: handle=%p, params=%p\n", handle,
326 (void *) params);
327
328
329 md = ms->dev;
330 mi = &md->info[md->scan_source];
331 val= ms->val;
332
333 if ( ! ms->scanning ) /* get an estimate for the params */
334 {
335
336 get_scan_mode_and_depth(ms, &mode, &depth, &bits_pp_in, &bits_pp_out);
337
338 switch ( mode )
339 {
340 case MS_MODE_COLOR:
341 if ( mi->onepass )
342 {
343 ms->params.format = SANE_FRAME_RGB;
344 ms->params.last_frame = SANE_TRUE;
345 }
346 else
347 {
348 ms->params.format = SANE_FRAME_RED;
349 ms->params.last_frame = SANE_FALSE;
350 }
351 break;
352 case MS_MODE_GRAY:
353 case MS_MODE_HALFTONE:
354 case MS_MODE_LINEART:
355 case MS_MODE_LINEARTFAKE:
356 ms->params.format = SANE_FRAME_GRAY;
357 ms->params.last_frame = SANE_TRUE;
358 break;
359 default:
360 DBG(1, "sane_get_parameters: Unknown scan mode %d\n", mode);
361 break;
362 }
363
364 ms->params.depth = (SANE_Int) bits_pp_out;
365
366 /* calculate lines, pixels per line and bytes per line */
367 if ( val[OPT_RESOLUTION_BIND].w == SANE_TRUE )
368 {
369 x_pixel_per_mm = y_pixel_per_mm =
370 SANE_UNFIX(val[OPT_RESOLUTION].w) / MM_PER_INCH;
371 DBG(30, "sane_get_parameters: x_res=y_res=%f\n",
372 SANE_UNFIX(val[OPT_RESOLUTION].w));
373 }
374 else
375 {
376 x_pixel_per_mm = SANE_UNFIX(val[OPT_RESOLUTION].w) / MM_PER_INCH;
377 y_pixel_per_mm = SANE_UNFIX(val[OPT_Y_RESOLUTION].w) / MM_PER_INCH;
378 DBG(30, "sane_get_parameters: x_res=%f, y_res=%f\n",
379 SANE_UNFIX(val[OPT_RESOLUTION].w),
380 SANE_UNFIX(val[OPT_Y_RESOLUTION].w));
381 }
382
383 DBG(30, "sane_get_parameters: x_ppm=%f, y_ppm=%f\n",
384 x_pixel_per_mm, y_pixel_per_mm);
385
386 y1_pixel = SANE_UNFIX(ms->val[OPT_TL_Y].w) * y_pixel_per_mm;
387 height_pixel = fabs(SANE_UNFIX(ms->val[OPT_BR_Y].w) * y_pixel_per_mm
388 - y1_pixel) + 0.5;
389 ms->params.lines = (SANE_Int) height_pixel;
390
391 x1_pixel = SANE_UNFIX(ms->val[OPT_TL_X].w) * x_pixel_per_mm;
392 width_pixel = fabs(SANE_UNFIX(ms->val[OPT_BR_X].w) * x_pixel_per_mm
393 - x1_pixel) + 0.5;
394 ms->params.pixels_per_line = (SANE_Int) width_pixel;
395
396
397 if ( bits_pp_out == 1 )
398 bytes_per_line = (width_pixel + 7 ) / 8;
399 else
400 {
401 bytes_per_line = ( width_pixel * bits_pp_out ) / 8 ;
402 if ( mode == MS_MODE_COLOR && mi->onepass )
403 bytes_per_line *= 3;
404 }
405 ms->params.bytes_per_line = (SANE_Int) bytes_per_line;
406 } /* if ms->scanning */
407
408 if ( params )
409 *params = ms->params;
410
411 DBG(30,"sane_get_parameters: format=%d, last_frame=%d, lines=%d\n",
412 ms->params.format,ms->params.last_frame, ms->params.lines);
413 DBG(30,"sane_get_parameters: depth=%d, ppl=%d, bpl=%d\n",
414 ms->params.depth,ms->params.pixels_per_line, ms->params.bytes_per_line);
415
416 return SANE_STATUS_GOOD;
417 }
418
419
420 /*---------- sane_get_select_fd() --------------------------------------------*/
421
422 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)423 sane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
424 {
425 Microtek2_Scanner *ms = handle;
426
427
428 DBG(30, "sane_get_select_fd: ms=%p\n", (void *) ms);
429
430 if ( ! ms->scanning )
431 {
432 DBG(1, "sane_get_select_fd: Scanner not scanning\n");
433 return SANE_STATUS_INVAL;
434 }
435
436 *fd = (SANE_Int) ms->fd[0];
437 return SANE_STATUS_GOOD;
438 }
439
440
441 /*---------- sane_init() -----------------------------------------------------*/
442
443 SANE_Status
444 #ifdef HAVE_AUTHORIZATION
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)445 sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
446 #else
447 sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
448 #endif
449 {
450 Microtek2_Device *md;
451 FILE *fp;
452
453
454 DBG_INIT();
455 DBG(1, "sane_init: Microtek2 (v%d.%d build %s) says hello...\n",
456 MICROTEK2_MAJOR, MICROTEK2_MINOR, MICROTEK2_BUILD);
457
458 if ( version_code )
459 *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
460
461 #ifdef HAVE_AUTHORIZATION
462 auth_callback = authorize;
463 #endif
464
465 sanei_thread_init();
466
467 fp = sanei_config_open(MICROTEK2_CONFIG_FILE);
468 if ( fp == NULL )
469 DBG(10, "sane_init: file not opened: '%s'\n", MICROTEK2_CONFIG_FILE);
470 else
471 {
472 /* check config file for devices and associated options */
473 parse_config_file(fp, &md_config_temp);
474
475 while ( md_config_temp )
476 {
477 sanei_config_attach_matching_devices(md_config_temp->device,
478 attach_one);
479 if ( md_config_temp->next ) /* go to next device, if existent */
480 md_config_temp = md_config_temp->next;
481 else
482 break;
483 }
484
485 fclose(fp);
486 }
487
488 if ( md_first_dev == NULL )
489 {
490 /* config file not found or no valid entry; default to /dev/scanner */
491 /* instead of insisting on config file */
492 add_device_list("/dev/scanner", &md);
493 if ( md )
494 attach(md);
495 }
496 return SANE_STATUS_GOOD;
497 }
498
499
500 /*---------- sane_open() -----------------------------------------------------*/
501
502 SANE_Status
sane_open(SANE_String_Const name,SANE_Handle * handle)503 sane_open(SANE_String_Const name, SANE_Handle *handle)
504 {
505 SANE_Status status;
506 Microtek2_Scanner *ms;
507 Microtek2_Device *md;
508 #ifdef HAVE_AUTHORIZATION
509 struct stat st;
510 int rc;
511 #endif
512
513
514 DBG(30, "sane_open: device='%s'\n", name);
515
516 *handle = NULL;
517 md = md_first_dev;
518
519 if ( name )
520 {
521 /* add_device_list() returns a pointer to the device struct if */
522 /* the device is known or newly added, else it returns NULL */
523
524 status = add_device_list(name, &md);
525 if ( status != SANE_STATUS_GOOD )
526 return status;
527 }
528
529 if ( ! md )
530 {
531 DBG(10, "sane_open: invalid device name '%s'\n", name);
532 return SANE_STATUS_INVAL;
533 }
534
535 /* attach calls INQUIRY and READ SCANNER ATTRIBUTES */
536 status = attach(md);
537 if ( status != SANE_STATUS_GOOD )
538 return status;
539
540 ms = malloc(sizeof(Microtek2_Scanner));
541 DBG(100, "sane_open: ms=%p, malloc'd %lu bytes\n",
542 (void *) ms, (u_long) sizeof(Microtek2_Scanner));
543 if ( ms == NULL )
544 {
545 DBG(1, "sane_open: malloc() for ms failed\n");
546 return SANE_STATUS_NO_MEM;
547 }
548
549 memset(ms, 0, sizeof(Microtek2_Scanner));
550 ms->dev = md;
551 ms->scanning = SANE_FALSE;
552 ms->cancelled = SANE_FALSE;
553 ms->current_pass = 0;
554 ms->sfd = -1;
555 sanei_thread_initialize(ms->pid);
556 ms->fp = NULL;
557 ms->gamma_table = NULL;
558 ms->buf.src_buf = ms->buf.src_buffer[0] = ms->buf.src_buffer[1] = NULL;
559 ms->control_bytes = NULL;
560 ms->shading_image = NULL;
561 ms->condensed_shading_w = NULL;
562 ms->condensed_shading_d = NULL;
563 ms->current_color = MS_COLOR_ALL;
564 ms->current_read_color = MS_COLOR_RED;
565
566 init_options(ms, MD_SOURCE_FLATBED);
567
568 /* insert scanner into linked list */
569 ms->next = ms_first_handle;
570 ms_first_handle = ms;
571
572 *handle = ms;
573
574 #ifdef HAVE_AUTHORIZATION
575 /* check whether the file with the passwords exists. If it doesn't */
576 /* exist, we don't use any authorization */
577
578 rc = stat(PASSWD_FILE, &st);
579 if ( rc == -1 && errno == ENOENT )
580 return SANE_STATUS_GOOD;
581 else
582 {
583 status = do_authorization(md->name);
584 return status;
585 }
586 #else
587 return SANE_STATUS_GOOD;
588 #endif
589 }
590
591
592 /*---------- sane_read() -----------------------------------------------------*/
593
594 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * buf,SANE_Int maxlen,SANE_Int * len)595 sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len )
596 {
597 Microtek2_Scanner *ms = handle;
598 SANE_Status status;
599 ssize_t nread;
600
601
602 DBG(30, "sane_read: handle=%p, buf=%p, maxlen=%d\n",
603 handle, (void *) buf, maxlen);
604
605 *len = 0;
606
607 if ( ! ms->scanning || ms->cancelled )
608 {
609 if ( ms->cancelled )
610 {
611 status = SANE_STATUS_CANCELLED;
612 }
613 else
614 {
615 DBG(15, "sane_read: Scanner %p not scanning\n", (void *) ms);
616 status = SANE_STATUS_IO_ERROR;
617 }
618 DBG(15, "sane_read: scan cancelled or scanner not scanning->cleanup\n");
619 cleanup_scanner(ms);
620 return status;
621 }
622
623
624 nread = read(ms->fd[0], (void *) buf, (int) maxlen);
625 if ( nread == -1 )
626 {
627 if ( errno == EAGAIN )
628 {
629 DBG(30, "sane_read: currently no data available\n");
630 return SANE_STATUS_GOOD;
631 }
632 else
633 {
634 DBG(1, "sane_read: read() failed, errno=%d\n", errno);
635 cleanup_scanner(ms);
636 return SANE_STATUS_IO_ERROR;
637 }
638 }
639
640 if ( nread == 0 )
641 {
642 DBG(15, "sane_read: read 0 bytes -> EOF\n");
643 ms->scanning = SANE_FALSE;
644 cleanup_scanner(ms);
645 return SANE_STATUS_EOF;
646 }
647
648
649 *len = (SANE_Int) nread;
650 DBG(30, "sane_read: *len=%d\n", *len);
651 return SANE_STATUS_GOOD;
652 }
653
654
655 /*---------- sane_set_io_mode() ---------------------------------------------*/
656
657 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)658 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
659 {
660 Microtek2_Scanner *ms = handle;
661 int rc;
662
663
664 DBG(30, "sane_set_io_mode: handle=%p, nonblocking=%d\n",
665 handle, non_blocking);
666
667 if ( ! ms->scanning )
668 {
669 DBG(1, "sane_set_io_mode: Scanner not scanning\n");
670 return SANE_STATUS_INVAL;
671 }
672
673 rc = fcntl(ms->fd[0], F_SETFL, non_blocking ? O_NONBLOCK : 0);
674 if ( rc == -1 )
675 {
676 DBG(1, "sane_set_io_mode: fcntl() failed\n");
677 return SANE_STATUS_INVAL;
678 }
679
680 return SANE_STATUS_GOOD;
681 }
682
683 /*---------- add_device_list() -----------------------------------------------*/
684
685 static SANE_Status
add_device_list(SANE_String_Const dev_name,Microtek2_Device ** mdev)686 add_device_list(SANE_String_Const dev_name, Microtek2_Device **mdev)
687 {
688 Microtek2_Device *md;
689 SANE_String hdev;
690 size_t len;
691
692
693 if ( (hdev = strdup(dev_name)) == NULL)
694 {
695 DBG(5, "add_device_list: malloc() for hdev failed\n");
696 return SANE_STATUS_NO_MEM;
697 }
698
699 len = strlen(hdev);
700 if ( hdev[len - 1] == '\n' )
701 hdev[--len] = '\0';
702
703 DBG(30, "add_device_list: device='%s'\n", hdev);
704
705 /* check, if device is already known */
706 md = md_first_dev;
707 while ( md )
708 {
709 if ( strcmp(hdev, md->name) == 0 )
710 {
711 DBG(30, "add_device_list: device '%s' already in list\n", hdev);
712
713 *mdev = md;
714 return SANE_STATUS_GOOD;
715 }
716 md = md->next;
717 }
718
719 md = (Microtek2_Device *) malloc(sizeof(Microtek2_Device));
720 DBG(100, "add_device_list: md=%p, malloc'd %lu bytes\n",
721 (void *) md, (u_long) sizeof(Microtek2_Device));
722 if ( md == NULL )
723 {
724 DBG(1, "add_device_list: malloc() for md failed\n");
725 return SANE_STATUS_NO_MEM;
726 }
727
728 /* initialize Device and add it at the beginning of the list */
729 memset(md, 0, sizeof(Microtek2_Device));
730 md->next = md_first_dev;
731 md_first_dev = md;
732 md->sane.name = NULL;
733 md->sane.vendor = NULL;
734 md->sane.model = NULL;
735 md->sane.type = NULL;
736 md->scan_source = MD_SOURCE_FLATBED;
737 md->shading_table_w = NULL;
738 md->shading_table_d = NULL;
739 strncpy(md->name, hdev, PATH_MAX - 1);
740 if ( md_config_temp )
741 md->opts = md_config_temp->opts;
742 else
743 md->opts = md_options;
744 ++md_num_devices;
745 *mdev = md;
746 DBG(100, "free hdev at %p\n", (void *) hdev);
747 free(hdev);
748
749 return SANE_STATUS_GOOD;
750 }
751
752 /*---------- attach() --------------------------------------------------------*/
753
754 static SANE_Status
attach(Microtek2_Device * md)755 attach(Microtek2_Device *md)
756 {
757 /* This function is called from sane_init() to do the inquiry and to read */
758 /* the scanner attributes. If one of these calls fails, or if a new */
759 /* device is passed in sane_open() this function may also be called */
760 /* from sane_open() or sane_get_devices(). */
761
762 SANE_String model_string;
763 SANE_Status status;
764 SANE_Byte source_info;
765
766
767 DBG(30, "attach: device='%s'\n", md->name);
768
769 status = scsi_inquiry( &md->info[MD_SOURCE_FLATBED], md->name );
770 if ( status != SANE_STATUS_GOOD )
771 {
772 DBG(1, "attach: '%s'\n", sane_strstatus(status));
773 return status;
774 }
775
776 /* We copy the inquiry info into the info structures for each scansource */
777 /* like ADF, TMA, STRIPE and SLIDE */
778
779 for ( source_info = 1; source_info < 5; ++source_info )
780 memcpy( &md->info[source_info],
781 &md->info[MD_SOURCE_FLATBED],
782 sizeof( Microtek2_Info ) );
783
784 /* Here we should insert a function, that stores all the relevant */
785 /* information in the info structure in a more conveniant format */
786 /* in the device structure, e.g. the model name with a trailing '\0'. */
787
788 status = check_inquiry(md, &model_string);
789 if ( status != SANE_STATUS_GOOD )
790 return status;
791
792 md->sane.name = md->name;
793 md->sane.vendor = "Microtek";
794 md->sane.model = strdup(model_string);
795 if ( md->sane.model == NULL )
796 DBG(1, "attach: strdup for model string failed\n");
797 md->sane.type = "flatbed scanner";
798 md->revision = strtod(md->info[MD_SOURCE_FLATBED].revision, NULL);
799
800 status = scsi_read_attributes(&md->info[0],
801 md->name, MD_SOURCE_FLATBED);
802 if ( status != SANE_STATUS_GOOD )
803 {
804 DBG(1, "attach: '%s'\n", sane_strstatus(status));
805 return status;
806 }
807
808 if ( MI_LUTCAP_NONE( md->info[MD_SOURCE_FLATBED].lut_cap) )
809 /* no gamma tables */
810 md->model_flags |= MD_NO_GAMMA;
811
812 /* check whether the device supports transparency media adapters */
813 if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_TMA )
814 {
815 status = scsi_read_attributes(&md->info[0],
816 md->name, MD_SOURCE_TMA);
817 if ( status != SANE_STATUS_GOOD )
818 return status;
819 }
820
821 /* check whether the device supports an ADF */
822 if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_ADF )
823 {
824 status = scsi_read_attributes(&md->info[0],
825 md->name, MD_SOURCE_ADF);
826 if ( status != SANE_STATUS_GOOD )
827 return status;
828 }
829
830 /* check whether the device supports STRIPES */
831 if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_STRIPE )
832 {
833 status = scsi_read_attributes(&md->info[0],
834 md->name, MD_SOURCE_STRIPE);
835 if ( status != SANE_STATUS_GOOD )
836 return status;
837 }
838
839 /* check whether the device supports SLIDES */
840 if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_SLIDE )
841 {
842 /* The Phantom 636cx indicates in its attributes that it supports */
843 /* slides, but it doesn't. Thus this command would fail. */
844
845 if ( ! (md->model_flags & MD_NO_SLIDE_MODE) )
846 {
847 status = scsi_read_attributes(&md->info[0],
848 md->name, MD_SOURCE_SLIDE);
849 if ( status != SANE_STATUS_GOOD )
850 return status;
851 }
852 }
853
854 status = scsi_read_system_status(md, -1);
855 if ( status != SANE_STATUS_GOOD )
856 return status;
857
858 return SANE_STATUS_GOOD;
859 }
860
861
862 /*---------- attach_one() ----------------------------------------------------*/
863
864 static SANE_Status
attach_one(const char * name)865 attach_one (const char *name)
866 {
867 Microtek2_Device *md;
868 Microtek2_Device *md_tmp;
869
870
871 DBG(30, "attach_one: name='%s'\n", name);
872
873 md_tmp = md_first_dev;
874 /* if add_device_list() adds an entry it does this at the beginning */
875 /* of the list and thus changes md_first_dev */
876 add_device_list(name, &md);
877 if ( md_tmp != md_first_dev )
878 attach(md);
879
880 return SANE_STATUS_GOOD;
881 }
882
883 /*---------- cancel_scan() ---------------------------------------------------*/
884
885 static SANE_Status
cancel_scan(Microtek2_Scanner * ms)886 cancel_scan(Microtek2_Scanner *ms)
887 {
888 SANE_Status status;
889
890
891 DBG(30, "cancel_scan: ms=%p\n", (void *) ms);
892
893 /* READ IMAGE with a transferlength of 0 aborts a scan */
894 ms->transfer_length = 0;
895 status = scsi_read_image(ms, (uint8_t *) NULL, 1);
896 if ( status != SANE_STATUS_GOOD )
897 {
898 DBG(1, "cancel_scan: cancel failed: '%s'\n", sane_strstatus(status));
899 status = SANE_STATUS_IO_ERROR;
900 }
901 else
902 status = SANE_STATUS_CANCELLED;
903
904 close(ms->fd[1]);
905
906 /* if we are aborting a scan because, for example, we run out
907 of material on a feeder, then pid may be already -1 and
908 kill(-1, SIGTERM), i.e. killing all our processes, is not
909 likely what we really want - --mj, 2001/Nov/19 */
910 if (sanei_thread_is_valid (ms->pid))
911 {
912 sanei_thread_kill(ms->pid);
913 sanei_thread_waitpid(ms->pid, NULL);
914 }
915
916 return status;
917 }
918
919
920 /*---------- check_option() --------------------------------------------------*/
921
922 static void
check_option(const char * cp,Config_Options * co)923 check_option(const char *cp, Config_Options *co)
924 {
925 /* This function analyses options in the config file */
926
927 char *endptr;
928
929 /* When this function is called, it is already made sure that this */
930 /* is an option line, i.e. a line that starts with option */
931
932 cp = sanei_config_skip_whitespace(cp); /* skip blanks */
933 cp = sanei_config_skip_whitespace(cp + 6); /* skip "option" */
934 if ( strncmp(cp, "dump", 4) == 0 && isspace(cp[4]) )
935 {
936 cp = sanei_config_skip_whitespace(cp + 4);
937 if ( *cp )
938 {
939 md_dump = (int) strtol(cp, &endptr, 10);
940 if ( md_dump > 4 || md_dump < 0 )
941 {
942 md_dump = 1;
943 DBG(30, "check_option: setting dump to %d\n", md_dump);
944 }
945 cp = sanei_config_skip_whitespace(endptr);
946 if ( *cp )
947 {
948 /* something behind the option value or value wrong */
949 md_dump = 1;
950 DBG(30, "check_option: option value wrong\n");
951 }
952 }
953 else
954 {
955 DBG(30, "check_option: missing option value\n");
956 /* reasonable fallback */
957 md_dump = 1;
958 }
959 }
960 else if ( strncmp(cp, "strip-height", 12) == 0 && isspace(cp[12]) )
961 {
962 cp = sanei_config_skip_whitespace(cp + 12);
963 if ( *cp )
964 {
965 co->strip_height = strtod(cp, &endptr);
966 DBG(30, "check_option: setting strip_height to %f\n",
967 co->strip_height);
968 if ( co->strip_height <= 0.0 )
969 co->strip_height = 14.0;
970 cp = sanei_config_skip_whitespace(endptr);
971 if ( *cp )
972 {
973 /* something behind the option value or value wrong */
974 co->strip_height = 14.0;
975 DBG(30, "check_option: option value wrong: %f\n",
976 co->strip_height);
977 }
978 }
979 }
980 else if ( strncmp(cp, "no-backtrack-option", 19) == 0
981 && isspace(cp[19]) )
982 {
983 cp = sanei_config_skip_whitespace(cp + 19);
984 if ( strncmp(cp, "on", 2) == 0 )
985 {
986 cp = sanei_config_skip_whitespace(cp + 2);
987 co->no_backtracking = "on";
988 }
989 else if ( strncmp(cp, "off", 3) == 0 )
990 {
991 cp = sanei_config_skip_whitespace(cp + 3);
992 co->no_backtracking = "off";
993 }
994 else
995 co->no_backtracking = "off";
996
997 if ( *cp )
998 {
999 /* something behind the option value or value wrong */
1000 co->no_backtracking = "off";
1001 DBG(30, "check_option: option value wrong: %s\n", cp);
1002 }
1003 }
1004 else if ( strncmp(cp, "lightlid-35", 11) == 0
1005 && isspace(cp[11]) )
1006 {
1007 cp = sanei_config_skip_whitespace(cp + 11);
1008 if ( strncmp(cp, "on", 2) == 0 )
1009 {
1010 cp = sanei_config_skip_whitespace(cp + 2);
1011 co->lightlid35 = "on";
1012 }
1013 else if ( strncmp(cp, "off", 3) == 0 )
1014 {
1015 cp = sanei_config_skip_whitespace(cp + 3);
1016 co->lightlid35 = "off";
1017 }
1018 else
1019 co->lightlid35 = "off";
1020
1021 if ( *cp )
1022 {
1023 /* something behind the option value or value wrong */
1024 co->lightlid35 = "off";
1025 DBG(30, "check_option: option value wrong: %s\n", cp);
1026 }
1027 }
1028 else if ( strncmp(cp, "toggle-lamp", 11) == 0
1029 && isspace(cp[11]) )
1030 {
1031 cp = sanei_config_skip_whitespace(cp + 11);
1032 if ( strncmp(cp, "on", 2) == 0 )
1033 {
1034 cp = sanei_config_skip_whitespace(cp + 2);
1035 co->toggle_lamp = "on";
1036 }
1037 else if ( strncmp(cp, "off", 3) == 0 )
1038 {
1039 cp = sanei_config_skip_whitespace(cp + 3);
1040 co->toggle_lamp = "off";
1041 }
1042 else
1043 co->toggle_lamp = "off";
1044
1045 if ( *cp )
1046 {
1047 /* something behind the option value or value wrong */
1048 co->toggle_lamp = "off";
1049 DBG(30, "check_option: option value wrong: %s\n", cp);
1050 }
1051 }
1052 else if ( strncmp(cp, "lineart-autoadjust", 18) == 0
1053 && isspace(cp[18]) )
1054 {
1055 cp = sanei_config_skip_whitespace(cp + 18);
1056 if ( strncmp(cp, "on", 2) == 0 )
1057 {
1058 cp = sanei_config_skip_whitespace(cp + 2);
1059 co->auto_adjust = "on";
1060 }
1061 else if ( strncmp(cp, "off", 3) == 0 )
1062 {
1063 cp = sanei_config_skip_whitespace(cp + 3);
1064 co->auto_adjust = "off";
1065 }
1066 else
1067 co->auto_adjust = "off";
1068
1069 if ( *cp )
1070 {
1071 /* something behind the option value or value wrong */
1072 co->auto_adjust = "off";
1073 DBG(30, "check_option: option value wrong: %s\n", cp);
1074 }
1075 }
1076 else if ( strncmp(cp, "backend-calibration", 19) == 0
1077 && isspace(cp[19]) )
1078 {
1079 cp = sanei_config_skip_whitespace(cp + 19);
1080 if ( strncmp(cp, "on", 2) == 0 )
1081 {
1082 cp = sanei_config_skip_whitespace(cp + 2);
1083 co->backend_calibration = "on";
1084 }
1085 else if ( strncmp(cp, "off", 3) == 0 )
1086 {
1087 cp = sanei_config_skip_whitespace(cp + 3);
1088 co->backend_calibration = "off";
1089 }
1090 else
1091 co->backend_calibration = "off";
1092
1093 if ( *cp )
1094 {
1095 /* something behind the option value or value wrong */
1096 co->backend_calibration = "off";
1097 DBG(30, "check_option: option value wrong: %s\n", cp);
1098 }
1099 }
1100 else if ( strncmp(cp, "colorbalance-adjust", 19) == 0
1101 && isspace(cp[19]) )
1102 {
1103 cp = sanei_config_skip_whitespace(cp + 19);
1104 if ( strncmp(cp, "on", 2) == 0 )
1105 {
1106 cp = sanei_config_skip_whitespace(cp + 2);
1107 co->colorbalance_adjust = "on";
1108 }
1109 else if ( strncmp(cp, "off", 3) == 0 )
1110 {
1111 cp = sanei_config_skip_whitespace(cp + 3);
1112 co->colorbalance_adjust = "off";
1113 }
1114 else
1115 co->colorbalance_adjust = "off";
1116
1117 if ( *cp )
1118 {
1119 /* something behind the option value or value wrong */
1120 co->colorbalance_adjust = "off";
1121 DBG(30, "check_option: option value wrong: %s\n", cp);
1122 }
1123 }
1124 else
1125 DBG(30, "check_option: invalid option in '%s'\n", cp);
1126 }
1127
1128
1129 /*---------- check_inquiry() -------------------------------------------------*/
1130
1131 static SANE_Status
check_inquiry(Microtek2_Device * md,SANE_String * model_string)1132 check_inquiry(Microtek2_Device *md, SANE_String *model_string)
1133 {
1134 Microtek2_Info *mi;
1135
1136 DBG(30, "check_inquiry: md=%p\n", (void *) md);
1137
1138 md->n_control_bytes = 0;
1139 md->shading_length = 0;
1140 md->shading_table_contents = 0;
1141
1142 mi = &md->info[MD_SOURCE_FLATBED];
1143 if ( mi->scsi_version != MI_SCSI_II_VERSION )
1144 {
1145 DBG(1, "check_inquiry: Device is not a SCSI-II device, but 0x%02x\n",
1146 mi->scsi_version);
1147 return SANE_STATUS_IO_ERROR;
1148 }
1149
1150 if ( mi->device_type != MI_DEVTYPE_SCANNER )
1151 {
1152 DBG(1, "check_inquiry: Device is not a scanner, but 0x%02x\n",
1153 mi->device_type);
1154 return SANE_STATUS_IO_ERROR;
1155 }
1156
1157 if ( strncasecmp("MICROTEK", mi->vendor, INQ_VENDOR_L) != 0
1158 && strncmp(" ", mi->vendor, INQ_VENDOR_L) != 0
1159 && strncmp("AGFA ", mi->vendor, INQ_VENDOR_L) != 0 )
1160 {
1161 DBG(1, "check_inquiry: Device is not a Microtek, but '%.*s'\n",
1162 INQ_VENDOR_L, mi->vendor);
1163 return SANE_STATUS_IO_ERROR;
1164 }
1165
1166 if ( mi->depth & MI_HASDEPTH_16 )
1167 md->shading_depth = 16;
1168 else if ( mi->depth & MI_HASDEPTH_14 )
1169 md->shading_depth = 14;
1170 else if ( mi->depth & MI_HASDEPTH_12 )
1171 md->shading_depth = 12;
1172 else if ( mi->depth & MI_HASDEPTH_10 )
1173 md->shading_depth = 10;
1174 else
1175 md->shading_depth = 8;
1176
1177 switch (mi->model_code)
1178 {
1179 case 0x81:
1180 case 0xab:
1181 *model_string = "ScanMaker 4";
1182 break;
1183 case 0x85:
1184 *model_string = "ScanMaker V300 / ColorPage-EP";
1185 /* The ScanMaker V300 (FW < 2.70) returns some values for the */
1186 /* "read image info" command in only two bytes */
1187 /* and doesn't understand read_image_status */
1188 md->model_flags |= MD_NO_RIS_COMMAND;
1189 if ( md->revision < 2.70 )
1190 md->model_flags |= MD_RII_TWO_BYTES;
1191 break;
1192 case 0x87:
1193 *model_string = "ScanMaker 5";
1194 md->model_flags |= MD_NO_GAMMA;
1195 break;
1196 case 0x89:
1197 *model_string = "ScanMaker 6400XL";
1198 break;
1199 case 0x8a:
1200 *model_string = "ScanMaker 9600XL";
1201 break;
1202 case 0x8c:
1203 *model_string = "ScanMaker 630 / ScanMaker V600";
1204 break;
1205 case 0x8d:
1206 *model_string = "ScanMaker 336 / ScanMaker V310";
1207 break;
1208 case 0x90:
1209 case 0x92:
1210 *model_string = "E3+ / Vobis HighScan";
1211 break;
1212 case 0x91:
1213 *model_string = "ScanMaker X6 / Phantom 636";
1214 /* The X6 indicates a data format of segregated data in TMA mode */
1215 /* but actually transfers as chunky data */
1216 md->model_flags |= MD_DATA_FORMAT_WRONG;
1217 if ( md->revision == 1.00 )
1218 md->model_flags |= MD_OFFSET_2;
1219 break;
1220 case 0x93:
1221 *model_string = "ScanMaker 336 / ScanMaker V310";
1222 break;
1223 case 0x70:
1224 case 0x71:
1225 case 0x94:
1226 case 0xa0:
1227 *model_string = "Phantom 330cx / Phantom 336cx / SlimScan C3";
1228 /* These models do not accept gamma tables. Apparently they */
1229 /* read the control bits and do not accept shading tables */
1230 /* They also don't support enhancements (contrast, brightness...)*/
1231 md->model_flags |= MD_NO_SLIDE_MODE
1232 | MD_NO_GAMMA
1233 #ifndef NO_PHANTOMTYPE_SHADING
1234 | MD_PHANTOM336CX_TYPE_SHADING
1235 #endif
1236 | MD_READ_CONTROL_BIT
1237 | MD_NO_ENHANCEMENTS;
1238 md->opt_backend_calib_default = SANE_TRUE;
1239 md->opt_no_backtrack_default = SANE_TRUE;
1240 md->n_control_bytes = 320;
1241 md->shading_length = 18;
1242 md->shading_depth = 10;
1243 md->controlbit_offset = 7;
1244 break;
1245 case 0x95:
1246 *model_string = "ArtixScan 1010";
1247 break;
1248 case 0x97:
1249 *model_string = "ScanMaker 636";
1250 break;
1251 case 0x98:
1252 *model_string = "ScanMaker X6EL";
1253 if ( md->revision == 1.00 )
1254 md->model_flags |= MD_OFFSET_2;
1255 break;
1256 case 0x99:
1257 *model_string = "ScanMaker X6USB";
1258 if ( md->revision == 1.00 )
1259 md->model_flags |= MD_OFFSET_2;
1260 md->model_flags |= MD_X6_SHORT_TRANSFER;
1261 break;
1262 case 0x9a:
1263 *model_string = "Phantom 636cx / C6";
1264 /* The Phantom 636cx says it supports the SLIDE mode, but it */
1265 /* doesn't. Thus inquring the attributes for slide mode would */
1266 /* fail. Also it does not accept gamma tables. Apparently */
1267 /* it reads the control bits and does not accept shading tables */
1268 md->model_flags |= MD_NO_SLIDE_MODE
1269 | MD_READ_CONTROL_BIT
1270 | MD_NO_GAMMA
1271 | MD_PHANTOM_C6;
1272 md->opt_backend_calib_default = SANE_TRUE;
1273 md->opt_no_backtrack_default = SANE_TRUE;
1274 md->n_control_bytes = 647;
1275 /* md->shading_length = 18; firmware values seem to work better */
1276 md->shading_depth = 12;
1277 md->controlbit_offset = 18;
1278 break;
1279 case 0x9d:
1280 *model_string = "AGFA Duoscan T1200";
1281 break;
1282 case 0xa3:
1283 *model_string = "ScanMaker V6USL";
1284 /* The V6USL does not accept gamma tables */
1285 md->model_flags |= MD_NO_GAMMA;
1286 break;
1287 case 0xa5:
1288 *model_string = "ArtixScan 4000t";
1289 break;
1290 case 0xac:
1291 *model_string = "ScanMaker V6UL";
1292 /* The V6USL does not accept gamma tables, perhaps the V6UL also */
1293 md->model_flags |= MD_NO_GAMMA;
1294 break;
1295 case 0xaf:
1296 *model_string = "SlimScan C3";
1297 md->model_flags |= MD_NO_SLIDE_MODE
1298 | MD_NO_GAMMA
1299 | MD_READ_CONTROL_BIT
1300 | MD_NO_ENHANCEMENTS;
1301 md->opt_backend_calib_default = SANE_TRUE;
1302 md->opt_no_backtrack_default = SANE_TRUE;
1303 md->n_control_bytes = 320;
1304 md->controlbit_offset = 7;
1305 break;
1306 case 0xb0:
1307 *model_string = "ScanMaker X12USL";
1308 md->opt_backend_calib_default = SANE_TRUE;
1309 md->model_flags |= MD_16BIT_TRANSFER
1310 | MD_CALIB_DIVISOR_600;
1311 break;
1312 case 0xb3:
1313 *model_string = "ScanMaker 3600";
1314 break;
1315 case 0xb4:
1316 *model_string = "ScanMaker 4700";
1317 break;
1318 case 0xb6:
1319 *model_string = "ScanMaker V6UPL";
1320 /* is like V6USL but with USB and Parport interface ?? */
1321 md->model_flags |= MD_NO_GAMMA;
1322 break;
1323 case 0xb8:
1324 *model_string = "ScanMaker 3700";
1325 break;
1326 case 0xde:
1327 *model_string = "ScanMaker 9800XL";
1328 md->model_flags |= MD_NO_GAMMA
1329 | MD_16BIT_TRANSFER;
1330 md->opt_backend_calib_default = SANE_TRUE;
1331 md->opt_no_backtrack_default = SANE_TRUE;
1332 break;
1333 default:
1334 DBG(1, "check_inquiry: Model 0x%02x not supported\n", mi->model_code);
1335 return SANE_STATUS_IO_ERROR;
1336 }
1337
1338 return SANE_STATUS_GOOD;
1339 }
1340
1341
1342 /*---------- cleanup_scanner() -----------------------------------------------*/
1343
1344 static void
cleanup_scanner(Microtek2_Scanner * ms)1345 cleanup_scanner(Microtek2_Scanner *ms)
1346 {
1347 DBG(30, "cleanup_scanner: ms=%p, ms->sfd=%d\n", (void *) ms, ms->sfd);
1348
1349 if ( ms->scanning == SANE_TRUE )
1350 cancel_scan(ms);
1351
1352 if ( ms->sfd != -1 )
1353 sanei_scsi_close(ms->sfd);
1354 ms->sfd = -1;
1355 sanei_thread_invalidate(ms->pid);
1356 ms->fp = NULL;
1357 ms->current_pass = 0;
1358 ms->scanning = SANE_FALSE;
1359 ms->cancelled = SANE_FALSE;
1360
1361 /* free buffers */
1362 if ( ms->buf.src_buffer[0] )
1363 {
1364 DBG(100, "free ms->buf.src_buffer[0] at %p\n",
1365 (void *) ms->buf.src_buffer[0]);
1366 free((void *) ms->buf.src_buffer[0]);
1367 ms->buf.src_buffer[0] = NULL;
1368 ms->buf.src_buf = NULL;
1369 }
1370 if ( ms->buf.src_buffer[1] )
1371 {
1372 DBG(100, "free ms->buf.src_buffer[1] at %p\n",
1373 (void *) ms->buf.src_buffer[1]);
1374 free((void *) ms->buf.src_buffer[1]);
1375 ms->buf.src_buffer[1] = NULL;
1376 ms->buf.src_buf = NULL;
1377 }
1378 if ( ms->buf.src_buf )
1379 {
1380 DBG(100, "free ms->buf.src_buf at %p\n", (void *) ms->buf.src_buf);
1381 free((void *) ms->buf.src_buf);
1382 ms->buf.src_buf = NULL;
1383 }
1384 if ( ms->temporary_buffer )
1385 {
1386 DBG(100, "free ms->temporary_buffer at %p\n",
1387 (void *) ms->temporary_buffer);
1388 free((void *) ms->temporary_buffer);
1389 ms->temporary_buffer = NULL;
1390 }
1391 if ( ms->gamma_table )
1392 {
1393 DBG(100, "free ms->gamma_table at %p\n", (void *) ms->gamma_table);
1394 free((void *) ms->gamma_table);
1395 ms->gamma_table = NULL;
1396 }
1397 if ( ms->control_bytes )
1398 {
1399 DBG(100, "free ms->control_bytes at %p\n", (void *) ms->control_bytes);
1400 free((void *) ms->control_bytes);
1401 ms->control_bytes = NULL;
1402 }
1403 if ( ms->condensed_shading_w )
1404 {
1405 DBG(100, "free ms->condensed_shading_w at %p\n",
1406 (void *) ms->condensed_shading_w);
1407 free((void *) ms->condensed_shading_w);
1408 ms->condensed_shading_w = NULL;
1409 }
1410 if ( ms->condensed_shading_d )
1411 {
1412 DBG(100, "free ms->condensed_shading_d at %p\n",
1413 (void *) ms->condensed_shading_d);
1414 free((void *) ms->condensed_shading_d);
1415 ms->condensed_shading_d = NULL;
1416 }
1417
1418 return;
1419 }
1420
1421 #ifdef HAVE_AUTHORIZATION
1422 /*---------- do_authorization() ----------------------------------------------*/
1423
1424 static SANE_Status
do_authorization(char * resource)1425 do_authorization(char *resource)
1426 {
1427 /* This function implements a simple authorization function. It looks */
1428 /* up an entry in the file SANE_PATH_CONFIG_DIR/auth. Such an entry */
1429 /* must be of the form device:user:password where password is a crypt() */
1430 /* encrypted password. If several users are allowed to access a device */
1431 /* an entry must be created for each user. If no entry exists for device */
1432 /* or the file does not exist no authentication is necessary. If the */
1433 /* file exists, but can't be opened the authentication fails */
1434
1435 SANE_Status status;
1436 FILE *fp;
1437 int device_found;
1438 char username[SANE_MAX_USERNAME_LEN];
1439 char password[SANE_MAX_PASSWORD_LEN];
1440 char line[MAX_LINE_LEN];
1441 char *linep;
1442 char *device;
1443 char *user;
1444 char *passwd;
1445 char *p;
1446
1447
1448 DBG(30, "do_authorization: resource=%s\n", resource);
1449
1450 if ( auth_callback == NULL ) /* frontend does not require authorization */
1451 return SANE_STATUS_GOOD;
1452
1453 /* first check if an entry exists in for this device. If not, we don't */
1454 /* use authorization */
1455
1456 fp = fopen(PASSWD_FILE, "r");
1457 if ( fp == NULL )
1458 {
1459 if ( errno == ENOENT )
1460 {
1461 DBG(1, "do_authorization: file not found: %s\n", PASSWD_FILE);
1462 return SANE_STATUS_GOOD;
1463 }
1464 else
1465 {
1466 DBG(1, "do_authorization: fopen() failed, errno=%d\n", errno);
1467 return SANE_STATUS_ACCESS_DENIED;
1468 }
1469 }
1470
1471 linep = &line[0];
1472 device_found = 0;
1473 while ( fgets(line, MAX_LINE_LEN, fp) )
1474 {
1475 p = index(linep, SEPARATOR);
1476 if ( p )
1477 {
1478 *p = '\0';
1479 device = linep;
1480 if ( strcmp(device, resource) == 0 )
1481 {
1482 DBG(2, "equal\n");
1483 device_found = 1;
1484 break;
1485 }
1486 }
1487 }
1488
1489 if ( ! device_found )
1490 {
1491 fclose(fp);
1492 return SANE_STATUS_GOOD;
1493 }
1494
1495 fseek(fp, 0L, SEEK_SET);
1496
1497 (*auth_callback) (resource, username, password);
1498
1499 status = SANE_STATUS_ACCESS_DENIED;
1500 do
1501 {
1502 fgets(line, MAX_LINE_LEN, fp);
1503 if ( ! ferror(fp) && ! feof(fp) )
1504 {
1505 /* neither strsep(3) nor strtok(3) seem to work on my system */
1506 p = index(linep, SEPARATOR);
1507 if ( p == NULL )
1508 continue;
1509 *p = '\0';
1510 device = linep;
1511 if ( strcmp( device, resource) != 0 ) /* not a matching entry */
1512 continue;
1513
1514 linep = ++p;
1515 p = index(linep, SEPARATOR);
1516 if ( p == NULL )
1517 continue;
1518
1519 *p = '\0';
1520 user = linep;
1521 if ( strncmp(user, username, SANE_MAX_USERNAME_LEN) != 0 )
1522 continue; /* username doesn't match */
1523
1524 linep = ++p;
1525 /* rest of the line is considered to be the password */
1526 passwd = linep;
1527 /* remove newline */
1528 *(passwd + strlen(passwd) - 1) = '\0';
1529 p = crypt(password, SALT);
1530 if ( strcmp(p, passwd) == 0 )
1531 {
1532 /* authentication ok */
1533 status = SANE_STATUS_GOOD;
1534 break;
1535 }
1536 else
1537 continue;
1538 }
1539 } while ( ! ferror(fp) && ! feof(fp) );
1540 fclose(fp);
1541
1542 return status;
1543 }
1544 #endif
1545
1546 /*---------- dump_area() -----------------------------------------------------*/
1547
1548 static SANE_Status
dump_area(uint8_t * area,int len,char * info)1549 dump_area(uint8_t *area, int len, char *info)
1550 {
1551 /* this function dumps control or information blocks */
1552
1553 #define BPL 16 /* bytes per line to print */
1554
1555 int i;
1556 int o;
1557 int o_limit;
1558 char outputline[100];
1559 char *outbuf;
1560
1561 if ( ! info[0] )
1562 info = "No additional info available";
1563
1564 DBG(30, "dump_area: %s\n", info);
1565
1566 outbuf = outputline;
1567 o_limit = (len + BPL - 1) / BPL;
1568 for ( o = 0; o < o_limit; o++)
1569 {
1570 sprintf(outbuf, " %4d: ", o * BPL);
1571 outbuf += 8;
1572 for ( i=0; i < BPL && (o * BPL + i ) < len; i++)
1573 {
1574 if ( i == BPL / 2 )
1575 {
1576 sprintf(outbuf, " ");
1577 outbuf +=1;
1578 }
1579 sprintf(outbuf, "%02x", area[o * BPL + i]);
1580 outbuf += 2;
1581 }
1582
1583 sprintf(outbuf, "%*s", 2 * ( 2 + BPL - i), " " );
1584 outbuf += (2 * ( 2 + BPL - i));
1585 sprintf(outbuf, "%s", (i == BPL / 2) ? " " : "");
1586 outbuf += ((i == BPL / 2) ? 1 : 0);
1587
1588 for ( i = 0; i < BPL && (o * BPL + i ) < len; i++)
1589 {
1590 if ( i == BPL / 2 )
1591 {
1592 sprintf(outbuf, " ");
1593 outbuf += 1;
1594 }
1595 sprintf(outbuf, "%c", isprint(area[o * BPL + i])
1596 ? area[o * BPL + i]
1597 : '.');
1598 outbuf += 1;
1599 }
1600 outbuf = outputline;
1601 DBG(1, "%s\n", outbuf);
1602 }
1603
1604 return SANE_STATUS_GOOD;
1605 }
1606
1607
1608 /*---------- dump_area2() ----------------------------------------------------*/
1609
1610 static SANE_Status
dump_area2(uint8_t * area,int len,char * info)1611 dump_area2(uint8_t *area, int len, char *info)
1612 {
1613
1614 #define BPL 16 /* bytes per line to print */
1615
1616 int i;
1617 char outputline[100];
1618 char *outbuf;
1619
1620 if ( ! info[0] )
1621 info = "No additional info available";
1622
1623 DBG(1, "[%s]\n", info);
1624
1625 outbuf = outputline;
1626 for ( i = 0; i < len; i++)
1627 {
1628 sprintf(outbuf, "%02x,", *(area + i));
1629 outbuf += 3;
1630 if ( ((i+1)%BPL == 0) || (i == len-1) )
1631 {
1632 outbuf = outputline;
1633 DBG(1, "%s\n", outbuf);
1634 }
1635 }
1636
1637 return SANE_STATUS_GOOD;
1638 }
1639
1640 /*---------- dump_to_file() --------------------------------------------------*/
1641 /*--- only for debugging, currently not used -----*/
1642 #if 0
1643 static SANE_Status
1644 dump_to_file(uint8_t *area, int len, char *filename, char *mode)
1645 {
1646 FILE *out;
1647 int i;
1648
1649 out = fopen(filename, mode);
1650
1651 for ( i = 0; i < len; i++)
1652 fputc( *(area + i ), out);
1653
1654 fclose(out);
1655
1656 return SANE_STATUS_GOOD;
1657 }
1658 #endif
1659
1660 /*---------- dump_attributes() -----------------------------------------------*/
1661
1662 static SANE_Status
dump_attributes(Microtek2_Info * mi)1663 dump_attributes(Microtek2_Info *mi)
1664 {
1665 /* dump all we know about the scanner */
1666
1667 int i;
1668
1669 DBG(30, "dump_attributes: mi=%p\n", (void *) mi);
1670 DBG(1, "\n");
1671 DBG(1, "Scanner attributes from device structure\n");
1672 DBG(1, "========================================\n");
1673 DBG(1, "Scanner ID...\n");
1674 DBG(1, "~~~~~~~~~~~~~\n");
1675 DBG(1, " Vendor Name%15s: '%s'\n", " ", mi->vendor);
1676 DBG(1, " Model Name%16s: '%s'\n", " ", mi->model);
1677 DBG(1, " Revision%18s: '%s'\n", " ", mi->revision);
1678 DBG(1, " Model Code%16s: 0x%02x\n"," ", mi->model_code);
1679 switch(mi->model_code)
1680 {
1681 case 0x80: DBG(1, "Redondo 2000XL / ArtixScan 2020\n"); break;
1682 case 0x81: DBG(1, "ScanMaker 4 / Aruba\n"); break;
1683 case 0x82: DBG(1, "Bali\n"); break;
1684 case 0x83: DBG(1, "Washington\n"); break;
1685 case 0x84: DBG(1, "Manhattan\n"); break;
1686 case 0x85: DBG(1, "ScanMaker V300 / Phantom parallel / TR3\n"); break;
1687 case 0x86: DBG(1, "CCP\n"); break;
1688 case 0x87: DBG(1, "Scanmaker V\n"); break;
1689 case 0x88: DBG(1, "Scanmaker VI\n"); break;
1690 case 0x89: DBG(1, "ScanMaker 6400XL / A3-400\n"); break;
1691 case 0x8a: DBG(1, "ScanMaker 9600XL / A3-600\n"); break;
1692 case 0x8b: DBG(1, "Watt\n"); break;
1693 case 0x8c: DBG(1, "ScanMaker V600 / TR6\n"); break;
1694 case 0x8d: DBG(1, "ScanMaker V310 / Tr3 10-bit\n"); break;
1695 case 0x8e: DBG(1, "CCB\n"); break;
1696 case 0x8f: DBG(1, "Sun Rise\n"); break;
1697 case 0x90: DBG(1, "ScanMaker E3+ 10-bit\n"); break;
1698 case 0x91: DBG(1, "ScanMaker X6 / Phantom 636\n"); break;
1699 case 0x92: DBG(1, "ScanMaker E3+ / Vobis Highscan\n"); break;
1700 case 0x93: DBG(1, "ScanMaker V310\n"); break;
1701 case 0x94: DBG(1, "SlimScan C3 / Phantom 330cx / 336cx\n"); break;
1702 case 0x95: DBG(1, "ArtixScan 1010\n"); break;
1703 case 0x97: DBG(1, "ScanMaker V636\n"); break;
1704 case 0x98: DBG(1, "ScanMaker X6EL\n"); break;
1705 case 0x99: DBG(1, "ScanMaker X6 / X6USB\n"); break;
1706 case 0x9a: DBG(1, "SlimScan C6 / Phantom 636cx\n"); break;
1707 case 0x9d: DBG(1, "AGFA DuoScan T1200\n"); break;
1708 case 0xa0: DBG(1, "SlimScan C3 / Phantom 336cx\n"); break;
1709 case 0xac: DBG(1, "ScanMaker V6UL\n"); break;
1710 case 0xa3: DBG(1, "ScanMaker V6USL\n"); break;
1711 case 0xaf: DBG(1, "SlimScan C3 / Phantom 336cx\n"); break;
1712 case 0xb0: DBG(1, "ScanMaker X12USL\n"); break;
1713 case 0xb3: DBG(1, "ScanMaker 3600\n"); break;
1714 case 0xb4: DBG(1, "ScanMaker 4700\n"); break;
1715 case 0xb6: DBG(1, "ScanMaker V6UPL\n"); break;
1716 case 0xb8: DBG(1, "ScanMaker 3700\n"); break;
1717 case 0xde: DBG(1, "ScanMaker 9800XL\n"); break;
1718 default: DBG(1, "Unknown\n"); break;
1719 }
1720 DBG(1, " Device Type Code%10s: 0x%02x (%s),\n", " ",
1721 mi->device_type,
1722 mi->device_type & MI_DEVTYPE_SCANNER ?
1723 "Scanner" : "Unknown type");
1724
1725 switch (mi->scanner_type)
1726 {
1727 case MI_TYPE_FLATBED:
1728 DBG(1, " Scanner type%14s:%s", " ", " Flatbed scanner\n");
1729 break;
1730 case MI_TYPE_TRANSPARENCY:
1731 DBG(1, " Scanner type%14s:%s", " ", " Transparency scanner\n");
1732 break;
1733 case MI_TYPE_SHEEDFEED:
1734 DBG(1, " Scanner type%14s:%s", " ", " Sheet feed scanner\n");
1735 break;
1736 default:
1737 DBG(1, " Scanner type%14s:%s", " ", " Unknown\n");
1738 break;
1739 }
1740
1741 DBG(1, " Supported options%9s: Automatic document feeder: %s\n",
1742 " ", mi->option_device & MI_OPTDEV_ADF ? "Yes" : "No");
1743 DBG(1, "%30sTransparency media adapter: %s\n",
1744 " ", mi->option_device & MI_OPTDEV_TMA ? "Yes" : "No");
1745 DBG(1, "%30sAuto paper detecting: %s\n",
1746 " ", mi->option_device & MI_OPTDEV_ADP ? "Yes" : "No");
1747 DBG(1, "%30sAdvanced picture system: %s\n",
1748 " ", mi->option_device & MI_OPTDEV_APS ? "Yes" : "No");
1749 DBG(1, "%30sStripes: %s\n",
1750 " ", mi->option_device & MI_OPTDEV_STRIPE ? "Yes" : "No");
1751 DBG(1, "%30sSlides: %s\n",
1752 " ", mi->option_device & MI_OPTDEV_SLIDE ? "Yes" : "No");
1753 DBG(1, " Scan button%15s: %s\n", " ", mi->scnbuttn ? "Yes" : "No");
1754
1755 DBG(1, "\n");
1756 DBG(1, " Imaging Capabilities...\n");
1757 DBG(1, " ~~~~~~~~~~~~~~~~~~~~~~~\n");
1758 DBG(1, " Color scanner%6s: %s\n", " ", (mi->color) ? "Yes" : "No");
1759 DBG(1, " Number passes%6s: %d pass%s\n", " ",
1760 (mi->onepass) ? 1 : 3,
1761 (mi->onepass) ? "" : "es");
1762 DBG(1, " Resolution%9s: X-max: %5d dpi\n%35sY-max: %5d dpi\n",
1763 " ", mi->max_xresolution, " ",mi->max_yresolution);
1764 DBG(1, " Geometry%11s: Geometric width: %5d pts (%2.2f'')\n", " ",
1765 mi->geo_width, (float) mi->geo_width / (float) mi->opt_resolution);
1766 DBG(1, "%23sGeometric height:%5d pts (%2.2f'')\n", " ",
1767 mi->geo_height, (float) mi->geo_height / (float) mi->opt_resolution);
1768 DBG(1, " Optical resolution%1s: %d\n", " ", mi->opt_resolution);
1769
1770 DBG(1, " Modes%14s: Lineart: %s\n%35sHalftone: %s\n", " ",
1771 (mi->scanmode & MI_HASMODE_LINEART) ? " Yes" : " No", " ",
1772 (mi->scanmode & MI_HASMODE_HALFTONE) ? "Yes" : "No");
1773
1774 DBG(1, "%23sGray: %s\n%35sColor: %s\n", " ",
1775 (mi->scanmode & MI_HASMODE_GRAY) ? " Yes" : " No", " ",
1776 (mi->scanmode & MI_HASMODE_COLOR) ? " Yes" : " No");
1777
1778 DBG(1, " Depths%14s: Nibble Gray: %s\n",
1779 " ", (mi->depth & MI_HASDEPTH_NIBBLE) ? "Yes" : "No");
1780 DBG(1, "%23s10-bit-color: %s\n",
1781 " ", (mi->depth & MI_HASDEPTH_10) ? "Yes" : "No");
1782 DBG(1, "%23s12-bit-color: %s\n", " ",
1783 (mi->depth & MI_HASDEPTH_12) ? "Yes" : "No");
1784 DBG(1, "%23s14-bit-color: %s\n", " ",
1785 (mi->depth & MI_HASDEPTH_14) ? "Yes" : "No");
1786 DBG(1, "%23s16-bit-color: %s\n", " ",
1787 (mi->depth & MI_HASDEPTH_16) ? "Yes" : "No");
1788 DBG(1, " d/l of HT pattern%2s: %s\n",
1789 " ", (mi->has_dnldptrn) ? "Yes" : "No");
1790 DBG(1, " Builtin HT pattern%1s: %d\n", " ", mi->grain_slct);
1791
1792 if ( MI_LUTCAP_NONE(mi->lut_cap) )
1793 DBG(1, " LUT capabilities : None\n");
1794 if ( mi->lut_cap & MI_LUTCAP_256B )
1795 DBG(1, " LUT capabilities : 256 bytes\n");
1796 if ( mi->lut_cap & MI_LUTCAP_1024B )
1797 DBG(1, " LUT capabilities : 1024 bytes\n");
1798 if ( mi->lut_cap & MI_LUTCAP_1024W )
1799 DBG(1, " LUT capabilities : 1024 words\n");
1800 if ( mi->lut_cap & MI_LUTCAP_4096B )
1801 DBG(1, " LUT capabilities : 4096 bytes\n");
1802 if ( mi->lut_cap & MI_LUTCAP_4096W )
1803 DBG(1, " LUT capabilities : 4096 words\n");
1804 if ( mi->lut_cap & MI_LUTCAP_64k_W )
1805 DBG(1, " LUT capabilities : 64k words\n");
1806 if ( mi->lut_cap & MI_LUTCAP_16k_W )
1807 DBG(1, " LUT capabilities : 16k words\n");
1808 DBG(1, "\n");
1809 DBG(1, " Miscellaneous capabilities...\n");
1810 DBG(1, " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
1811 if ( mi->onepass)
1812 {
1813 switch(mi->data_format)
1814 {
1815 case MI_DATAFMT_CHUNKY:
1816 DBG(1, " Data format :%s",
1817 " Chunky data, R, G & B in one pixel\n");
1818 break;
1819 case MI_DATAFMT_LPLCONCAT:
1820 DBG(1, " Data format :%s",
1821 " Line by line in concatenated sequence,\n");
1822 DBG(1, "%23swithout color indicator\n", " ");
1823 break;
1824 case MI_DATAFMT_LPLSEGREG:
1825 DBG(1, " Data format :%s",
1826 " Line by line in segregated sequence,\n");
1827 DBG(1, "%23swith color indicator\n", " ");
1828 break;
1829 case MI_DATAFMT_WORDCHUNKY:
1830 DBG(1, " Data format : Word chunky data\n");
1831 break;
1832 default:
1833 DBG(1, " Data format : Unknown\n");
1834 break;
1835 }
1836 }
1837 else
1838 DBG(1, "No information with 3-pass scanners\n");
1839
1840 DBG(1, " Color Sequence%17s: \n", " ");
1841 for ( i = 0; i < RSA_COLORSEQUENCE_L; i++)
1842 {
1843 switch(mi->color_sequence[i])
1844 {
1845 case MI_COLSEQ_RED: DBG(1,"%34s%s\n", " ","R"); break;
1846 case MI_COLSEQ_GREEN: DBG(1,"%34s%s\n", " ","G"); break;
1847 case MI_COLSEQ_BLUE: DBG(1,"%34s%s\n", " ","B"); break;
1848 }
1849 }
1850 if ( mi->new_image_status == SANE_TRUE )
1851 DBG(1, " Using new ReadImageStatus format\n");
1852 else
1853 DBG(1, " Using old ReadImageStatus format\n");
1854 if ( mi->direction & MI_DATSEQ_RTOL )
1855 DBG(1, " Scanning direction : right to left\n");
1856 else
1857 DBG(1, " Scanning direction : left to right\n");
1858 DBG(1, " CCD gap%24s: %d lines\n", " ", mi->ccd_gap);
1859 DBG(1, " CCD pixels%21s: %d\n", " ", mi->ccd_pixels);
1860 DBG(1, " Calib white stripe location%4s: %d\n",
1861 " ", mi->calib_white);
1862 DBG(1, " Max calib space%16s: %d\n", " ", mi->calib_space);
1863 DBG(1, " Number of lens%17s: %d\n", " ", mi->nlens);
1864 DBG(1, " Max number of windows%10s: %d\n", " ", mi->nwindows);
1865 DBG(1, " Shading transfer function%6s: 0x%02x\n", " ",mi->shtrnsferequ);
1866 DBG(1, " Red balance%20s: %d\n", " ", mi->balance[0]);
1867 DBG(1, " Green balance%18s: %d\n", " ", mi->balance[1]);
1868 DBG(1, " Blue balance%19s: %d\n", " " , mi->balance[2]);
1869 DBG(1, " Buffer type%20s: %s\n",
1870 " ", mi->buftype ? "Ping-Pong" : "Ring");
1871 DBG(1, " FEPROM%25s: %s\n", " ", mi->feprom ? "Yes" : "No");
1872
1873 md_dump_clear = 0;
1874 return SANE_STATUS_GOOD;
1875 }
1876
1877 /*---------- max_string_size() -----------------------------------------------*/
1878
1879 static size_t
max_string_size(const SANE_String_Const strings[])1880 max_string_size (const SANE_String_Const strings[])
1881 {
1882 size_t size;
1883 size_t max_size = 0;
1884 int i;
1885
1886 for (i = 0; strings[i]; ++i) {
1887 size = strlen(strings[i]) + 1; /* +1 because NUL counts as part of string */
1888 if (size > max_size) max_size = size;
1889 }
1890 return max_size;
1891 }
1892
1893 /*---------- parse_config_file() ---------------------------------------------*/
1894
1895 static void
parse_config_file(FILE * fp,Config_Temp ** ct)1896 parse_config_file(FILE *fp, Config_Temp **ct)
1897 {
1898 /* builds a list of device names with associated options from the */
1899 /* config file for later use, when building the list of devices. */
1900 /* ct->device = NULL indicates global options (valid for all devices */
1901
1902 char s[PATH_MAX];
1903 Config_Options global_opts;
1904 Config_Temp *hct1;
1905 Config_Temp *hct2;
1906
1907
1908 DBG(30, "parse_config_file: fp=%p\n", (void *) fp);
1909
1910 *ct = hct1 = NULL;
1911
1912 /* first read global options and store them in global_opts */
1913 /* initialize global_opts with default values */
1914
1915 global_opts = md_options;
1916
1917 while ( sanei_config_read(s, sizeof(s), fp) )
1918 {
1919 DBG(100, "parse_config_file: read line: %s\n", s);
1920 if ( *s == '#' || *s == '\0' ) /* ignore empty lines and comments */
1921 continue;
1922
1923 if ( strncmp( sanei_config_skip_whitespace(s), "option ", 7) == 0
1924 || strncmp( sanei_config_skip_whitespace(s), "option\t", 7) == 0 )
1925 {
1926 DBG(100, "parse_config_file: found global option %s\n", s);
1927 check_option(s, &global_opts);
1928 }
1929 else /* it is considered a new device */
1930 break;
1931 }
1932
1933 if ( ferror(fp) || feof(fp) )
1934 {
1935 if ( ferror(fp) )
1936 DBG(1, "parse_config_file: fread failed: errno=%d\n", errno);
1937
1938 return;
1939 }
1940
1941 while ( ! feof(fp) && ! ferror(fp) )
1942 {
1943 if ( *s == '#' || *s == '\0' ) /* ignore empty lines and comments */
1944 {
1945 sanei_config_read(s, sizeof(s), fp);
1946 continue;
1947 }
1948
1949 if ( strncmp( sanei_config_skip_whitespace(s), "option ", 7) == 0
1950 || strncmp( sanei_config_skip_whitespace(s), "option\t", 7) == 0 )
1951 {
1952 /* when we enter this loop for the first time we allocate */
1953 /* memory, because the line surely contains a device name, */
1954 /* so hct1 is always != NULL at this point */
1955 DBG(100, "parse_config_file: found device option %s\n", s);
1956 check_option(s, &hct1->opts);
1957 }
1958
1959
1960 else /* it is considered a new device */
1961 {
1962 DBG(100, "parse_config_file: found device %s\n", s);
1963 hct2 = (Config_Temp *) malloc(sizeof(Config_Temp));
1964 if ( hct2 == NULL )
1965 {
1966 DBG(1, "parse_config_file: malloc() failed\n");
1967 return;
1968 }
1969
1970 if ( *ct == NULL ) /* first element */
1971 *ct = hct1 = hct2;
1972
1973 hct1->next = hct2;
1974 hct1 = hct2;
1975
1976 hct1->device = strdup(s);
1977 hct1->opts = global_opts;
1978 hct1->next = NULL;
1979 }
1980 sanei_config_read(s, sizeof(s), fp);
1981 }
1982 /* set filepointer to the beginning of the file */
1983 fseek(fp, 0L, SEEK_SET);
1984 return;
1985 }
1986
1987
1988 /*---------- signal_handler() ------------------------------------------------*/
1989
1990 static void
signal_handler(int signal)1991 signal_handler (int signal)
1992 {
1993 if ( signal == SIGTERM )
1994 {
1995 sanei_scsi_req_flush_all ();
1996 _exit (SANE_STATUS_GOOD);
1997 }
1998 }
1999
2000 /*---------- init_options() --------------------------------------------------*/
2001
2002 static SANE_Status
init_options(Microtek2_Scanner * ms,uint8_t current_scan_source)2003 init_options(Microtek2_Scanner *ms, uint8_t current_scan_source)
2004 {
2005 /* This function is called every time, when the scan source changes. */
2006 /* The option values, that possibly change, are then reinitialized, */
2007 /* whereas the option descriptors and option values that never */
2008 /* change are not */
2009
2010 SANE_Option_Descriptor *sod;
2011 SANE_Status status;
2012 Option_Value *val;
2013 Microtek2_Device *md;
2014 Microtek2_Info *mi;
2015 int tablesize;
2016 int option_size;
2017 int max_gamma_value;
2018 int color;
2019 int i;
2020 static int first_call = 1; /* indicates, whether option */
2021 /* descriptors must be initialized */
2022 /* cannot be used as after a sane_close the sod's must be initialized */
2023
2024 DBG(30, "init_options: handle=%p, source=%d\n", (void *) ms,
2025 current_scan_source);
2026
2027 sod = ms->sod;
2028 val = ms->val;
2029 md = ms->dev;
2030 mi = &md->info[current_scan_source];
2031
2032 /* needed for gamma calculation */
2033 get_lut_size(mi, &md->max_lut_size, &md->lut_entry_size);
2034
2035 /* calculate new values, where possibly needed */
2036
2037 /* Scan source */
2038 if ( val[OPT_SOURCE].s )
2039 free((void *) val[OPT_SOURCE].s);
2040 i = 0;
2041 md->scansource_list[i] = (SANE_String) MD_SOURCESTRING_FLATBED;
2042 if ( current_scan_source == MD_SOURCE_FLATBED )
2043 val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2044 if ( md->status.adfcnt )
2045 {
2046 md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_ADF;
2047 if ( current_scan_source == MD_SOURCE_ADF )
2048 val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2049 }
2050 if ( md->status.tmacnt )
2051 {
2052 md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_TMA;
2053 if ( current_scan_source == MD_SOURCE_TMA )
2054 val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2055 }
2056 if ( mi->option_device & MI_OPTDEV_STRIPE )
2057 {
2058 md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_STRIPE;
2059 if ( current_scan_source == MD_SOURCE_STRIPE )
2060 val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2061 }
2062
2063 /* Comment this out as long as I do not know in which bit */
2064 /* it is indicated, whether a slide adapter is connected */
2065 #if 0
2066 if ( mi->option_device & MI_OPTDEV_SLIDE )
2067 {
2068 md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_SLIDE;
2069 if ( current_scan_source == MD_SOURCE_SLIDE )
2070 val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2071 }
2072 #endif
2073
2074 md->scansource_list[++i] = NULL;
2075
2076 /* Scan mode */
2077 if ( val[OPT_MODE].s )
2078 free((void *) val[OPT_MODE].s);
2079
2080 i = 0;
2081 if ( (mi->scanmode & MI_HASMODE_COLOR) )
2082 {
2083 md->scanmode_list[i] = (SANE_String) MD_MODESTRING_COLOR;
2084 val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2085 ++i;
2086 }
2087
2088 if ( mi->scanmode & MI_HASMODE_GRAY )
2089 {
2090 md->scanmode_list[i] = (SANE_String) MD_MODESTRING_GRAY;
2091 if ( ! (mi->scanmode & MI_HASMODE_COLOR ) )
2092 val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2093 ++i;
2094 }
2095
2096 if ( mi->scanmode & MI_HASMODE_HALFTONE )
2097 {
2098 md->scanmode_list[i] = (SANE_String) MD_MODESTRING_HALFTONE;
2099 if ( ! (mi->scanmode & MI_HASMODE_COLOR )
2100 && ! (mi->scanmode & MI_HASMODE_GRAY ) )
2101 val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2102 ++i;
2103 }
2104
2105 /* Always enable a lineart mode. Some models (X6, FW 1.40) say */
2106 /* that they have no lineart mode. In this case we will do a grayscale */
2107 /* scan and convert it to onebit data */
2108 md->scanmode_list[i] = (SANE_String) MD_MODESTRING_LINEART;
2109 if ( ! (mi->scanmode & MI_HASMODE_COLOR )
2110 && ! (mi->scanmode & MI_HASMODE_GRAY )
2111 && ! (mi->scanmode & MI_HASMODE_HALFTONE ) )
2112 val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2113 ++i;
2114 md->scanmode_list[i] = NULL;
2115
2116 /* bitdepth */
2117 i = 0;
2118
2119 #if 0
2120 if ( mi->depth & MI_HASDEPTH_NIBBLE )
2121 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_4;
2122 #endif
2123
2124 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_8;
2125 if ( mi->depth & MI_HASDEPTH_10 )
2126 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_10;
2127 if ( mi->depth & MI_HASDEPTH_12 )
2128 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_12;
2129 if ( mi->depth & MI_HASDEPTH_14 )
2130 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_14;
2131 if ( mi->depth & MI_HASDEPTH_16 )
2132 md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_16;
2133
2134 md->bitdepth_list[0] = i;
2135 if ( md->bitdepth_list[1] == (SANE_Int) MD_DEPTHVAL_8 )
2136 val[OPT_BITDEPTH].w = md->bitdepth_list[1];
2137 else
2138 val[OPT_BITDEPTH].w = md->bitdepth_list[2];
2139
2140 /* Halftone */
2141 md->halftone_mode_list[0] = (SANE_String) MD_HALFTONE0;
2142 md->halftone_mode_list[1] = (SANE_String) MD_HALFTONE1;
2143 md->halftone_mode_list[2] = (SANE_String) MD_HALFTONE2;
2144 md->halftone_mode_list[3] = (SANE_String) MD_HALFTONE3;
2145 md->halftone_mode_list[4] = (SANE_String) MD_HALFTONE4;
2146 md->halftone_mode_list[5] = (SANE_String) MD_HALFTONE5;
2147 md->halftone_mode_list[6] = (SANE_String) MD_HALFTONE6;
2148 md->halftone_mode_list[7] = (SANE_String) MD_HALFTONE7;
2149 md->halftone_mode_list[8] = (SANE_String) MD_HALFTONE8;
2150 md->halftone_mode_list[9] = (SANE_String) MD_HALFTONE9;
2151 md->halftone_mode_list[10] = (SANE_String) MD_HALFTONE10;
2152 md->halftone_mode_list[11] = (SANE_String) MD_HALFTONE11;
2153 md->halftone_mode_list[12] = NULL;
2154 if ( val[OPT_HALFTONE].s )
2155 free((void *) val[OPT_HALFTONE].s);
2156 val[OPT_HALFTONE].s = strdup(md->halftone_mode_list[0]);
2157
2158 /* Resolution */
2159 md->x_res_range_dpi.min = SANE_FIX(10.0);
2160 md->x_res_range_dpi.max = SANE_FIX(mi->max_xresolution);
2161 md->x_res_range_dpi.quant = SANE_FIX(1.0);
2162 val[OPT_RESOLUTION].w = MIN(MD_RESOLUTION_DEFAULT, md->x_res_range_dpi.max);
2163
2164 md->y_res_range_dpi.min = SANE_FIX(10.0);
2165 md->y_res_range_dpi.max = SANE_FIX(mi->max_yresolution);
2166 md->y_res_range_dpi.quant = SANE_FIX(1.0);
2167 val[OPT_Y_RESOLUTION].w = val[OPT_RESOLUTION].w; /* bind is default */
2168
2169 /* Preview mode */
2170 val[OPT_PREVIEW].w = SANE_FALSE;
2171
2172 /* Geometry */
2173 md->x_range_mm.min = SANE_FIX(0.0);
2174 md->x_range_mm.max = SANE_FIX((double) mi->geo_width
2175 / (double) mi->opt_resolution
2176 * MM_PER_INCH);
2177 md->x_range_mm.quant = SANE_FIX(0.0);
2178 md->y_range_mm.min = SANE_FIX(0.0);
2179 md->y_range_mm.max = SANE_FIX((double) mi->geo_height
2180 / (double) mi->opt_resolution
2181 * MM_PER_INCH);
2182 md->y_range_mm.quant = SANE_FIX(0.0);
2183 val[OPT_TL_X].w = SANE_FIX(0.0);
2184 val[OPT_TL_Y].w = SANE_FIX(0.0);
2185 val[OPT_BR_X].w = md->x_range_mm.max;
2186 val[OPT_BR_Y].w = md->y_range_mm.max;
2187
2188 /* Enhancement group */
2189 val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2190 val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2191 val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2192
2193 /* Gamma */
2194 /* linear gamma must come first */
2195 i = 0;
2196 md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_LINEAR;
2197 md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_SCALAR;
2198 md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_CUSTOM;
2199 if ( val[OPT_GAMMA_MODE].s )
2200 free((void *) val[OPT_GAMMA_MODE].s);
2201 val[OPT_GAMMA_MODE].s = strdup(md->gammamode_list[0]);
2202
2203 md->gammamode_list[i] = NULL;
2204
2205 /* bind gamma */
2206 val[OPT_GAMMA_BIND].w = SANE_TRUE;
2207 val[OPT_GAMMA_SCALAR].w = MD_GAMMA_DEFAULT;
2208 val[OPT_GAMMA_SCALAR_R].w = MD_GAMMA_DEFAULT;
2209 val[OPT_GAMMA_SCALAR_G].w = MD_GAMMA_DEFAULT;
2210 val[OPT_GAMMA_SCALAR_B].w = MD_GAMMA_DEFAULT;
2211
2212 /* If the device supports gamma tables, we allocate memory according */
2213 /* to lookup table capabilities, otherwise we allocate 4096 elements */
2214 /* which is sufficient for a color depth of 12. If the device */
2215 /* does not support gamma tables, we fill the table according to */
2216 /* the actual bit depth, i.e. 256 entries with a range of 0..255 */
2217 /* if the actual bit depth is 8, for example. This will hopefully*/
2218 /* make no trouble if the bit depth is 1. */
2219 if ( md->model_flags & MD_NO_GAMMA )
2220 {
2221 tablesize = 4096;
2222 option_size = (int) pow(2.0, (double) val[OPT_BITDEPTH].w );
2223 max_gamma_value = option_size - 1;
2224 }
2225 else
2226 {
2227 tablesize = md->max_lut_size;
2228 option_size = tablesize;
2229 max_gamma_value = md->max_lut_size - 1;
2230 }
2231
2232 for ( color = 0; color < 4; color++ )
2233 {
2234 /* index 0 is used if bind gamma == true, index 1 to 3 */
2235 /* if bind gamma == false */
2236 if ( md->custom_gamma_table[color] )
2237 free((void *) md->custom_gamma_table[color]);
2238 md->custom_gamma_table[color] =
2239 (SANE_Int *) malloc(tablesize * sizeof(SANE_Int));
2240 DBG(100, "init_options: md->custom_gamma_table[%d]=%p, malloc'd %lu bytes\n",
2241 color, (void *) md->custom_gamma_table[color], (u_long) (tablesize * sizeof(SANE_Int)));
2242 if ( md->custom_gamma_table[color] == NULL )
2243 {
2244 DBG(1, "init_options: malloc for custom gamma table failed\n");
2245 return SANE_STATUS_NO_MEM;
2246 }
2247
2248 for ( i = 0; i < max_gamma_value; i++ )
2249 md->custom_gamma_table[color][i] = i;
2250 }
2251
2252 md->custom_gamma_range.min = 0;
2253 md->custom_gamma_range.max = max_gamma_value;
2254 md->custom_gamma_range.quant = 1;
2255
2256 sod[OPT_GAMMA_CUSTOM].size = option_size * sizeof (SANE_Int);
2257 sod[OPT_GAMMA_CUSTOM_R].size = option_size * sizeof (SANE_Int);
2258 sod[OPT_GAMMA_CUSTOM_G].size = option_size * sizeof (SANE_Int);
2259 sod[OPT_GAMMA_CUSTOM_B].size = option_size * sizeof (SANE_Int);
2260
2261 val[OPT_GAMMA_CUSTOM].wa = &md->custom_gamma_table[0][0];
2262 val[OPT_GAMMA_CUSTOM_R].wa = &md->custom_gamma_table[1][0];
2263 val[OPT_GAMMA_CUSTOM_G].wa = &md->custom_gamma_table[2][0];
2264 val[OPT_GAMMA_CUSTOM_B].wa = &md->custom_gamma_table[3][0];
2265
2266 /* Shadow, midtone, highlight, exposure time */
2267 md->channel_list[0] = (SANE_String) MD_CHANNEL_MASTER;
2268 md->channel_list[1] = (SANE_String) MD_CHANNEL_RED;
2269 md->channel_list[2] = (SANE_String) MD_CHANNEL_GREEN;
2270 md->channel_list[3] = (SANE_String) MD_CHANNEL_BLUE;
2271 md->channel_list[4] = NULL;
2272 if ( val[OPT_CHANNEL].s )
2273 free((void *) val[OPT_CHANNEL].s);
2274 val[OPT_CHANNEL].s = strdup(md->channel_list[0]);
2275 val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2276 val[OPT_SHADOW_R].w = MD_SHADOW_DEFAULT;
2277 val[OPT_SHADOW_G].w = MD_SHADOW_DEFAULT;
2278 val[OPT_SHADOW_B].w = MD_SHADOW_DEFAULT;
2279 val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2280 val[OPT_MIDTONE_R].w = MD_MIDTONE_DEFAULT;
2281 val[OPT_MIDTONE_G].w = MD_MIDTONE_DEFAULT;
2282 val[OPT_MIDTONE_B].w = MD_MIDTONE_DEFAULT;
2283 val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2284 val[OPT_HIGHLIGHT_R].w = MD_HIGHLIGHT_DEFAULT;
2285 val[OPT_HIGHLIGHT_G].w = MD_HIGHLIGHT_DEFAULT;
2286 val[OPT_HIGHLIGHT_B].w = MD_HIGHLIGHT_DEFAULT;
2287 val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2288 val[OPT_EXPOSURE_R].w = MD_EXPOSURE_DEFAULT;
2289 val[OPT_EXPOSURE_G].w = MD_EXPOSURE_DEFAULT;
2290 val[OPT_EXPOSURE_B].w = MD_EXPOSURE_DEFAULT;
2291
2292 /* special options */
2293 val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
2294
2295 /* enable/disable option for backtracking */
2296 val[OPT_DISABLE_BACKTRACK].w = md->opt_no_backtrack_default;
2297
2298 /* enable/disable calibration by backend */
2299 val[OPT_CALIB_BACKEND].w = md->opt_backend_calib_default;
2300
2301 /* turn off the lamp during a scan */
2302 val[OPT_LIGHTLID35].w = SANE_FALSE;
2303
2304 /* auto adjustment of threshold during a lineart scan */
2305 val[OPT_AUTOADJUST].w = SANE_FALSE;
2306
2307 /* color balance (100% means no correction) */
2308 val[OPT_BALANCE_R].w = SANE_FIX(100);
2309 val[OPT_BALANCE_G].w = SANE_FIX(100);
2310 val[OPT_BALANCE_B].w = SANE_FIX(100);
2311
2312 if ( first_call )
2313 {
2314 /* initialize option descriptors and ranges */
2315
2316 /* Percentage range for brightness, contrast */
2317 md->percentage_range.min = 0 << SANE_FIXED_SCALE_SHIFT;
2318 md->percentage_range.max = 200 << SANE_FIXED_SCALE_SHIFT;
2319 md->percentage_range.quant = 1 << SANE_FIXED_SCALE_SHIFT;
2320
2321 md->threshold_range.min = 1;
2322 md->threshold_range.max = 255;
2323 md->threshold_range.quant = 1;
2324
2325 md->scalar_gamma_range.min = SANE_FIX(0.1);
2326 md->scalar_gamma_range.max = SANE_FIX(4.0);
2327 md->scalar_gamma_range.quant = SANE_FIX(0.1);
2328
2329 md->shadow_range.min = 0;
2330 md->shadow_range.max = 253;
2331 md->shadow_range.quant = 1;
2332
2333 md->midtone_range.min = 1;
2334 md->midtone_range.max = 254;
2335 md->midtone_range.quant = 1;
2336
2337 md->highlight_range.min = 2;
2338 md->highlight_range.max = 255;
2339 md->highlight_range.quant = 1;
2340
2341 md->exposure_range.min = 0;
2342 md->exposure_range.max = 510;
2343 md->exposure_range.quant = 2;
2344
2345 md->balance_range.min = 0;
2346 md->balance_range.max = 200 << SANE_FIXED_SCALE_SHIFT;
2347 md->balance_range.quant = 1 << SANE_FIXED_SCALE_SHIFT;
2348
2349 /* default for most options */
2350 for ( i = 0; i < NUM_OPTIONS; i++ )
2351 {
2352 sod[i].type = SANE_TYPE_FIXED;
2353 sod[i].unit = SANE_UNIT_NONE;
2354 sod[i].size = sizeof(SANE_Fixed);
2355 sod[i].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
2356 sod[i].constraint_type = SANE_CONSTRAINT_RANGE;
2357 }
2358
2359 sod[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
2360 sod[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2361 sod[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2362 sod[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2363 sod[OPT_NUM_OPTS].size = sizeof (SANE_Int);
2364 sod[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2365 sod[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
2366 val[OPT_NUM_OPTS].w = NUM_OPTIONS; /* NUM_OPTIONS is no option */
2367 DBG(255, "sod=%p\n", (void *) sod);
2368 DBG(255, "OPT_NUM_OPTS=%d\n", OPT_NUM_OPTS);
2369 DBG(255, "SANE_CAP_SOFT_DETECT=%d\n", SANE_CAP_SOFT_DETECT);
2370 DBG(255, "OPT_NUM_OPTS.cap=%d\n", sod[0].cap);
2371
2372 /* The Scan Mode Group */
2373 sod[OPT_MODE_GROUP].title = M_TITLE_SCANMODEGRP;
2374 sod[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2375 sod[OPT_MODE_GROUP].size = 0;
2376 sod[OPT_MODE_GROUP].desc = "";
2377 sod[OPT_MODE_GROUP].cap = 0;
2378 sod[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2379
2380 /* Scan source */
2381 sod[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
2382 sod[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
2383 sod[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
2384 sod[OPT_SOURCE].type = SANE_TYPE_STRING;
2385 sod[OPT_SOURCE].size = max_string_size(md->scansource_list);
2386 /* if there is only one scan source, deactivate option */
2387 if ( md->scansource_list[1] == NULL )
2388 sod[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
2389 sod[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2390 sod[OPT_SOURCE].constraint.string_list = md->scansource_list;
2391
2392 /* Scan mode */
2393 sod[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2394 sod[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2395 sod[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2396 sod[OPT_MODE].type = SANE_TYPE_STRING;
2397 sod[OPT_MODE].size = max_string_size(md->scanmode_list);
2398 sod[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2399 sod[OPT_MODE].constraint.string_list = md->scanmode_list;
2400
2401 /* Bit depth */
2402 sod[OPT_BITDEPTH].name = SANE_NAME_BIT_DEPTH;
2403 sod[OPT_BITDEPTH].title = SANE_TITLE_BIT_DEPTH;
2404 sod[OPT_BITDEPTH].desc = SANE_DESC_BIT_DEPTH;
2405 sod[OPT_BITDEPTH].type = SANE_TYPE_INT;
2406 sod[OPT_BITDEPTH].unit = SANE_UNIT_BIT;
2407 sod[OPT_BITDEPTH].size = sizeof(SANE_Int);
2408 /* if we have only 8 bit color deactivate this option */
2409 if ( md->bitdepth_list[0] == 1 )
2410 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2411 sod[OPT_BITDEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2412 sod[OPT_BITDEPTH].constraint.word_list = md->bitdepth_list;
2413
2414 /* Halftone */
2415 sod[OPT_HALFTONE].name = SANE_NAME_HALFTONE;
2416 sod[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
2417 sod[OPT_HALFTONE].desc = SANE_DESC_HALFTONE;
2418 sod[OPT_HALFTONE].type = SANE_TYPE_STRING;
2419 sod[OPT_HALFTONE].size = max_string_size(md->halftone_mode_list);
2420 sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2421 sod[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2422 sod[OPT_HALFTONE].constraint.string_list = md->halftone_mode_list;
2423
2424 /* Resolution */
2425 sod[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2426 sod[OPT_RESOLUTION].title = SANE_TITLE_SCAN_X_RESOLUTION;
2427 sod[OPT_RESOLUTION].desc = SANE_DESC_SCAN_X_RESOLUTION;
2428 sod[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
2429 sod[OPT_RESOLUTION].constraint.range = &md->x_res_range_dpi;
2430
2431 sod[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
2432 sod[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
2433 sod[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
2434 sod[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
2435 sod[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
2436 sod[OPT_Y_RESOLUTION].constraint.range = &md->y_res_range_dpi;
2437
2438 /* Preview */
2439 sod[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
2440 sod[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
2441 sod[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
2442 sod[OPT_PREVIEW].type = SANE_TYPE_BOOL;
2443 sod[OPT_PREVIEW].size = sizeof(SANE_Bool);
2444 sod[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
2445
2446 /* Geometry group, for scan area selection */
2447 sod[OPT_GEOMETRY_GROUP].title = M_TITLE_GEOMGRP;
2448 sod[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2449 sod[OPT_GEOMETRY_GROUP].size = 0;
2450 sod[OPT_GEOMETRY_GROUP].desc = "";
2451 sod[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
2452 sod[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2453
2454 sod[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2455 sod[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2456 sod[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2457 sod[OPT_TL_X].unit = SANE_UNIT_MM;
2458 sod[OPT_TL_X].constraint.range = &md->x_range_mm;
2459
2460 sod[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2461 sod[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2462 sod[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2463 sod[OPT_TL_Y].unit = SANE_UNIT_MM;
2464 sod[OPT_TL_Y].constraint.range = &md->y_range_mm;
2465
2466 sod[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2467 sod[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2468 sod[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2469 sod[OPT_BR_X].unit = SANE_UNIT_MM;
2470 sod[OPT_BR_X].constraint.range = &md->x_range_mm;
2471
2472 sod[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2473 sod[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2474 sod[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2475 sod[OPT_BR_Y].unit = SANE_UNIT_MM;
2476 sod[OPT_BR_Y].constraint.range = &md->y_range_mm;
2477
2478 /* Enhancement group */
2479 sod[OPT_ENHANCEMENT_GROUP].title = M_TITLE_ENHANCEGRP;
2480 sod[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2481 sod[OPT_ENHANCEMENT_GROUP].desc = "";
2482 sod[OPT_ENHANCEMENT_GROUP].size = 0;
2483 sod[OPT_ENHANCEMENT_GROUP].cap = 0;
2484 sod[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2485
2486 sod[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2487 sod[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2488 sod[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2489 sod[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
2490 sod[OPT_BRIGHTNESS].constraint.range = &md->percentage_range;
2491
2492 sod[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
2493 sod[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
2494 sod[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
2495 sod[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
2496 sod[OPT_CONTRAST].constraint.range = &md->percentage_range;
2497
2498 sod[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
2499 sod[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
2500 sod[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
2501 sod[OPT_THRESHOLD].type = SANE_TYPE_INT;
2502 sod[OPT_THRESHOLD].size = sizeof(SANE_Int);
2503 sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2504 sod[OPT_THRESHOLD].constraint.range = &md->threshold_range;
2505
2506 /* automatically adjust threshold for a lineart scan */
2507 sod[OPT_AUTOADJUST].name = M_NAME_AUTOADJUST;
2508 sod[OPT_AUTOADJUST].title = M_TITLE_AUTOADJUST;
2509 sod[OPT_AUTOADJUST].desc = M_DESC_AUTOADJUST;
2510 sod[OPT_AUTOADJUST].type = SANE_TYPE_BOOL;
2511 sod[OPT_AUTOADJUST].size = sizeof(SANE_Bool);
2512 sod[OPT_AUTOADJUST].constraint_type = SANE_CONSTRAINT_NONE;
2513 if ( strncmp(md->opts.auto_adjust, "off", 3) == 0 )
2514 sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2515
2516 /* Gamma */
2517 sod[OPT_GAMMA_GROUP].title = "Gamma";
2518 sod[OPT_GAMMA_GROUP].desc = "";
2519 sod[OPT_GAMMA_GROUP].type = SANE_TYPE_GROUP;
2520 sod[OPT_GAMMA_GROUP].size = 0;
2521 sod[OPT_GAMMA_GROUP].cap = 0;
2522 sod[OPT_GAMMA_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2523
2524 sod[OPT_GAMMA_MODE].name = M_NAME_GAMMA_MODE;
2525 sod[OPT_GAMMA_MODE].title = M_TITLE_GAMMA_MODE;
2526 sod[OPT_GAMMA_MODE].desc = M_DESC_GAMMA_MODE;
2527 sod[OPT_GAMMA_MODE].type = SANE_TYPE_STRING;
2528 sod[OPT_GAMMA_MODE].size = max_string_size(md->gammamode_list);
2529 sod[OPT_GAMMA_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2530 sod[OPT_GAMMA_MODE].constraint.string_list = md->gammamode_list;
2531
2532 sod[OPT_GAMMA_BIND].name = M_NAME_GAMMA_BIND;
2533 sod[OPT_GAMMA_BIND].title = M_TITLE_GAMMA_BIND;
2534 sod[OPT_GAMMA_BIND].desc = M_DESC_GAMMA_BIND;
2535 sod[OPT_GAMMA_BIND].type = SANE_TYPE_BOOL;
2536 sod[OPT_GAMMA_BIND].size = sizeof(SANE_Bool);
2537 sod[OPT_GAMMA_BIND].constraint_type = SANE_CONSTRAINT_NONE;
2538
2539 /* this is active if gamma_bind == true and gammamode == scalar */
2540 sod[OPT_GAMMA_SCALAR].name = M_NAME_GAMMA_SCALAR;
2541 sod[OPT_GAMMA_SCALAR].title = M_TITLE_GAMMA_SCALAR;
2542 sod[OPT_GAMMA_SCALAR].desc = M_DESC_GAMMA_SCALAR;
2543 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
2544 sod[OPT_GAMMA_SCALAR].constraint.range = &md->scalar_gamma_range;
2545
2546 sod[OPT_GAMMA_SCALAR_R].name = M_NAME_GAMMA_SCALAR_R;
2547 sod[OPT_GAMMA_SCALAR_R].title = M_TITLE_GAMMA_SCALAR_R;
2548 sod[OPT_GAMMA_SCALAR_R].desc = M_DESC_GAMMA_SCALAR_R;
2549 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
2550 sod[OPT_GAMMA_SCALAR_R].constraint.range = &md->scalar_gamma_range;
2551
2552 sod[OPT_GAMMA_SCALAR_G].name = M_NAME_GAMMA_SCALAR_G;
2553 sod[OPT_GAMMA_SCALAR_G].title = M_TITLE_GAMMA_SCALAR_G;
2554 sod[OPT_GAMMA_SCALAR_G].desc = M_DESC_GAMMA_SCALAR_G;
2555 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
2556 sod[OPT_GAMMA_SCALAR_G].constraint.range = &md->scalar_gamma_range;
2557
2558 sod[OPT_GAMMA_SCALAR_B].name = M_NAME_GAMMA_SCALAR_B;
2559 sod[OPT_GAMMA_SCALAR_B].title = M_TITLE_GAMMA_SCALAR_B;
2560 sod[OPT_GAMMA_SCALAR_B].desc = M_DESC_GAMMA_SCALAR_B;
2561 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
2562 sod[OPT_GAMMA_SCALAR_B].constraint.range = &md->scalar_gamma_range;
2563
2564 sod[OPT_GAMMA_CUSTOM].name = SANE_NAME_GAMMA_VECTOR;
2565 sod[OPT_GAMMA_CUSTOM].title = SANE_TITLE_GAMMA_VECTOR;
2566 sod[OPT_GAMMA_CUSTOM].desc = SANE_DESC_GAMMA_VECTOR;
2567 sod[OPT_GAMMA_CUSTOM].type = SANE_TYPE_INT;
2568 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
2569 sod[OPT_GAMMA_CUSTOM].size = option_size * sizeof (SANE_Int);
2570 sod[OPT_GAMMA_CUSTOM].constraint.range = &md->custom_gamma_range;
2571
2572 sod[OPT_GAMMA_CUSTOM_R].name = SANE_NAME_GAMMA_VECTOR_R;
2573 sod[OPT_GAMMA_CUSTOM_R].title = SANE_TITLE_GAMMA_VECTOR_R;
2574 sod[OPT_GAMMA_CUSTOM_R].desc = SANE_DESC_GAMMA_VECTOR_R;
2575 sod[OPT_GAMMA_CUSTOM_R].type = SANE_TYPE_INT;
2576 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
2577 sod[OPT_GAMMA_CUSTOM_R].size = option_size * sizeof (SANE_Int);
2578 sod[OPT_GAMMA_CUSTOM_R].constraint.range = &md->custom_gamma_range;
2579
2580 sod[OPT_GAMMA_CUSTOM_G].name = SANE_NAME_GAMMA_VECTOR_G;
2581 sod[OPT_GAMMA_CUSTOM_G].title = SANE_TITLE_GAMMA_VECTOR_G;
2582 sod[OPT_GAMMA_CUSTOM_G].desc = SANE_DESC_GAMMA_VECTOR_G;
2583 sod[OPT_GAMMA_CUSTOM_G].type = SANE_TYPE_INT;
2584 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
2585 sod[OPT_GAMMA_CUSTOM_G].size = option_size * sizeof (SANE_Int);
2586 sod[OPT_GAMMA_CUSTOM_G].constraint.range = &md->custom_gamma_range;
2587
2588 sod[OPT_GAMMA_CUSTOM_B].name = SANE_NAME_GAMMA_VECTOR_B;
2589 sod[OPT_GAMMA_CUSTOM_B].title = SANE_TITLE_GAMMA_VECTOR_B;
2590 sod[OPT_GAMMA_CUSTOM_B].desc = SANE_DESC_GAMMA_VECTOR_B;
2591 sod[OPT_GAMMA_CUSTOM_B].type = SANE_TYPE_INT;
2592 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
2593 sod[OPT_GAMMA_CUSTOM_B].size = option_size * sizeof (SANE_Int);
2594 sod[OPT_GAMMA_CUSTOM_B].constraint.range = &md->custom_gamma_range;
2595
2596 /* Shadow, midtone, highlight */
2597 sod[OPT_SMH_GROUP].title = M_TITLE_SMHGRP;
2598 sod[OPT_SMH_GROUP].desc = "";
2599 sod[OPT_SMH_GROUP].type = SANE_TYPE_GROUP;
2600 sod[OPT_SMH_GROUP].size = 0;
2601 sod[OPT_SMH_GROUP].cap = 0;
2602 sod[OPT_SMH_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2603
2604 sod[OPT_CHANNEL].name = M_NAME_CHANNEL;
2605 sod[OPT_CHANNEL].title = M_TITLE_CHANNEL;
2606 sod[OPT_CHANNEL].desc = M_DESC_CHANNEL;
2607 sod[OPT_CHANNEL].type = SANE_TYPE_STRING;
2608 sod[OPT_CHANNEL].size = max_string_size(md->channel_list);
2609 sod[OPT_CHANNEL].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2610 sod[OPT_CHANNEL].constraint.string_list = md->channel_list;
2611
2612 sod[OPT_SHADOW].name = SANE_NAME_SHADOW;
2613 sod[OPT_SHADOW].title = SANE_TITLE_SHADOW;
2614 sod[OPT_SHADOW].desc = SANE_DESC_SHADOW;
2615 sod[OPT_SHADOW].type = SANE_TYPE_INT;
2616 sod[OPT_SHADOW].size = sizeof(SANE_Int);
2617 sod[OPT_SHADOW].constraint.range = &md->shadow_range;
2618
2619 sod[OPT_SHADOW_R].name = SANE_NAME_SHADOW_R;
2620 sod[OPT_SHADOW_R].title = SANE_TITLE_SHADOW_R;
2621 sod[OPT_SHADOW_R].desc = SANE_DESC_SHADOW_R;
2622 sod[OPT_SHADOW_R].type = SANE_TYPE_INT;
2623 sod[OPT_SHADOW_R].size = sizeof(SANE_Int);
2624 sod[OPT_SHADOW_R].constraint.range = &md->shadow_range;
2625
2626 sod[OPT_SHADOW_G].name = SANE_NAME_SHADOW_G;
2627 sod[OPT_SHADOW_G].title = SANE_TITLE_SHADOW_G;
2628 sod[OPT_SHADOW_G].desc = SANE_DESC_SHADOW_G;
2629 sod[OPT_SHADOW_G].type = SANE_TYPE_INT;
2630 sod[OPT_SHADOW_G].size = sizeof(SANE_Int);
2631 sod[OPT_SHADOW_G].constraint.range = &md->shadow_range;
2632
2633 sod[OPT_SHADOW_B].name = SANE_NAME_SHADOW_B;
2634 sod[OPT_SHADOW_B].title = SANE_TITLE_SHADOW_B;
2635 sod[OPT_SHADOW_B].desc = SANE_DESC_SHADOW_B;
2636 sod[OPT_SHADOW_B].type = SANE_TYPE_INT;
2637 sod[OPT_SHADOW_B].size = sizeof(SANE_Int);
2638 sod[OPT_SHADOW_B].constraint.range = &md->shadow_range;
2639
2640 sod[OPT_MIDTONE].name = M_NAME_MIDTONE;
2641 sod[OPT_MIDTONE].title = M_TITLE_MIDTONE;
2642 sod[OPT_MIDTONE].desc = M_DESC_MIDTONE;
2643 sod[OPT_MIDTONE].type = SANE_TYPE_INT;
2644 sod[OPT_MIDTONE].size = sizeof(SANE_Int);
2645 sod[OPT_MIDTONE].constraint.range = &md->midtone_range;
2646
2647 sod[OPT_MIDTONE_R].name = M_NAME_MIDTONE_R;
2648 sod[OPT_MIDTONE_R].title = M_TITLE_MIDTONE_R;
2649 sod[OPT_MIDTONE_R].desc = M_DESC_MIDTONE_R;
2650 sod[OPT_MIDTONE_R].type = SANE_TYPE_INT;
2651 sod[OPT_MIDTONE_R].size = sizeof(SANE_Int);
2652 sod[OPT_MIDTONE_R].constraint.range = &md->midtone_range;
2653
2654 sod[OPT_MIDTONE_G].name = M_NAME_MIDTONE_G;
2655 sod[OPT_MIDTONE_G].title = M_TITLE_MIDTONE_G;
2656 sod[OPT_MIDTONE_G].desc = M_DESC_MIDTONE_G;
2657 sod[OPT_MIDTONE_G].type = SANE_TYPE_INT;
2658 sod[OPT_MIDTONE_G].size = sizeof(SANE_Int);
2659 sod[OPT_MIDTONE_G].constraint.range = &md->midtone_range;
2660
2661 sod[OPT_MIDTONE_B].name = M_NAME_MIDTONE_B;
2662 sod[OPT_MIDTONE_B].title = M_TITLE_MIDTONE_B;
2663 sod[OPT_MIDTONE_B].desc = M_DESC_MIDTONE_B;
2664 sod[OPT_MIDTONE_B].type = SANE_TYPE_INT;
2665 sod[OPT_MIDTONE_B].size = sizeof(SANE_Int);
2666 sod[OPT_MIDTONE_B].constraint.range = &md->midtone_range;
2667
2668 sod[OPT_HIGHLIGHT].name = SANE_NAME_HIGHLIGHT;
2669 sod[OPT_HIGHLIGHT].title = SANE_TITLE_HIGHLIGHT;
2670 sod[OPT_HIGHLIGHT].desc = SANE_DESC_HIGHLIGHT;
2671 sod[OPT_HIGHLIGHT].type = SANE_TYPE_INT;
2672 sod[OPT_HIGHLIGHT].size = sizeof(SANE_Int);
2673 sod[OPT_HIGHLIGHT].constraint.range = &md->highlight_range;
2674
2675 sod[OPT_HIGHLIGHT_R].name = SANE_NAME_HIGHLIGHT_R;
2676 sod[OPT_HIGHLIGHT_R].title = SANE_TITLE_HIGHLIGHT_R;
2677 sod[OPT_HIGHLIGHT_R].desc = SANE_DESC_HIGHLIGHT_R;
2678 sod[OPT_HIGHLIGHT_R].type = SANE_TYPE_INT;
2679 sod[OPT_HIGHLIGHT_R].size = sizeof(SANE_Int);
2680 sod[OPT_HIGHLIGHT_R].constraint.range = &md->highlight_range;
2681
2682 sod[OPT_HIGHLIGHT_G].name = SANE_NAME_HIGHLIGHT_G;
2683 sod[OPT_HIGHLIGHT_G].title = SANE_TITLE_HIGHLIGHT_G;
2684 sod[OPT_HIGHLIGHT_G].desc = SANE_DESC_HIGHLIGHT_G;
2685 sod[OPT_HIGHLIGHT_G].type = SANE_TYPE_INT;
2686 sod[OPT_HIGHLIGHT_G].size = sizeof(SANE_Int);
2687 sod[OPT_HIGHLIGHT_G].constraint.range = &md->highlight_range;
2688
2689 sod[OPT_HIGHLIGHT_B].name = SANE_NAME_HIGHLIGHT_B;
2690 sod[OPT_HIGHLIGHT_B].title = SANE_TITLE_HIGHLIGHT_B;
2691 sod[OPT_HIGHLIGHT_B].desc = SANE_DESC_HIGHLIGHT_B;
2692 sod[OPT_HIGHLIGHT_B].type = SANE_TYPE_INT;
2693 sod[OPT_HIGHLIGHT_B].size = sizeof(SANE_Int);
2694 sod[OPT_HIGHLIGHT_B].constraint.range = &md->highlight_range;
2695
2696 sod[OPT_EXPOSURE].name = SANE_NAME_SCAN_EXPOS_TIME;
2697 sod[OPT_EXPOSURE].title = SANE_TITLE_SCAN_EXPOS_TIME;
2698 sod[OPT_EXPOSURE].desc = SANE_DESC_SCAN_EXPOS_TIME;
2699 sod[OPT_EXPOSURE].type = SANE_TYPE_INT;
2700 sod[OPT_EXPOSURE].unit = SANE_UNIT_PERCENT;
2701 sod[OPT_EXPOSURE].size = sizeof(SANE_Int);
2702 sod[OPT_EXPOSURE].constraint.range = &md->exposure_range;
2703
2704 sod[OPT_EXPOSURE_R].name = SANE_NAME_SCAN_EXPOS_TIME_R;
2705 sod[OPT_EXPOSURE_R].title = SANE_TITLE_SCAN_EXPOS_TIME_R;
2706 sod[OPT_EXPOSURE_R].desc = SANE_DESC_SCAN_EXPOS_TIME_R;
2707 sod[OPT_EXPOSURE_R].type = SANE_TYPE_INT;
2708 sod[OPT_EXPOSURE_R].unit = SANE_UNIT_PERCENT;
2709 sod[OPT_EXPOSURE_R].size = sizeof(SANE_Int);
2710 sod[OPT_EXPOSURE_R].constraint.range = &md->exposure_range;
2711
2712 sod[OPT_EXPOSURE_G].name = SANE_NAME_SCAN_EXPOS_TIME_G;
2713 sod[OPT_EXPOSURE_G].title = SANE_TITLE_SCAN_EXPOS_TIME_G;
2714 sod[OPT_EXPOSURE_G].desc = SANE_DESC_SCAN_EXPOS_TIME_G;
2715 sod[OPT_EXPOSURE_G].type = SANE_TYPE_INT;
2716 sod[OPT_EXPOSURE_G].unit = SANE_UNIT_PERCENT;
2717 sod[OPT_EXPOSURE_G].size = sizeof(SANE_Int);
2718 sod[OPT_EXPOSURE_G].constraint.range = &md->exposure_range;
2719
2720 sod[OPT_EXPOSURE_B].name = SANE_NAME_SCAN_EXPOS_TIME_B;
2721 sod[OPT_EXPOSURE_B].title = SANE_TITLE_SCAN_EXPOS_TIME_B;
2722 sod[OPT_EXPOSURE_B].desc = SANE_DESC_SCAN_EXPOS_TIME_B;
2723 sod[OPT_EXPOSURE_B].type = SANE_TYPE_INT;
2724 sod[OPT_EXPOSURE_B].unit = SANE_UNIT_PERCENT;
2725 sod[OPT_EXPOSURE_B].size = sizeof(SANE_Int);
2726 sod[OPT_EXPOSURE_B].constraint.range = &md->exposure_range;
2727
2728 /* The Special Options Group */
2729 sod[OPT_SPECIAL].title = M_TITLE_SPECIALGRP;
2730 sod[OPT_SPECIAL].type = SANE_TYPE_GROUP;
2731 sod[OPT_SPECIAL].size = 0;
2732 sod[OPT_SPECIAL].desc = "";
2733 sod[OPT_SPECIAL].cap = SANE_CAP_ADVANCED;
2734 sod[OPT_SPECIAL].constraint_type = SANE_CONSTRAINT_NONE;
2735
2736 sod[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
2737 sod[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
2738 sod[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
2739 sod[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
2740 sod[OPT_RESOLUTION_BIND].size = sizeof(SANE_Bool);
2741 sod[OPT_RESOLUTION_BIND].cap |= SANE_CAP_ADVANCED;
2742 sod[OPT_RESOLUTION_BIND].constraint_type = SANE_CONSTRAINT_NONE;
2743
2744 /* enable/disable option for backtracking */
2745 sod[OPT_DISABLE_BACKTRACK].name = M_NAME_NOBACKTRACK;
2746 sod[OPT_DISABLE_BACKTRACK].title = M_TITLE_NOBACKTRACK;
2747 sod[OPT_DISABLE_BACKTRACK].desc = M_DESC_NOBACKTRACK;
2748 sod[OPT_DISABLE_BACKTRACK].type = SANE_TYPE_BOOL;
2749 sod[OPT_DISABLE_BACKTRACK].size = sizeof(SANE_Bool);
2750 sod[OPT_DISABLE_BACKTRACK].cap |= SANE_CAP_ADVANCED;
2751 sod[OPT_DISABLE_BACKTRACK].constraint_type = SANE_CONSTRAINT_NONE;
2752 if ( strncmp(md->opts.no_backtracking, "off", 3) == 0 )
2753 sod[OPT_DISABLE_BACKTRACK].cap |= SANE_CAP_INACTIVE;
2754
2755 /* calibration by driver */
2756 sod[OPT_CALIB_BACKEND].name = M_NAME_CALIBBACKEND;
2757 sod[OPT_CALIB_BACKEND].title = M_TITLE_CALIBBACKEND;
2758 sod[OPT_CALIB_BACKEND].desc = M_DESC_CALIBBACKEND;
2759 sod[OPT_CALIB_BACKEND].type = SANE_TYPE_BOOL;
2760 sod[OPT_CALIB_BACKEND].size = sizeof(SANE_Bool);
2761 sod[OPT_CALIB_BACKEND].cap |= SANE_CAP_ADVANCED;
2762 sod[OPT_CALIB_BACKEND].constraint_type = SANE_CONSTRAINT_NONE;
2763 if ( strncmp(md->opts.backend_calibration, "off", 3) == 0 )
2764 sod[OPT_CALIB_BACKEND].cap |= SANE_CAP_INACTIVE;
2765
2766 /* turn off the lamp of the flatbed during a scan */
2767 sod[OPT_LIGHTLID35].name = M_NAME_LIGHTLID35;
2768 sod[OPT_LIGHTLID35].title = M_TITLE_LIGHTLID35;
2769 sod[OPT_LIGHTLID35].desc = M_DESC_LIGHTLID35;
2770 sod[OPT_LIGHTLID35].type = SANE_TYPE_BOOL;
2771 sod[OPT_LIGHTLID35].size = sizeof(SANE_Bool);
2772 sod[OPT_LIGHTLID35].cap |= SANE_CAP_ADVANCED;
2773 sod[OPT_LIGHTLID35].constraint_type = SANE_CONSTRAINT_NONE;
2774 if ( strncmp(md->opts.lightlid35, "off", 3) == 0 )
2775 sod[OPT_LIGHTLID35].cap |= SANE_CAP_INACTIVE;
2776
2777 /* toggle the lamp of the flatbed */
2778 sod[OPT_TOGGLELAMP].name = M_NAME_TOGGLELAMP;
2779 sod[OPT_TOGGLELAMP].title = M_TITLE_TOGGLELAMP;
2780 sod[OPT_TOGGLELAMP].desc = M_DESC_TOGGLELAMP;
2781 sod[OPT_TOGGLELAMP].type = SANE_TYPE_BUTTON;
2782 sod[OPT_TOGGLELAMP].size = 0;
2783 sod[OPT_TOGGLELAMP].cap |= SANE_CAP_ADVANCED;
2784 sod[OPT_TOGGLELAMP].constraint_type = SANE_CONSTRAINT_NONE;
2785 if ( strncmp(md->opts.toggle_lamp, "off", 3) == 0 )
2786 sod[OPT_TOGGLELAMP].cap |= SANE_CAP_INACTIVE;
2787
2788 /* color balance */
2789 sod[OPT_COLORBALANCE].title = M_TITLE_COLBALANCEGRP;
2790 sod[OPT_COLORBALANCE].type = SANE_TYPE_GROUP;
2791 sod[OPT_COLORBALANCE].size = 0;
2792 sod[OPT_COLORBALANCE].desc = "";
2793 sod[OPT_COLORBALANCE].cap = SANE_CAP_ADVANCED;
2794 sod[OPT_COLORBALANCE].constraint_type = SANE_CONSTRAINT_NONE;
2795
2796 sod[OPT_BALANCE_R].name = M_NAME_BALANCE_R;
2797 sod[OPT_BALANCE_R].title = M_TITLE_BALANCE_R;
2798 sod[OPT_BALANCE_R].desc = M_DESC_BALANCE_R;
2799 sod[OPT_BALANCE_R].unit = SANE_UNIT_PERCENT;
2800 sod[OPT_BALANCE_R].cap |= SANE_CAP_ADVANCED;
2801 sod[OPT_BALANCE_R].constraint.range = &md->balance_range;
2802 if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2803 sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2804
2805 sod[OPT_BALANCE_G].name = M_NAME_BALANCE_G;
2806 sod[OPT_BALANCE_G].title = M_TITLE_BALANCE_G;
2807 sod[OPT_BALANCE_G].desc = M_DESC_BALANCE_G;
2808 sod[OPT_BALANCE_G].unit = SANE_UNIT_PERCENT;
2809 sod[OPT_BALANCE_G].cap |= SANE_CAP_ADVANCED;
2810 sod[OPT_BALANCE_G].constraint.range = &md->balance_range;
2811 if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2812 sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2813
2814 sod[OPT_BALANCE_B].name = M_NAME_BALANCE_B;
2815 sod[OPT_BALANCE_B].title = M_TITLE_BALANCE_B;
2816 sod[OPT_BALANCE_B].desc = M_DESC_BALANCE_B;
2817 sod[OPT_BALANCE_B].unit = SANE_UNIT_PERCENT;
2818 sod[OPT_BALANCE_B].cap |= SANE_CAP_ADVANCED;
2819 sod[OPT_BALANCE_B].constraint.range = &md->balance_range;
2820 if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2821 sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2822
2823 sod[OPT_BALANCE_FW].name = M_NAME_BALANCE_FW;
2824 sod[OPT_BALANCE_FW].title = M_TITLE_BALANCE_FW;
2825 sod[OPT_BALANCE_FW].desc = M_DESC_BALANCE_FW;
2826 sod[OPT_BALANCE_FW].type = SANE_TYPE_BUTTON;
2827 sod[OPT_BALANCE_FW].size = 0;
2828 sod[OPT_BALANCE_FW].cap |= SANE_CAP_ADVANCED;
2829 sod[OPT_BALANCE_FW].constraint_type = SANE_CONSTRAINT_NONE;
2830 if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2831 sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2832 }
2833
2834 status = set_option_dependencies(ms, sod, val);
2835 if ( status != SANE_STATUS_GOOD )
2836 return status;
2837
2838 return SANE_STATUS_GOOD;
2839 }
2840
2841 /*---------- set_option_dependencies() ---------------------------------------*/
2842
2843 static SANE_Status
set_option_dependencies(Microtek2_Scanner * ms,SANE_Option_Descriptor * sod,Option_Value * val)2844 set_option_dependencies(Microtek2_Scanner *ms, SANE_Option_Descriptor *sod,
2845 Option_Value *val)
2846 {
2847
2848 Microtek2_Device *md;
2849 md = ms->dev;
2850
2851 DBG(40, "set_option_dependencies: val=%p, sod=%p, mode=%s\n",
2852 (void *) val, (void *) sod, val[OPT_MODE].s);
2853
2854 if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
2855 {
2856 /* activate brightness,..., deactivate halftone pattern */
2857 /* and threshold */
2858 sod[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
2859 sod[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
2860 sod[OPT_CHANNEL].cap &= ~SANE_CAP_INACTIVE;
2861 sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
2862 sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
2863 sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
2864 sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
2865 sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2866 sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2867 if ( md->bitdepth_list[0] != 1 )
2868 sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE;
2869 else
2870 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2871 sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2872 if ( ! ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 ) )
2873 {
2874 sod[OPT_BALANCE_R].cap &= ~SANE_CAP_INACTIVE;
2875 sod[OPT_BALANCE_G].cap &= ~SANE_CAP_INACTIVE;
2876 sod[OPT_BALANCE_B].cap &= ~SANE_CAP_INACTIVE;
2877 sod[OPT_BALANCE_FW].cap &= ~SANE_CAP_INACTIVE;
2878 }
2879 /* reset options values that are inactive to their default */
2880 val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2881 }
2882
2883 else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
2884 {
2885 sod[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
2886 sod[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
2887 sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2888 sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
2889 sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
2890 sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
2891 sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
2892 sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2893 sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2894 if ( md->bitdepth_list[0] != 1 )
2895 sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE;
2896 else
2897 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2898 sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2899 sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2900 sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2901 sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2902 sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2903
2904 /* reset options values that are inactive to their default */
2905 if ( val[OPT_CHANNEL].s )
2906 free((void *) val[OPT_CHANNEL].s);
2907 val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2908 }
2909
2910 else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0 )
2911 {
2912 sod[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2913 sod[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2914 sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2915 sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
2916 sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
2917 sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
2918 sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
2919 sod[OPT_HALFTONE].cap &= ~SANE_CAP_INACTIVE;
2920 sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2921 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2922 sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2923 sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2924 sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2925 sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2926 sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2927
2928 /* reset options values that are inactive to their default */
2929 val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2930 val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2931 if ( val[OPT_CHANNEL].s )
2932 free((void *) val[OPT_CHANNEL].s);
2933 val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2934 val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2935 val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2936 val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2937 val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2938 val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2939 }
2940
2941 else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
2942 {
2943 sod[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2944 sod[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2945 sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2946 sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
2947 sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
2948 sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
2949 sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
2950 sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2951 if ( val[OPT_AUTOADJUST].w == SANE_FALSE )
2952 sod[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
2953 else
2954 sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2955 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2956 sod[OPT_AUTOADJUST].cap &= ~SANE_CAP_INACTIVE;
2957 sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2958 sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2959 sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2960 sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2961
2962 /* reset options values that are inactive to their default */
2963 val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2964 val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2965 if ( val[OPT_CHANNEL].s )
2966 free((void *) val[OPT_CHANNEL].s);
2967 val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2968 val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2969 val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2970 val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2971 val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2972 }
2973
2974 else
2975 {
2976 DBG(1, "set_option_dependencies: unknown mode '%s'\n",
2977 val[OPT_MODE].s );
2978 return SANE_STATUS_INVAL;
2979 }
2980
2981 /* these ones are always inactive if the mode changes */
2982 sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
2983 sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
2984 sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
2985 sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
2986 sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
2987 sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
2988 sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
2989 sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
2990 sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
2991 sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
2992 sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
2993 sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
2994
2995 /* reset options values that are inactive to their default */
2996 val[OPT_SHADOW_R].w = val[OPT_SHADOW_G].w = val[OPT_SHADOW_B].w
2997 = MD_SHADOW_DEFAULT;
2998 val[OPT_MIDTONE_R].w = val[OPT_MIDTONE_G].w = val[OPT_MIDTONE_B].w
2999 = MD_MIDTONE_DEFAULT;
3000 val[OPT_HIGHLIGHT_R].w = val[OPT_HIGHLIGHT_G].w = val[OPT_HIGHLIGHT_B].w
3001 = MD_HIGHLIGHT_DEFAULT;
3002 val[OPT_EXPOSURE_R].w = val[OPT_EXPOSURE_G].w = val[OPT_EXPOSURE_B].w
3003 = MD_EXPOSURE_DEFAULT;
3004
3005 if ( SANE_OPTION_IS_SETTABLE(sod[OPT_GAMMA_MODE].cap) )
3006 {
3007 restore_gamma_options(sod, val);
3008 }
3009
3010 return SANE_STATUS_GOOD;
3011 }
3012
3013 /*---------- sane_control_option() -------------------------------------------*/
3014
3015 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * value,SANE_Int * info)3016 sane_control_option(SANE_Handle handle, SANE_Int option,
3017 SANE_Action action, void *value, SANE_Int *info)
3018 {
3019 Microtek2_Scanner *ms = handle;
3020 Microtek2_Device *md;
3021 Microtek2_Info *mi;
3022 Option_Value *val;
3023 SANE_Option_Descriptor *sod;
3024 SANE_Status status;
3025
3026 md = ms->dev;
3027 val = &ms->val[0];
3028 sod = &ms->sod[0];
3029 mi = &md->info[md->scan_source];
3030
3031 if ( ms->scanning )
3032 return SANE_STATUS_DEVICE_BUSY;
3033
3034 if ( option < 0 || option >= NUM_OPTIONS )
3035 {
3036 DBG(100, "sane_control_option: option %d; action %d \n", option, action);
3037 DBG(10, "sane_control_option: option %d invalid\n", option);
3038 return SANE_STATUS_INVAL;
3039 }
3040
3041 if ( ! SANE_OPTION_IS_ACTIVE(ms->sod[option].cap) )
3042 {
3043 DBG(100, "sane_control_option: option %d; action %d \n", option, action);
3044 DBG(10, "sane_control_option: option %d not active\n", option);
3045 return SANE_STATUS_INVAL;
3046 }
3047
3048 if ( info )
3049 *info = 0;
3050
3051 switch ( action )
3052 {
3053 case SANE_ACTION_GET_VALUE: /* read out option values */
3054 switch ( option )
3055 {
3056 /* word options */
3057 case OPT_BITDEPTH:
3058 case OPT_RESOLUTION:
3059 case OPT_Y_RESOLUTION:
3060 case OPT_THRESHOLD:
3061 case OPT_TL_X:
3062 case OPT_TL_Y:
3063 case OPT_BR_X:
3064 case OPT_BR_Y:
3065 case OPT_PREVIEW:
3066 case OPT_BRIGHTNESS:
3067 case OPT_CONTRAST:
3068 case OPT_SHADOW:
3069 case OPT_SHADOW_R:
3070 case OPT_SHADOW_G:
3071 case OPT_SHADOW_B:
3072 case OPT_MIDTONE:
3073 case OPT_MIDTONE_R:
3074 case OPT_MIDTONE_G:
3075 case OPT_MIDTONE_B:
3076 case OPT_HIGHLIGHT:
3077 case OPT_HIGHLIGHT_R:
3078 case OPT_HIGHLIGHT_G:
3079 case OPT_HIGHLIGHT_B:
3080 case OPT_EXPOSURE:
3081 case OPT_EXPOSURE_R:
3082 case OPT_EXPOSURE_G:
3083 case OPT_EXPOSURE_B:
3084 case OPT_GAMMA_SCALAR:
3085 case OPT_GAMMA_SCALAR_R:
3086 case OPT_GAMMA_SCALAR_G:
3087 case OPT_GAMMA_SCALAR_B:
3088 case OPT_BALANCE_R:
3089 case OPT_BALANCE_G:
3090 case OPT_BALANCE_B:
3091
3092 *(SANE_Word *) value = val[option].w;
3093
3094 if (sod[option].type == SANE_TYPE_FIXED )
3095 DBG(50, "sane_control_option: opt=%d, act=%d, val=%f\n",
3096 option, action, SANE_UNFIX(val[option].w));
3097 else
3098 DBG(50, "sane_control_option: opt=%d, act=%d, val=%d\n",
3099 option, action, val[option].w);
3100
3101 return SANE_STATUS_GOOD;
3102
3103 /* boolean options */
3104 case OPT_RESOLUTION_BIND:
3105 case OPT_DISABLE_BACKTRACK:
3106 case OPT_CALIB_BACKEND:
3107 case OPT_LIGHTLID35:
3108 case OPT_GAMMA_BIND:
3109 case OPT_AUTOADJUST:
3110 *(SANE_Bool *) value = val[option].w;
3111 DBG(50, "sane_control_option: opt=%d, act=%d, val=%d\n",
3112 option, action, val[option].w);
3113 return SANE_STATUS_GOOD;
3114
3115 /* string options */
3116 case OPT_SOURCE:
3117 case OPT_MODE:
3118 case OPT_HALFTONE:
3119 case OPT_CHANNEL:
3120 case OPT_GAMMA_MODE:
3121 strcpy(value, val[option].s);
3122 DBG(50, "sane_control_option: opt=%d, act=%d, val=%s\n",
3123 option, action, val[option].s);
3124 return SANE_STATUS_GOOD;
3125
3126 /* word array options */
3127 case OPT_GAMMA_CUSTOM:
3128 case OPT_GAMMA_CUSTOM_R:
3129 case OPT_GAMMA_CUSTOM_G:
3130 case OPT_GAMMA_CUSTOM_B:
3131 memcpy(value, val[option].wa, sod[option].size);
3132 return SANE_STATUS_GOOD;
3133
3134 /* button options */
3135 case OPT_TOGGLELAMP:
3136 case OPT_BALANCE_FW:
3137 return SANE_STATUS_GOOD;
3138
3139 /* others */
3140 case OPT_NUM_OPTS:
3141 *(SANE_Word *) value = NUM_OPTIONS;
3142 return SANE_STATUS_GOOD;
3143
3144 default:
3145 return SANE_STATUS_UNSUPPORTED;
3146 }
3147 /* NOTREACHED */
3148 /* break; */
3149
3150 case SANE_ACTION_SET_VALUE: /* set option values */
3151 if ( ! SANE_OPTION_IS_SETTABLE(sod[option].cap) )
3152 {
3153 DBG(100, "sane_control_option: option %d; action %d \n",
3154 option, action);
3155 DBG(10, "sane_control_option: trying to set unsettable option\n");
3156 return SANE_STATUS_INVAL;
3157 }
3158
3159 /* do not check OPT_BR_Y, xscanimage sometimes tries to set */
3160 /* it to a too large value; bug in xscanimage ? */
3161 /* if ( option != OPT_BR_Y )
3162 { */
3163 status = sanei_constrain_value(ms->sod + option, value, info);
3164 if (status != SANE_STATUS_GOOD)
3165 {
3166 DBG(10, "sane_control_option: invalid option value\n");
3167 return status;
3168 }
3169 /* } */
3170
3171 switch ( sod[option].type )
3172 {
3173 case SANE_TYPE_BOOL:
3174 DBG(50, "sane_control_option: option=%d, action=%d, value=%d\n",
3175 option, action, *(SANE_Int *) value);
3176 if ( ! ( ( *(SANE_Bool *) value == SANE_TRUE )
3177 || ( *(SANE_Bool *) value == SANE_FALSE ) ) )
3178 {
3179 DBG(10, "sane_control_option: invalid BOOL option value\n");
3180 return SANE_STATUS_INVAL;
3181 }
3182 if ( val[option].w == *(SANE_Bool *) value ) /* no change */
3183 return SANE_STATUS_GOOD;
3184 val[option].w = *(SANE_Bool *) value;
3185 break;
3186
3187 case SANE_TYPE_INT:
3188 if ( sod[option].size == sizeof(SANE_Int) )
3189 {
3190 /* word option */
3191 DBG(50, "sane_control_option: option=%d, action=%d, "
3192 "value=%d\n", option, action, *(SANE_Int *) value);
3193 if ( val[option].w == *(SANE_Int *) value ) /* no change */
3194 return SANE_STATUS_GOOD;
3195 val[option].w = *(SANE_Int *) value;
3196 }
3197 else
3198 {
3199 /* word array option */
3200 memcpy(val[option].wa, value, sod[option].size);
3201 }
3202 break;
3203
3204 case SANE_TYPE_FIXED:
3205 DBG(50, "sane_control_option: option=%d, action=%d, value=%f\n",
3206 option, action, SANE_UNFIX( *(SANE_Fixed *) value));
3207 if ( val[option].w == *(SANE_Fixed *) value ) /* no change */
3208 return SANE_STATUS_GOOD;
3209 val[option].w = *(SANE_Fixed *) value;
3210 break;
3211
3212 case SANE_TYPE_STRING:
3213 DBG(50, "sane_control_option: option=%d, action=%d, value=%s\n",
3214 option, action, (SANE_String) value);
3215 if ( strcmp(val[option].s, (SANE_String) value) == 0 )
3216 return SANE_STATUS_GOOD; /* no change */
3217 if ( val[option].s )
3218 free((void *) val[option].s);
3219 val[option].s = strdup(value);
3220 if ( val[option].s == NULL )
3221 {
3222 DBG(1, "sane_control_option: strdup failed\n");
3223 return SANE_STATUS_NO_MEM;
3224 }
3225 break;
3226
3227 case SANE_TYPE_BUTTON:
3228 break;
3229
3230 default:
3231 DBG(1, "sane_control_option: unknown type %d\n",
3232 sod[option].type);
3233 break;
3234 }
3235
3236 switch ( option )
3237 {
3238 case OPT_RESOLUTION:
3239 case OPT_Y_RESOLUTION:
3240 case OPT_TL_X:
3241 case OPT_TL_Y:
3242 case OPT_BR_X:
3243 case OPT_BR_Y:
3244 if ( info )
3245 *info |= SANE_INFO_RELOAD_PARAMS;
3246 return SANE_STATUS_GOOD;
3247 case OPT_DISABLE_BACKTRACK:
3248 case OPT_CALIB_BACKEND:
3249 case OPT_LIGHTLID35:
3250 case OPT_PREVIEW:
3251 case OPT_BRIGHTNESS:
3252 case OPT_THRESHOLD:
3253 case OPT_CONTRAST:
3254 case OPT_EXPOSURE:
3255 case OPT_EXPOSURE_R:
3256 case OPT_EXPOSURE_G:
3257 case OPT_EXPOSURE_B:
3258 case OPT_GAMMA_SCALAR:
3259 case OPT_GAMMA_SCALAR_R:
3260 case OPT_GAMMA_SCALAR_G:
3261 case OPT_GAMMA_SCALAR_B:
3262 case OPT_GAMMA_CUSTOM:
3263 case OPT_GAMMA_CUSTOM_R:
3264 case OPT_GAMMA_CUSTOM_G:
3265 case OPT_GAMMA_CUSTOM_B:
3266 case OPT_HALFTONE:
3267 case OPT_BALANCE_R:
3268 case OPT_BALANCE_G:
3269 case OPT_BALANCE_B:
3270 return SANE_STATUS_GOOD;
3271
3272 case OPT_BITDEPTH:
3273 /* If the bitdepth has changed we must change the size of */
3274 /* the gamma table if the device does not support gamma */
3275 /* tables. This will hopefully cause no trouble if the */
3276 /* mode is one bit */
3277
3278 if ( md->model_flags & MD_NO_GAMMA )
3279 {
3280 int max_gamma_value;
3281 int size;
3282 int color;
3283 int i;
3284
3285 size = (int) pow(2.0, (double) val[OPT_BITDEPTH].w) - 1;
3286 max_gamma_value = size - 1;
3287 for ( color = 0; color < 4; color++ )
3288 {
3289 for ( i = 0; i < max_gamma_value; i++ )
3290 md->custom_gamma_table[color][i] = (SANE_Int) i;
3291 }
3292 md->custom_gamma_range.max = (SANE_Int) max_gamma_value;
3293 sod[OPT_GAMMA_CUSTOM].size = size * sizeof (SANE_Int);
3294 sod[OPT_GAMMA_CUSTOM_R].size = size * sizeof (SANE_Int);
3295 sod[OPT_GAMMA_CUSTOM_G].size = size * sizeof (SANE_Int);
3296 sod[OPT_GAMMA_CUSTOM_B].size = size * sizeof (SANE_Int);
3297
3298 if ( info )
3299 *info |= SANE_INFO_RELOAD_OPTIONS;
3300
3301 }
3302
3303 if ( info )
3304 *info |= SANE_INFO_RELOAD_PARAMS;
3305 return SANE_STATUS_GOOD;
3306
3307 case OPT_SOURCE:
3308 if ( info )
3309 *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
3310 if ( strcmp(val[option].s, MD_SOURCESTRING_FLATBED) == 0 )
3311 md->scan_source = MD_SOURCE_FLATBED;
3312 else if ( strcmp(val[option].s, MD_SOURCESTRING_TMA) == 0 )
3313 md->scan_source = MD_SOURCE_TMA;
3314 else if ( strcmp(val[option].s, MD_SOURCESTRING_ADF) == 0 )
3315 md->scan_source = MD_SOURCE_ADF;
3316 else if ( strcmp(val[option].s, MD_SOURCESTRING_STRIPE) == 0 )
3317 md->scan_source = MD_SOURCE_STRIPE;
3318 else if ( strcmp(val[option].s, MD_SOURCESTRING_SLIDE) == 0 )
3319 md->scan_source = MD_SOURCE_SLIDE;
3320 else
3321 {
3322 DBG(1, "sane_control_option: unsupported option %s\n",
3323 val[option].s);
3324 return SANE_STATUS_UNSUPPORTED;
3325 }
3326
3327 init_options(ms, md->scan_source);
3328 return SANE_STATUS_GOOD;
3329
3330 case OPT_MODE:
3331 if ( info )
3332 *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
3333
3334 status = set_option_dependencies(ms, sod, val);
3335
3336 /* Options with side effects need special treatment. They are */
3337 /* reset, even if they were set by set_option_dependencies(): */
3338 /* if we have more than one color depth activate this option */
3339
3340 if ( md->bitdepth_list[0] == 1 )
3341 sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
3342 if ( strncmp(md->opts.auto_adjust, "off", 3) == 0 )
3343 sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
3344
3345 if ( status != SANE_STATUS_GOOD )
3346 return status;
3347 return SANE_STATUS_GOOD;
3348
3349 case OPT_CHANNEL:
3350 if ( info )
3351 *info |= SANE_INFO_RELOAD_OPTIONS;
3352 if ( strcmp(val[option].s, MD_CHANNEL_MASTER) == 0 )
3353 {
3354 sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
3355 sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
3356 sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
3357 sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3358 sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3359 sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3360 sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3361 sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3362 sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3363 sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3364 sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3365 sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3366 sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3367 sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3368 sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3369 sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3370 }
3371 else if ( strcmp(val[option].s, MD_CHANNEL_RED) == 0 )
3372 {
3373 sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3374 sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3375 sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3376 sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3377 sod[OPT_SHADOW_R].cap &= ~SANE_CAP_INACTIVE;
3378 sod[OPT_MIDTONE_R].cap &= ~SANE_CAP_INACTIVE;
3379 sod[OPT_HIGHLIGHT_R].cap &= ~SANE_CAP_INACTIVE;
3380 sod[OPT_EXPOSURE_R].cap &= ~SANE_CAP_INACTIVE;
3381 sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3382 sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3383 sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3384 sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3385 sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3386 sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3387 sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3388 sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3389 }
3390 else if ( strcmp(val[option].s, MD_CHANNEL_GREEN) == 0 )
3391 {
3392 sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3393 sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3394 sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3395 sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3396 sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3397 sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3398 sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3399 sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3400 sod[OPT_SHADOW_G].cap &= ~SANE_CAP_INACTIVE;
3401 sod[OPT_MIDTONE_G].cap &= ~SANE_CAP_INACTIVE;
3402 sod[OPT_HIGHLIGHT_G].cap &= ~SANE_CAP_INACTIVE;
3403 sod[OPT_EXPOSURE_G].cap &= ~SANE_CAP_INACTIVE;
3404 sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3405 sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3406 sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3407 sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3408 }
3409 else if ( strcmp(val[option].s, MD_CHANNEL_BLUE) == 0 )
3410 {
3411 sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3412 sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3413 sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3414 sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3415 sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3416 sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3417 sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3418 sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3419 sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3420 sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3421 sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3422 sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3423 sod[OPT_SHADOW_B].cap &= ~SANE_CAP_INACTIVE;
3424 sod[OPT_MIDTONE_B].cap &= ~SANE_CAP_INACTIVE;
3425 sod[OPT_HIGHLIGHT_B].cap &= ~SANE_CAP_INACTIVE;
3426 sod[OPT_EXPOSURE_B].cap &= ~SANE_CAP_INACTIVE;
3427 }
3428 return SANE_STATUS_GOOD;
3429
3430 case OPT_GAMMA_MODE:
3431 restore_gamma_options(sod, val);
3432 if ( info )
3433 *info |= SANE_INFO_RELOAD_OPTIONS;
3434 return SANE_STATUS_GOOD;
3435
3436 case OPT_GAMMA_BIND:
3437 restore_gamma_options(sod, val);
3438 if ( info )
3439 *info |= SANE_INFO_RELOAD_OPTIONS;
3440
3441 return SANE_STATUS_GOOD;
3442
3443 case OPT_SHADOW:
3444 case OPT_SHADOW_R:
3445 case OPT_SHADOW_G:
3446 case OPT_SHADOW_B:
3447 if ( val[option].w >= val[option + 1].w )
3448 {
3449 val[option + 1].w = val[option].w + 1;
3450 if ( info )
3451 *info |= SANE_INFO_RELOAD_OPTIONS;
3452 }
3453 if ( val[option + 1].w >= val[option + 2].w )
3454 val[option + 2].w = val[option + 1].w + 1;
3455
3456 return SANE_STATUS_GOOD;
3457
3458 case OPT_MIDTONE:
3459 case OPT_MIDTONE_R:
3460 case OPT_MIDTONE_G:
3461 case OPT_MIDTONE_B:
3462 if ( val[option].w <= val[option - 1].w )
3463 {
3464 val[option - 1].w = val[option].w - 1;
3465 if ( info )
3466 *info |= SANE_INFO_RELOAD_OPTIONS;
3467 }
3468 if ( val[option].w >= val[option + 1].w )
3469 {
3470 val[option + 1].w = val[option].w + 1;
3471 if ( info )
3472 *info |= SANE_INFO_RELOAD_OPTIONS;
3473 }
3474
3475 return SANE_STATUS_GOOD;
3476
3477 case OPT_HIGHLIGHT:
3478 case OPT_HIGHLIGHT_R:
3479 case OPT_HIGHLIGHT_G:
3480 case OPT_HIGHLIGHT_B:
3481 if ( val[option].w <= val[option - 1].w )
3482 {
3483 val[option - 1].w = val[option].w - 1;
3484 if ( info )
3485 *info |= SANE_INFO_RELOAD_OPTIONS;
3486 }
3487 if ( val[option - 1].w <= val[option - 2].w )
3488 val[option - 2].w = val[option - 1].w - 1;
3489
3490 return SANE_STATUS_GOOD;
3491
3492 case OPT_RESOLUTION_BIND:
3493 if ( ms->val[option].w == SANE_FALSE )
3494 {
3495 ms->sod[OPT_Y_RESOLUTION].cap &= ~SANE_CAP_INACTIVE;
3496 }
3497 else
3498 {
3499 ms->sod[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
3500 }
3501 if ( info )
3502 *info |= SANE_INFO_RELOAD_OPTIONS;
3503 return SANE_STATUS_GOOD;
3504
3505 case OPT_TOGGLELAMP:
3506 status = scsi_read_system_status(md, -1);
3507 if ( status != SANE_STATUS_GOOD )
3508 return SANE_STATUS_IO_ERROR;
3509
3510 md->status.flamp ^= 1;
3511 status = scsi_send_system_status(md, -1);
3512 if ( status != SANE_STATUS_GOOD )
3513 return SANE_STATUS_IO_ERROR;
3514 return SANE_STATUS_GOOD;
3515
3516 case OPT_AUTOADJUST:
3517 if ( info )
3518 *info |= SANE_INFO_RELOAD_OPTIONS;
3519
3520 if ( ms->val[option].w == SANE_FALSE )
3521 ms->sod[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
3522 else
3523 ms->sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
3524
3525 return SANE_STATUS_GOOD;
3526
3527 case OPT_BALANCE_FW:
3528 val[OPT_BALANCE_R].w =
3529 SANE_FIX((uint8_t)( (float)mi->balance[0] / 2.55 ) );
3530 val[OPT_BALANCE_G].w =
3531 SANE_FIX((uint8_t)( (float)mi->balance[1] / 2.55 ) );
3532 val[OPT_BALANCE_B].w =
3533 SANE_FIX((uint8_t)( (float)mi->balance[2] / 2.55 ) );
3534 if ( info )
3535 *info |= SANE_INFO_RELOAD_OPTIONS;
3536
3537 return SANE_STATUS_GOOD;
3538
3539
3540 default:
3541 return SANE_STATUS_UNSUPPORTED;
3542 }
3543 #if 0
3544 break;
3545 #endif
3546 default:
3547 DBG(1, "sane_control_option: Unsupported action %d\n", action);
3548 return SANE_STATUS_UNSUPPORTED;
3549 }
3550 }
3551
3552 /*---------- sane_get_option_descriptor() ------------------------------------*/
3553
3554 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int n)3555 sane_get_option_descriptor(SANE_Handle handle, SANE_Int n)
3556 {
3557 Microtek2_Scanner *ms = handle;
3558
3559 DBG(255, "sane_get_option_descriptor: handle=%p, sod=%p, opt=%d\n",
3560 (void *) handle, (void *) ms->sod, n);
3561
3562 if ( n < 0 || n >= NUM_OPTIONS )
3563 {
3564 DBG(30, "sane_get_option_descriptor: invalid option %d\n", n);
3565 return NULL;
3566 }
3567
3568 return &ms->sod[n];
3569 }
3570
3571 /*---------- restore_gamma_options() -----------------------------------------*/
3572
3573 static SANE_Status
restore_gamma_options(SANE_Option_Descriptor * sod,Option_Value * val)3574 restore_gamma_options(SANE_Option_Descriptor *sod, Option_Value *val)
3575 {
3576
3577 DBG(40, "restore_gamma_options: val=%p, sod=%p\n", (void *) val, (void *) sod);
3578 /* if we don't have a gamma table return immediately */
3579 if ( ! val[OPT_GAMMA_MODE].s )
3580 return SANE_STATUS_GOOD;
3581
3582 if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
3583 {
3584 sod[OPT_GAMMA_MODE].cap &= ~SANE_CAP_INACTIVE;
3585 if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_LINEAR) == 0 )
3586 {
3587 sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3588 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3589 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3590 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3591 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3592 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3593 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3594 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3595 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3596 }
3597 else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_SCALAR) == 0 )
3598 {
3599 sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3600 if ( val[OPT_GAMMA_BIND].w == SANE_TRUE )
3601 {
3602 sod[OPT_GAMMA_SCALAR].cap &= ~SANE_CAP_INACTIVE;
3603 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3604 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3605 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3606 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3607 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3608 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3609 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3610 }
3611 else
3612 {
3613 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3614 sod[OPT_GAMMA_SCALAR_R].cap &= ~SANE_CAP_INACTIVE;
3615 sod[OPT_GAMMA_SCALAR_G].cap &= ~SANE_CAP_INACTIVE;
3616 sod[OPT_GAMMA_SCALAR_B].cap &= ~SANE_CAP_INACTIVE;
3617 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3618 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3619 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3620 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3621 }
3622 }
3623 else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_CUSTOM) == 0 )
3624 {
3625 sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3626 if ( val[OPT_GAMMA_BIND].w == SANE_TRUE )
3627 {
3628 sod[OPT_GAMMA_CUSTOM].cap &= ~SANE_CAP_INACTIVE;
3629 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3630 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3631 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3632 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3633 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3634 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3635 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3636 }
3637 else
3638 {
3639 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3640 sod[OPT_GAMMA_CUSTOM_R].cap &= ~SANE_CAP_INACTIVE;
3641 sod[OPT_GAMMA_CUSTOM_G].cap &= ~SANE_CAP_INACTIVE;
3642 sod[OPT_GAMMA_CUSTOM_B].cap &= ~SANE_CAP_INACTIVE;
3643 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3644 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3645 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3646 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3647 }
3648 }
3649 }
3650 else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
3651 {
3652 sod[OPT_GAMMA_MODE].cap &= ~SANE_CAP_INACTIVE;
3653 sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3654 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3655 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3656 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3657 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3658 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3659 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3660 if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_LINEAR) == 0 )
3661 {
3662 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3663 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3664 }
3665 else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_SCALAR) == 0 )
3666 {
3667 sod[OPT_GAMMA_SCALAR].cap &= ~SANE_CAP_INACTIVE;
3668 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3669 }
3670 else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_CUSTOM) == 0 )
3671 {
3672 sod[OPT_GAMMA_CUSTOM].cap &= ~SANE_CAP_INACTIVE;
3673 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3674 }
3675 }
3676 else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0
3677 || strcmp(val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
3678 {
3679 /* reset gamma to default */
3680 if ( val[OPT_GAMMA_MODE].s )
3681 free((void *) val[OPT_GAMMA_MODE].s);
3682 val[OPT_GAMMA_MODE].s = strdup(MD_GAMMAMODE_LINEAR);
3683 sod[OPT_GAMMA_MODE].cap |= SANE_CAP_INACTIVE;
3684 sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3685 sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3686 sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3687 sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3688 sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3689 sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3690 sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3691 sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3692 sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3693 }
3694 else
3695 DBG(1, "restore_gamma_options: unknown mode %s\n", val[OPT_MODE].s);
3696
3697 return SANE_STATUS_GOOD;
3698 }
3699
3700
3701 /*---------- calculate_sane_params() -----------------------------------------*/
3702
3703 static SANE_Status
calculate_sane_params(Microtek2_Scanner * ms)3704 calculate_sane_params(Microtek2_Scanner *ms)
3705 {
3706 Microtek2_Device *md;
3707 Microtek2_Info *mi;
3708
3709
3710 DBG(30, "calculate_sane_params: ms=%p\n", (void *) ms);
3711
3712 md = ms->dev;
3713 mi = &md->info[md->scan_source];
3714
3715 if ( ! mi->onepass && ms->mode == MS_MODE_COLOR )
3716 {
3717 if ( ms->current_pass == 1 )
3718 ms->params.format = SANE_FRAME_RED;
3719 else if ( ms->current_pass == 2 )
3720 ms->params.format = SANE_FRAME_GREEN;
3721 else if ( ms->current_pass == 3 )
3722 ms->params.format = SANE_FRAME_BLUE;
3723 else
3724 {
3725 DBG(1, "calculate_sane_params: invalid pass number %d\n",
3726 ms->current_pass);
3727 return SANE_STATUS_IO_ERROR;
3728 }
3729 }
3730 else if ( mi->onepass && ms->mode == MS_MODE_COLOR )
3731 ms->params.format = SANE_FRAME_RGB;
3732 else
3733 ms->params.format = SANE_FRAME_GRAY;
3734
3735 if ( ! mi->onepass && ms->mode == MS_MODE_COLOR && ms->current_pass < 3 )
3736 ms->params.last_frame = SANE_FALSE;
3737 else
3738 ms->params.last_frame = SANE_TRUE;
3739 ms->params.lines = ms->src_remaining_lines;
3740 ms->params.pixels_per_line = ms->ppl;
3741 ms->params.bytes_per_line = ms->real_bpl;
3742 ms->params.depth = ms->bits_per_pixel_out;
3743
3744 return SANE_STATUS_GOOD;
3745
3746 }
3747
3748 /*---------- get_calib_params() ----------------------------------------------*/
3749
3750 static void
get_calib_params(Microtek2_Scanner * ms)3751 get_calib_params(Microtek2_Scanner *ms)
3752 {
3753 Microtek2_Device *md;
3754 Microtek2_Info *mi;
3755
3756
3757 DBG(30, "get_calib_params: handle=%p\n", (void *) ms);
3758
3759 md = ms->dev;
3760 mi = &md->info[md->scan_source];
3761
3762 if ( md->model_flags & MD_CALIB_DIVISOR_600 )
3763 {
3764 if ( ms->x_resolution_dpi <= 600 )
3765 mi->calib_divisor = 2;
3766 else
3767 mi->calib_divisor = 1;
3768 }
3769 DBG(30, "Calib Divisor: %d\n", mi->calib_divisor);
3770
3771
3772 ms->x_resolution_dpi = mi->opt_resolution / mi->calib_divisor;
3773 ms->y_resolution_dpi = mi->opt_resolution / 5; /* ignore dust particles */
3774 ms->x1_dots = 0;
3775 ms->y1_dots = mi->calib_white;
3776 ms->width_dots = mi->geo_width;
3777 if ( md->shading_length != 0 )
3778 ms->height_dots = md->shading_length;
3779 else
3780 ms->height_dots = mi->calib_space;
3781
3782 ms->mode = MS_MODE_COLOR;
3783
3784 if ( mi->depth & MI_HASDEPTH_16 )
3785 ms->depth = 16;
3786 else if ( mi->depth & MI_HASDEPTH_14 )
3787 ms->depth = 14;
3788 else if ( mi->depth & MI_HASDEPTH_12 )
3789 ms->depth = 12;
3790 else if ( mi->depth & MI_HASDEPTH_10 )
3791 ms->depth = 10;
3792 else
3793 ms->depth = 8;
3794
3795 ms->stay = 0;
3796 if ( mi->calib_space < 10 )
3797 ms->stay = 1;
3798 ms->rawdat = 1;
3799 ms->quality = 1;
3800 ms->fastscan = 0;
3801 /* ms->scan_source = md->scan_source; */
3802 ms->scan_source = 0;
3803 ms->brightness_m = ms->brightness_r = ms->brightness_g =
3804 ms->brightness_b = 128;
3805 ms->exposure_m = ms->exposure_r = ms->exposure_g = ms->exposure_b = 0;
3806 ms->contrast_m = ms->contrast_r = ms->contrast_g = ms->contrast_b = 128;
3807 ms->shadow_m = ms->shadow_r = ms->shadow_g = ms->shadow_b = 0;
3808 ms->midtone_m = ms->midtone_r = ms->midtone_g = ms->midtone_b = 128;
3809 ms->highlight_m = ms->highlight_r = ms->highlight_g = ms->highlight_b = 255;
3810
3811 return;
3812 }
3813
3814
3815 /*---------- get_scan_parameters () ------------------------------------------*/
3816
3817 static SANE_Status
get_scan_parameters(Microtek2_Scanner * ms)3818 get_scan_parameters(Microtek2_Scanner *ms)
3819 {
3820 Microtek2_Device *md;
3821 Microtek2_Info *mi;
3822 double dpm; /* dots per millimeter */
3823 int x2_dots;
3824 int y2_dots;
3825 int i;
3826
3827
3828 DBG(30, "get_scan_parameters: handle=%p\n", (void *) ms);
3829
3830 md = ms->dev;
3831 mi = &md->info[md->scan_source];
3832
3833 get_scan_mode_and_depth(ms, &ms->mode, &ms->depth,
3834 &ms->bits_per_pixel_in, &ms->bits_per_pixel_out);
3835
3836 /* get the scan_source */
3837 if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_FLATBED) == 0 )
3838 ms->scan_source = MS_SOURCE_FLATBED;
3839 else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_ADF) == 0 )
3840 ms->scan_source = MS_SOURCE_ADF;
3841 else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_TMA) == 0 )
3842 ms->scan_source = MS_SOURCE_TMA;
3843 else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_STRIPE) == 0 )
3844 ms->scan_source = MS_SOURCE_STRIPE;
3845 else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_SLIDE) == 0 )
3846 ms->scan_source = MS_SOURCE_SLIDE;
3847
3848 /* enable/disable backtracking */
3849 if ( ms->val[OPT_DISABLE_BACKTRACK].w == SANE_TRUE )
3850 ms->no_backtracking = 1;
3851 else
3852 ms->no_backtracking = 0;
3853
3854 /* turn off the lamp during a scan */
3855 if ( ms->val[OPT_LIGHTLID35].w == SANE_TRUE )
3856 ms->lightlid35 = 1;
3857 else
3858 ms->lightlid35 = 0;
3859
3860 /* automatic adjustment of threshold */
3861 if ( ms->val[OPT_AUTOADJUST].w == SANE_TRUE)
3862 ms->auto_adjust = 1;
3863 else
3864 ms->auto_adjust = 0;
3865
3866 /* color calibration by backend */
3867 if ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
3868 ms->calib_backend = 1;
3869 else
3870 ms->calib_backend = 0;
3871
3872 /* if halftone mode select halftone pattern */
3873 if ( ms->mode == MS_MODE_HALFTONE )
3874 {
3875 i = 0;
3876 while ( strcmp(md->halftone_mode_list[i], ms->val[OPT_HALFTONE].s) )
3877 ++i;
3878 ms->internal_ht_index = i;
3879 }
3880
3881 /* if lineart get the value for threshold */
3882 if ( ms->mode == MS_MODE_LINEART || ms->mode == MS_MODE_LINEARTFAKE)
3883 ms->threshold = (uint8_t) ms->val[OPT_THRESHOLD].w;
3884 else
3885 ms->threshold = (uint8_t) M_THRESHOLD_DEFAULT;
3886
3887 DBG(30, "get_scan_parameters: mode=%d, depth=%d, bpp_in=%d, bpp_out=%d\n",
3888 ms->mode, ms->depth, ms->bits_per_pixel_in,
3889 ms->bits_per_pixel_out);
3890
3891 /* calculate positions, width and height in dots */
3892 /* check for impossible values */
3893 /* ensure a minimum scan area of 10 x 10 pixels */
3894 dpm = (double) mi->opt_resolution / MM_PER_INCH;
3895 ms->x1_dots = (SANE_Int) ( SANE_UNFIX(ms->val[OPT_TL_X].w) * dpm + 0.5 );
3896 if ( ms->x1_dots > ( mi->geo_width - 10 ) )
3897 ms->x1_dots = ( mi->geo_width - 10 );
3898 ms->y1_dots = (SANE_Int) ( SANE_UNFIX(ms->val[OPT_TL_Y].w) * dpm + 0.5 );
3899 if ( ms->y1_dots > ( mi->geo_height - 10 ) )
3900 ms->y1_dots = ( mi->geo_height - 10 );
3901 x2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_X].w) * dpm + 0.5 );
3902 if ( x2_dots >= mi->geo_width )
3903 x2_dots = mi->geo_width - 1;
3904 y2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_Y].w) * dpm + 0.5 );
3905 if ( y2_dots >= mi->geo_height )
3906 y2_dots = mi->geo_height - 1;
3907 ms->width_dots = x2_dots - ms->x1_dots;
3908 if ( md->model_flags & MD_OFFSET_2 ) /* this firmware has problems with */
3909 if ( ( ms->width_dots % 2 ) == 1 ) /* odd pixel numbers */
3910 ms->width_dots -= 1;
3911 if ( ms->width_dots < 10 )
3912 ms->width_dots = 10;
3913 ms->height_dots = y2_dots - ms->y1_dots;
3914 if ( ms->height_dots < 10 )
3915 ms->height_dots = 10;
3916
3917 /*test!!!*/
3918 /* ms->y1_dots -= 50;*/
3919
3920 /* take scanning direction into account */
3921 if ((mi->direction & MI_DATSEQ_RTOL) == 1)
3922 ms->x1_dots = mi->geo_width - ms->x1_dots - ms->width_dots;
3923
3924 if ( ms->val[OPT_RESOLUTION_BIND].w == SANE_TRUE )
3925 {
3926 ms->x_resolution_dpi =
3927 (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3928 ms->y_resolution_dpi =
3929 (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3930 }
3931 else
3932 {
3933 ms->x_resolution_dpi =
3934 (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3935 ms->y_resolution_dpi =
3936 (SANE_Int) (SANE_UNFIX(ms->val[OPT_Y_RESOLUTION].w) + 0.5);
3937 }
3938
3939 if ( ms->x_resolution_dpi < 10 )
3940 ms->x_resolution_dpi = 10;
3941 if ( ms->y_resolution_dpi < 10 )
3942 ms->y_resolution_dpi = 10;
3943
3944 DBG(30, "get_scan_parameters: yres=%d, x1=%d, width=%d, y1=%d, height=%d\n",
3945 ms->y_resolution_dpi, ms->x1_dots, ms->width_dots,
3946 ms->y1_dots, ms->height_dots);
3947
3948 /* Preview mode */
3949 if ( ms->val[OPT_PREVIEW].w == SANE_TRUE )
3950 {
3951 ms->fastscan = SANE_TRUE;
3952 ms->quality = SANE_FALSE;
3953 }
3954 else
3955 {
3956 ms->fastscan = SANE_FALSE;
3957 ms->quality = SANE_TRUE;
3958 }
3959
3960 ms->rawdat = 0;
3961
3962 /* brightness, contrast, values 1,..,255 */
3963 ms->brightness_m = (uint8_t) (SANE_UNFIX(ms->val[OPT_BRIGHTNESS].w)
3964 / SANE_UNFIX(md->percentage_range.max) * 254.0) + 1;
3965 ms->brightness_r = ms->brightness_g = ms->brightness_b = ms->brightness_m;
3966
3967 ms->contrast_m = (uint8_t) (SANE_UNFIX(ms->val[OPT_CONTRAST].w)
3968 / SANE_UNFIX(md->percentage_range.max) * 254.0) + 1;
3969 ms->contrast_r = ms->contrast_g = ms->contrast_b = ms->contrast_m;
3970
3971 /* shadow, midtone, highlight, exposure */
3972 ms->shadow_m = (uint8_t) ms->val[OPT_SHADOW].w;
3973 ms->shadow_r = (uint8_t) ms->val[OPT_SHADOW_R].w;
3974 ms->shadow_g = (uint8_t) ms->val[OPT_SHADOW_G].w;
3975 ms->shadow_b = (uint8_t) ms->val[OPT_SHADOW_B].w;
3976 ms->midtone_m = (uint8_t) ms->val[OPT_MIDTONE].w;
3977 ms->midtone_r = (uint8_t) ms->val[OPT_MIDTONE_R].w;
3978 ms->midtone_g = (uint8_t) ms->val[OPT_MIDTONE_G].w;
3979 ms->midtone_b = (uint8_t) ms->val[OPT_MIDTONE_B].w;
3980 ms->highlight_m = (uint8_t) ms->val[OPT_HIGHLIGHT].w;
3981 ms->highlight_r = (uint8_t) ms->val[OPT_HIGHLIGHT_R].w;
3982 ms->highlight_g = (uint8_t) ms->val[OPT_HIGHLIGHT_G].w;
3983 ms->highlight_b = (uint8_t) ms->val[OPT_HIGHLIGHT_B].w;
3984 ms->exposure_m = (uint8_t) (ms->val[OPT_EXPOSURE].w / 2);
3985 ms->exposure_r = (uint8_t) (ms->val[OPT_EXPOSURE_R].w / 2);
3986 ms->exposure_g = (uint8_t) (ms->val[OPT_EXPOSURE_G].w / 2);
3987 ms->exposure_b = (uint8_t) (ms->val[OPT_EXPOSURE_B].w / 2);
3988
3989 ms->gamma_mode = strdup( (char *) ms->val[OPT_GAMMA_MODE].s);
3990
3991 ms->balance[0] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_R].w));
3992 ms->balance[1] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_G].w));
3993 ms->balance[2] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_B].w));
3994 DBG(255, "get_scan_parameters:ms->balance[0]=%d,[1]=%d,[2]=%d\n",
3995 ms->balance[0], ms->balance[1], ms->balance[2]);
3996
3997 return SANE_STATUS_GOOD;
3998 }
3999
4000 /*---------- get_scan_mode_and_depth() ---------------------------------------*/
4001
4002 static SANE_Status
get_scan_mode_and_depth(Microtek2_Scanner * ms,int * mode,int * depth,int * bits_per_pixel_in,int * bits_per_pixel_out)4003 get_scan_mode_and_depth(Microtek2_Scanner *ms,
4004 int *mode,
4005 int *depth,
4006 int *bits_per_pixel_in,
4007 int *bits_per_pixel_out)
4008 {
4009 /* This function translates the strings for the possible modes and */
4010 /* bitdepth into a more conveniant format as needed for SET WINDOW. */
4011 /* bits_per_pixel is the number of bits per color one pixel needs */
4012 /* when transferred from the scanner, bits_perpixel_out is the */
4013 /* number of bits per color one pixel uses when transferred to the */
4014 /* frontend. These may be different. For example, with a depth of 4 */
4015 /* two pixels per byte are transferred from the scanner, but only one */
4016 /* pixel per byte is transferred to the frontend. */
4017 /* If lineart_fake is set to !=0, we need the parameters for a */
4018 /* grayscale scan, because the scanner has no lineart mode */
4019
4020 Microtek2_Device *md;
4021 Microtek2_Info *mi;
4022
4023 DBG(30, "get_scan_mode_and_depth: handle=%p\n", (void *) ms);
4024
4025 md = ms->dev;
4026 mi = &md->info[md->scan_source];
4027
4028 if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
4029 *mode = MS_MODE_COLOR;
4030 else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
4031 *mode = MS_MODE_GRAY;
4032 else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0)
4033 *mode = MS_MODE_HALFTONE;
4034 else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
4035 {
4036 if ( MI_LINEART_NONE(mi->scanmode)
4037 || ms->val[OPT_AUTOADJUST].w == SANE_TRUE
4038 || md->model_flags & MD_READ_CONTROL_BIT)
4039 *mode = MS_MODE_LINEARTFAKE;
4040 else
4041 *mode = MS_MODE_LINEART;
4042 }
4043 else
4044 {
4045 DBG(1, "get_scan_mode_and_depth: Unknown mode %s\n",
4046 ms->val[OPT_MODE].s);
4047 return SANE_STATUS_INVAL;
4048 }
4049
4050 if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0
4051 || strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
4052 {
4053 if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_16 )
4054 {
4055 *depth = 16;
4056 *bits_per_pixel_in = *bits_per_pixel_out = 16;
4057 }
4058 else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_14 )
4059 {
4060 *depth = 14;
4061 *bits_per_pixel_in = *bits_per_pixel_out = 16;
4062 }
4063 else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_12 )
4064 {
4065 *depth = 12;
4066 *bits_per_pixel_in = *bits_per_pixel_out = 16;
4067 }
4068 else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_10 )
4069 {
4070 *depth = 10;
4071 *bits_per_pixel_in = *bits_per_pixel_out = 16;
4072 }
4073 else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_8 )
4074 {
4075 *depth = 8;
4076 *bits_per_pixel_in = *bits_per_pixel_out = 8;
4077 }
4078 else if ( ms->val[OPT_MODE].w == MD_DEPTHVAL_4 )
4079 {
4080 *depth = 4;
4081 *bits_per_pixel_in = 4;
4082 *bits_per_pixel_out = 8;
4083 }
4084 }
4085 else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0 )
4086 {
4087 *depth = 1;
4088 *bits_per_pixel_in = *bits_per_pixel_out = 1;
4089 }
4090 else /* lineart */
4091 {
4092 *bits_per_pixel_out = 1;
4093 if ( *mode == MS_MODE_LINEARTFAKE )
4094 {
4095 *depth = 8;
4096 *bits_per_pixel_in = 8;
4097 }
4098 else
4099 {
4100 *depth = 1;
4101 *bits_per_pixel_in = 1;
4102 }
4103 }
4104
4105 #if 0
4106 if ( ms->val[OPT_PREVIEW].w == SANE_TRUE )
4107 {
4108 if ( *depth > 8 )
4109 {
4110 *depth = 8;
4111 *bits_per_pixel_in = *bits_per_pixel_out = 8;
4112 }
4113 }
4114 #endif
4115
4116 DBG(30, "get_scan_mode_and_depth: mode=%d, depth=%d,"
4117 " bits_pp_in=%d, bits_pp_out=%d, preview=%d\n",
4118 *mode, *depth, *bits_per_pixel_in, *bits_per_pixel_out,
4119 ms->val[OPT_PREVIEW].w);
4120
4121 return SANE_STATUS_GOOD;
4122 }
4123
4124
4125 /*---------- scsi_wait_for_image() -------------------------------------------*/
4126
4127 static SANE_Status
scsi_wait_for_image(Microtek2_Scanner * ms)4128 scsi_wait_for_image(Microtek2_Scanner *ms)
4129 {
4130 int retry = 60;
4131 SANE_Status status;
4132
4133
4134 DBG(30, "scsi_wait_for_image: ms=%p\n", (void *) ms);
4135
4136 while ( retry-- > 0 )
4137 {
4138 status = scsi_read_image_status(ms);
4139 if (status == SANE_STATUS_DEVICE_BUSY )
4140 {
4141 sleep(1);
4142 continue;
4143 }
4144 if ( status == SANE_STATUS_GOOD )
4145 return status;
4146
4147 /* status != GOOD && != BUSY */
4148 DBG(1, "scsi_wait_for_image: '%s'\n", sane_strstatus(status));
4149 return status;
4150 }
4151
4152 /* BUSY after n retries */
4153 DBG(1, "scsi_wait_for_image: '%s'\n", sane_strstatus(status));
4154 return status;
4155 }
4156
4157
4158 /*---------- scsi_read_gamma() -----------------------------------------------*/
4159
4160 /* currently not used */
4161 /*
4162 static SANE_Status
4163 scsi_read_gamma(Microtek2_Scanner *ms, int color)
4164 {
4165 uint8_t readgamma[RG_CMD_L];
4166 uint8_t result[3072];
4167 size_t size;
4168 SANE_Bool endiantype;
4169 SANE_Status status;
4170
4171 RG_CMD(readgamma);
4172 ENDIAN_TYPE(endiantype);
4173 RG_PCORMAC(readgamma, endiantype);
4174 RG_COLOR(readgamma, color);
4175 RG_WORD(readgamma, ( ms->dev->lut_entry_size == 1 ) ? 0 : 1);
4176 RG_TRANSFERLENGTH(readgamma, (color == 3 ) ? 3072 : 1024);
4177
4178 dump_area(readgamma, 10, "ReadGamma");
4179
4180 size = sizeof(result);
4181 status = sanei_scsi_cmd(ms->sfd, readgamma, sizeof(readgamma),
4182 result, &size);
4183 if ( status != SANE_STATUS_GOOD ) {
4184 DBG(1, "scsi_read_gamma: (L,R) read_gamma failed: status '%s'\n",
4185 sane_strstatus(status));
4186 return status;
4187 }
4188
4189 dump_area(result, 3072, "Result");
4190
4191 return SANE_STATUS_GOOD;
4192 }
4193 */
4194
4195
4196 /*---------- scsi_send_gamma() -----------------------------------------------*/
4197
4198 static SANE_Status
scsi_send_gamma(Microtek2_Scanner * ms)4199 scsi_send_gamma(Microtek2_Scanner *ms)
4200 {
4201 SANE_Bool endiantype;
4202 SANE_Status status;
4203 size_t size;
4204 uint8_t *cmd, color;
4205
4206
4207 DBG(30, "scsi_send_gamma: pos=%p, size=%d, word=%d, color=%d\n",
4208 (void *) ms->gamma_table, ms->lut_size_bytes, ms->word,
4209 ms->current_color);
4210
4211 if ( ( 3 * ms->lut_size_bytes ) <= 0xffff ) /*send Gamma with one command*/
4212 {
4213 cmd = (uint8_t *) alloca(SG_CMD_L + 3 * ms->lut_size_bytes);
4214 if ( cmd == NULL )
4215 {
4216 DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n");
4217 return SANE_STATUS_IO_ERROR;
4218 }
4219
4220 SG_SET_CMD(cmd);
4221 ENDIAN_TYPE(endiantype)
4222 SG_SET_PCORMAC(cmd, endiantype);
4223 SG_SET_COLOR(cmd, ms->current_color);
4224 SG_SET_WORD(cmd, ms->word);
4225 SG_SET_TRANSFERLENGTH(cmd, 3 * ms->lut_size_bytes);
4226 memcpy(cmd + SG_CMD_L, ms->gamma_table, 3 * ms->lut_size_bytes);
4227 size = 3 * ms->lut_size_bytes;
4228 if ( md_dump >= 2 )
4229 dump_area2(cmd, SG_CMD_L, "sendgammacmd");
4230 if ( md_dump >= 3 )
4231 dump_area2(cmd + SG_CMD_L, size, "sendgammadata");
4232
4233 status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0);
4234 if ( status != SANE_STATUS_GOOD )
4235 DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status));
4236 }
4237
4238 else /* send gamma with 3 commands, one for each color */
4239 {
4240 for ( color = 0; color < 3; color++ )
4241 {
4242 cmd = (uint8_t *) alloca(SG_CMD_L + ms->lut_size_bytes);
4243 if ( cmd == NULL )
4244 {
4245 DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n");
4246 return SANE_STATUS_IO_ERROR;
4247 }
4248 SG_SET_CMD(cmd);
4249 ENDIAN_TYPE(endiantype)
4250 SG_SET_PCORMAC(cmd, endiantype);
4251 SG_SET_COLOR(cmd, color);
4252 SG_SET_WORD(cmd, ms->word);
4253 SG_SET_TRANSFERLENGTH(cmd, ms->lut_size_bytes);
4254 memcpy(cmd + SG_CMD_L,
4255 ms->gamma_table + color * ms->lut_size_bytes,
4256 ms->lut_size_bytes);
4257 size = ms->lut_size_bytes;
4258 if ( md_dump >= 2 )
4259 dump_area2(cmd, SG_CMD_L, "sendgammacmd");
4260 if ( md_dump >= 3 )
4261 dump_area2(cmd + SG_CMD_L, size, "sendgammadata");
4262
4263 status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0);
4264 if ( status != SANE_STATUS_GOOD )
4265 DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status));
4266 }
4267
4268 }
4269
4270 return status;
4271 }
4272
4273
4274 /*---------- scsi_inquiry() --------------------------------------------------*/
4275
4276 static SANE_Status
scsi_inquiry(Microtek2_Info * mi,char * device)4277 scsi_inquiry(Microtek2_Info *mi, char *device)
4278 {
4279 SANE_Status status;
4280 uint8_t cmd[INQ_CMD_L];
4281 uint8_t *result;
4282 uint8_t inqlen;
4283 size_t size;
4284 int sfd;
4285
4286
4287 DBG(30, "scsi_inquiry: mi=%p, device='%s'\n", (void *) mi, device);
4288
4289 status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0);
4290 if ( status != SANE_STATUS_GOOD )
4291 {
4292 DBG(1, "scsi_inquiry: '%s'\n", sane_strstatus(status));
4293 return status;
4294 }
4295
4296 INQ_CMD(cmd);
4297 INQ_SET_ALLOC(cmd, INQ_ALLOC_L);
4298 result = (uint8_t *) alloca(INQ_ALLOC_L);
4299 if ( result == NULL )
4300 {
4301 DBG(1, "scsi_inquiry: malloc failed\n");
4302 sanei_scsi_close(sfd);
4303 return SANE_STATUS_NO_MEM;
4304 }
4305
4306 size = INQ_ALLOC_L;
4307 status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4308 if ( status != SANE_STATUS_GOOD )
4309 {
4310 DBG(1, "scsi_inquiry: '%s'\n", sane_strstatus(status));
4311 sanei_scsi_close(sfd);
4312 return status;
4313 }
4314
4315 INQ_GET_INQLEN(inqlen, result);
4316 INQ_SET_ALLOC(cmd, inqlen + INQ_ALLOC_L);
4317 result = alloca(inqlen + INQ_ALLOC_L);
4318 if ( result == NULL )
4319 {
4320 DBG(1, "scsi_inquiry: malloc failed\n");
4321 sanei_scsi_close(sfd);
4322 return SANE_STATUS_NO_MEM;
4323 }
4324 size = inqlen + INQ_ALLOC_L;
4325 if (md_dump >= 2 )
4326 dump_area2(cmd, sizeof(cmd), "inquiry");
4327
4328 status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4329 if ( status != SANE_STATUS_GOOD )
4330 {
4331 DBG(1, "scsi_inquiry: cmd '%s'\n", sane_strstatus(status));
4332 sanei_scsi_close(sfd);
4333 return status;
4334 }
4335 sanei_scsi_close(sfd);
4336
4337 if (md_dump >= 2 )
4338 {
4339 dump_area2((uint8_t *) result, size, "inquiryresult");
4340 dump_area((uint8_t *) result, size, "inquiryresult");
4341 }
4342
4343 /* copy results */
4344 INQ_GET_QUAL(mi->device_qualifier, result);
4345 INQ_GET_DEVT(mi->device_type, result);
4346 INQ_GET_VERSION(mi->scsi_version, result);
4347 INQ_GET_VENDOR(mi->vendor, (char *)result);
4348 INQ_GET_MODEL(mi->model, (char *)result);
4349 INQ_GET_REV(mi->revision, (char *)result);
4350 INQ_GET_MODELCODE(mi->model_code, result);
4351
4352
4353 return SANE_STATUS_GOOD;
4354 }
4355
4356
4357 /*---------- scsi_read_attributes() ------------------------------------------*/
4358
4359 static SANE_Status
scsi_read_attributes(Microtek2_Info * pmi,char * device,uint8_t scan_source)4360 scsi_read_attributes(Microtek2_Info *pmi, char *device, uint8_t scan_source)
4361 {
4362 SANE_Status status;
4363 Microtek2_Info *mi;
4364 uint8_t readattributes[RSA_CMD_L];
4365 uint8_t result[RSA_TRANSFERLENGTH];
4366 size_t size;
4367 int sfd;
4368
4369
4370 mi = &pmi[scan_source];
4371
4372 DBG(30, "scsi_read_attributes: mi=%p, device='%s', source=%d\n",
4373 (void *) mi, device, scan_source);
4374
4375 RSA_CMD(readattributes);
4376 RSA_SETMEDIA(readattributes, scan_source);
4377 status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0);
4378 if ( status != SANE_STATUS_GOOD )
4379 {
4380 DBG(1, "scsi_read_attributes: open '%s'\n", sane_strstatus(status));
4381 return status;
4382 }
4383
4384 if (md_dump >= 2 )
4385 dump_area2(readattributes, sizeof(readattributes), "scannerattributes");
4386
4387 size = sizeof(result);
4388 status = sanei_scsi_cmd(sfd, readattributes,
4389 sizeof(readattributes), result, &size);
4390 if ( status != SANE_STATUS_GOOD )
4391 {
4392 DBG(1, "scsi_read_attributes: cmd '%s'\n", sane_strstatus(status));
4393 sanei_scsi_close(sfd);
4394 return status;
4395 }
4396
4397 sanei_scsi_close(sfd);
4398
4399 /* The X6 appears to lie about the data format for a TMA */
4400 if ( (&pmi[0])->model_code == 0x91 )
4401 result[0] &= 0xfd;
4402 /* default value for calib_divisor ... bit49?? */
4403 mi->calib_divisor = 1;
4404 /* 9600XL */
4405 if ( (&pmi[0])->model_code == 0xde )
4406 mi->calib_divisor = 2;
4407 /* 6400XL has problems in lineart mode*/
4408 if ( (&pmi[0])->model_code == 0x89 )
4409 result[13] &= 0xfe; /* simulate no lineart */
4410 #if 0
4411 result[13] &= 0xfe; /* simulate no lineart */
4412 #endif
4413
4414 /* copy all the stuff into the info structure */
4415 RSA_COLOR(mi->color, result);
4416 RSA_ONEPASS(mi->onepass, result);
4417 RSA_SCANNERTYPE(mi->scanner_type, result);
4418 RSA_FEPROM(mi->feprom, result);
4419 RSA_DATAFORMAT(mi->data_format, result);
4420 RSA_COLORSEQUENCE(mi->color_sequence, result);
4421 RSA_NIS(mi->new_image_status, result);
4422 RSA_DATSEQ(mi->direction, result);
4423 RSA_CCDGAP(mi->ccd_gap, result);
4424 RSA_MAX_XRESOLUTION(mi->max_xresolution, result);
4425 RSA_MAX_YRESOLUTION(mi->max_yresolution, result);
4426 RSA_GEOWIDTH(mi->geo_width, result);
4427 RSA_GEOHEIGHT(mi->geo_height, result);
4428 RSA_OPTRESOLUTION(mi->opt_resolution, result);
4429 RSA_DEPTH(mi->depth, result);
4430 /* The X12USL doesn't say that it has 14bit */
4431 if ( (&pmi[0])->model_code == 0xb0 )
4432 mi->depth |= MI_HASDEPTH_14;
4433 RSA_SCANMODE(mi->scanmode, result);
4434 RSA_CCDPIXELS(mi->ccd_pixels, result);
4435 RSA_LUTCAP(mi->lut_cap, result);
4436 RSA_DNLDPTRN(mi->has_dnldptrn, result);
4437 RSA_GRAINSLCT(mi->grain_slct, result);
4438 RSA_SUPPOPT(mi->option_device, result);
4439 RSA_CALIBWHITE(mi->calib_white, result);
4440 RSA_CALIBSPACE(mi->calib_space, result);
4441 RSA_NLENS(mi->nlens, result);
4442 RSA_NWINDOWS(mi->nwindows, result);
4443 RSA_SHTRNSFEREQU(mi->shtrnsferequ, result);
4444 RSA_SCNBTTN(mi->scnbuttn, result);
4445 RSA_BUFTYPE(mi->buftype, result);
4446 RSA_REDBALANCE(mi->balance[0], result);
4447 RSA_GREENBALANCE(mi->balance[1], result);
4448 RSA_BLUEBALANCE(mi->balance[2], result);
4449 RSA_APSMAXFRAMES(mi->aps_maxframes, result);
4450
4451 if (md_dump >= 2 )
4452 dump_area2((uint8_t *) result, sizeof(result),
4453 "scannerattributesresults");
4454 if ( md_dump >= 1 && md_dump_clear )
4455 dump_attributes(mi);
4456
4457 return SANE_STATUS_GOOD;
4458 }
4459
4460
4461 /*---------- scsi_read_control_bits() ----------------------------------------*/
4462
4463 static SANE_Status
scsi_read_control_bits(Microtek2_Scanner * ms)4464 scsi_read_control_bits(Microtek2_Scanner *ms)
4465 {
4466 SANE_Status status;
4467 uint8_t cmd[RCB_CMD_L];
4468 uint32_t byte;
4469 int bit;
4470 int count_1s;
4471
4472 DBG(30, "scsi_read_control_bits: ms=%p, fd=%d\n", (void *) ms, ms->sfd);
4473 DBG(30, "ms->control_bytes = %p\n", (void *) ms->control_bytes);
4474
4475 RCB_SET_CMD(cmd);
4476 RCB_SET_LENGTH(cmd, ms->n_control_bytes);
4477
4478 if ( md_dump >= 2)
4479 dump_area2(cmd, RCB_CMD_L, "readcontrolbits");
4480
4481 status = sanei_scsi_cmd(ms->sfd,
4482 cmd,
4483 sizeof(cmd),
4484 ms->control_bytes,
4485 &ms->n_control_bytes);
4486
4487 if ( status != SANE_STATUS_GOOD )
4488 {
4489 DBG(1, "scsi_read_control_bits: cmd '%s'\n", sane_strstatus(status));
4490 return status;
4491 }
4492
4493 if ( md_dump >= 2)
4494 dump_area2(ms->control_bytes,
4495 ms->n_control_bytes,
4496 "readcontrolbitsresult");
4497
4498 count_1s = 0;
4499 for ( byte = 0; byte < ms->n_control_bytes; byte++ )
4500 {
4501 for ( bit = 0; bit < 8; bit++ )
4502 {
4503 if ( (ms->control_bytes[byte] >> bit) & 0x01 )
4504 ++count_1s;
4505 }
4506 }
4507 DBG(20, "read_control_bits: number of 1's in controlbytes: %d\n", count_1s);
4508
4509 return SANE_STATUS_GOOD;
4510 }
4511
4512
4513 /*---------- scsi_set_window() -----------------------------------------------*/
4514
4515 static SANE_Status
scsi_set_window(Microtek2_Scanner * ms,int n)4516 scsi_set_window(Microtek2_Scanner *ms, int n) { /* n windows, not yet */
4517 /* implemented */
4518 SANE_Status status;
4519 uint8_t *setwindow;
4520 int size;
4521
4522
4523 DBG(30, "scsi_set_window: ms=%p, wnd=%d\n", (void *) ms, n);
4524
4525 size = SW_CMD_L + SW_HEADER_L + n * SW_BODY_L;
4526 setwindow = (uint8_t *) malloc(size);
4527 DBG(100, "scsi_set_window: setwindow= %p, malloc'd %d Bytes\n",
4528 (void *) setwindow, size);
4529 if ( setwindow == NULL )
4530 {
4531 DBG(1, "scsi_set_window: malloc for setwindow failed\n");
4532 return SANE_STATUS_NO_MEM;
4533 }
4534 memset(setwindow, 0, size);
4535
4536 SW_CMD(setwindow);
4537 SW_PARAM_LENGTH(setwindow, SW_HEADER_L + n * SW_BODY_L);
4538 SW_WNDDESCLEN(setwindow + SW_HEADER_P, SW_WNDDESCVAL);
4539
4540 #define POS (setwindow + SW_BODY_P(n-1))
4541
4542 SW_WNDID(POS, n-1);
4543 SW_XRESDPI(POS, ms->x_resolution_dpi);
4544 SW_YRESDPI(POS, ms->y_resolution_dpi);
4545 SW_XPOSTL(POS, ms->x1_dots);
4546 SW_YPOSTL(POS, ms->y1_dots);
4547 SW_WNDWIDTH(POS, ms->width_dots);
4548 SW_WNDHEIGHT(POS, ms->height_dots);
4549 SW_THRESHOLD(POS, ms->threshold);
4550 SW_IMGCOMP(POS, ms->mode);
4551 SW_BITSPERPIXEL(POS, ms->depth);
4552 SW_EXTHT(POS, ms->use_external_ht);
4553 SW_INTHTINDEX(POS, ms->internal_ht_index);
4554 SW_RIF(POS, 1);
4555 SW_LENS(POS, 0); /* ???? */
4556 SW_INFINITE(POS, 0);
4557 SW_STAY(POS, ms->stay);
4558 SW_RAWDAT(POS, ms->rawdat);
4559 SW_QUALITY(POS, ms->quality);
4560 SW_FASTSCAN(POS, ms->fastscan);
4561 SW_MEDIA(POS, ms->scan_source);
4562 SW_BRIGHTNESS_M(POS, ms->brightness_m);
4563 SW_CONTRAST_M(POS, ms->contrast_m);
4564 SW_EXPOSURE_M(POS, ms->exposure_m);
4565 SW_SHADOW_M(POS, ms->shadow_m);
4566 SW_MIDTONE_M(POS, ms->midtone_m);
4567 SW_HIGHLIGHT_M(POS, ms->highlight_m);
4568 /* the following properties are only referenced if it's a color scan */
4569 /* but I guess they don't matter at a gray scan */
4570 SW_BRIGHTNESS_R(POS, ms->brightness_r);
4571 SW_CONTRAST_R(POS, ms->contrast_r);
4572 SW_EXPOSURE_R(POS, ms->exposure_r);
4573 SW_SHADOW_R(POS, ms->shadow_r);
4574 SW_MIDTONE_R(POS, ms->midtone_r);
4575 SW_HIGHLIGHT_R(POS, ms->highlight_r);
4576 SW_BRIGHTNESS_G(POS, ms->brightness_g);
4577 SW_CONTRAST_G(POS, ms->contrast_g);
4578 SW_EXPOSURE_G(POS, ms->exposure_g);
4579 SW_SHADOW_G(POS, ms->shadow_g);
4580 SW_MIDTONE_G(POS, ms->midtone_g);
4581 SW_HIGHLIGHT_G(POS, ms->highlight_g);
4582 SW_BRIGHTNESS_B(POS, ms->brightness_b);
4583 SW_CONTRAST_B(POS, ms->contrast_b);
4584 SW_EXPOSURE_B(POS, ms->exposure_b);
4585 SW_SHADOW_B(POS, ms->shadow_b);
4586 SW_MIDTONE_B(POS, ms->midtone_b);
4587 SW_HIGHLIGHT_B(POS, ms->highlight_b);
4588
4589 if ( md_dump >= 2 )
4590 {
4591 dump_area2(setwindow, 10, "setwindowcmd");
4592 dump_area2(setwindow + 10 ,8 , "setwindowheader");
4593 dump_area2(setwindow + 18 ,61 , "setwindowbody");
4594 }
4595
4596 status = sanei_scsi_cmd(ms->sfd, setwindow, size, NULL, 0);
4597 if ( status != SANE_STATUS_GOOD )
4598 DBG(1, "scsi_set_window: '%s'\n", sane_strstatus(status));
4599
4600 DBG(100, "scsi_set_window: free setwindow at %p\n", (void *) setwindow);
4601 free((void *) setwindow);
4602 return status;
4603 }
4604
4605
4606 /*---------- scsi_read_image_info() ------------------------------------------*/
4607
4608 static SANE_Status
scsi_read_image_info(Microtek2_Scanner * ms)4609 scsi_read_image_info(Microtek2_Scanner *ms)
4610 {
4611 uint8_t cmd[RII_CMD_L];
4612 uint8_t result[RII_RESULT_L];
4613 size_t size;
4614 SANE_Status status;
4615 Microtek2_Device *md;
4616
4617 md = ms->dev;
4618
4619 DBG(30, "scsi_read_image_info: ms=%p\n", (void *) ms);
4620
4621 RII_SET_CMD(cmd);
4622
4623 if ( md_dump >= 2)
4624 dump_area2(cmd, RII_CMD_L, "readimageinfo");
4625
4626 size = sizeof(result);
4627 status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), result, &size);
4628 if ( status != SANE_STATUS_GOOD )
4629 {
4630 DBG(1, "scsi_read_image_info: '%s'\n", sane_strstatus(status));
4631 return status;
4632 }
4633
4634 if ( md_dump >= 2)
4635 dump_area2(result, size, "readimageinforesult");
4636
4637 /* The V300 returns some values in only two bytes */
4638 if ( !(md->revision==2.70) && (md->model_flags & MD_RII_TWO_BYTES) )
4639 {
4640 RII_GET_V300_WIDTHPIXEL(ms->ppl, result);
4641 RII_GET_V300_WIDTHBYTES(ms->bpl, result);
4642 RII_GET_V300_HEIGHTLINES(ms->src_remaining_lines, result);
4643 RII_GET_V300_REMAINBYTES(ms->remaining_bytes, result);
4644 }
4645 else
4646 {
4647 RII_GET_WIDTHPIXEL(ms->ppl, result);
4648 RII_GET_WIDTHBYTES(ms->bpl, result);
4649 RII_GET_HEIGHTLINES(ms->src_remaining_lines, result);
4650 RII_GET_REMAINBYTES(ms->remaining_bytes, result);
4651 }
4652
4653 DBG(30, "scsi_read_image_info: ppl=%d, bpl=%d, lines=%d, remain=%d\n",
4654 ms->ppl, ms->bpl, ms->src_remaining_lines, ms->remaining_bytes);
4655
4656 return SANE_STATUS_GOOD;
4657 }
4658
4659
4660 /*---------- scsi_read_image() -----------------------------------------------*/
4661
4662 static SANE_Status
scsi_read_image(Microtek2_Scanner * ms,uint8_t * buffer,int bytes_per_pixel)4663 scsi_read_image(Microtek2_Scanner *ms, uint8_t *buffer, int bytes_per_pixel)
4664 {
4665 uint8_t cmd[RI_CMD_L];
4666 SANE_Bool endiantype;
4667 SANE_Status status;
4668 size_t size;
4669 size_t i;
4670 uint8_t tmp;
4671
4672
4673 DBG(30, "scsi_read_image: ms=%p, buffer=%p\n",
4674 (void *) ms, (void *) buffer);
4675
4676 ENDIAN_TYPE(endiantype)
4677 RI_SET_CMD(cmd);
4678 RI_SET_PCORMAC(cmd, endiantype);
4679 RI_SET_COLOR(cmd, ms->current_read_color);
4680 RI_SET_TRANSFERLENGTH(cmd, ms->transfer_length);
4681
4682 DBG(30, "scsi_read_image: transferlength=%d\n", ms->transfer_length);
4683
4684 if ( md_dump >= 2 )
4685 dump_area2(cmd, RI_CMD_L, "readimagecmd");
4686
4687 size = ms->transfer_length;
4688 status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), buffer, &size);
4689
4690 if ( buffer && ( ms->dev->model_flags & MD_PHANTOM_C6 ) && endiantype )
4691 {
4692 switch(bytes_per_pixel)
4693 {
4694 case 1: break;
4695 case 2:
4696 for ( i = 1; i < size; i += 2 )
4697 {
4698 tmp = buffer[i-1];
4699 buffer[i-1] = buffer[i];
4700 buffer[i] = tmp;
4701 }
4702 break;
4703 default:
4704 DBG(1, "scsi_read_image: Unexpected bytes_per_pixel=%d\n", bytes_per_pixel);
4705 }
4706 }
4707
4708 if ( status != SANE_STATUS_GOOD )
4709 DBG(1, "scsi_read_image: '%s'\n", sane_strstatus(status));
4710
4711 if ( md_dump > 3 )
4712 dump_area2(buffer, ms->transfer_length, "readimageresult");
4713
4714 return status;
4715 }
4716
4717
4718 /*---------- scsi_read_image_status() ----------------------------------------*/
4719
4720 static SANE_Status
scsi_read_image_status(Microtek2_Scanner * ms)4721 scsi_read_image_status(Microtek2_Scanner *ms)
4722 {
4723 Microtek2_Device *md;
4724 Microtek2_Info *mi;
4725 uint8_t cmd[RIS_CMD_L];
4726 uint8_t dummy;
4727 size_t dummy_length;
4728 SANE_Status status;
4729 SANE_Bool endian_type;
4730
4731 md = ms->dev;
4732 mi = &md->info[md->scan_source];
4733
4734 DBG(30, "scsi_read_image_status: ms=%p\n", (void *) ms);
4735
4736 ENDIAN_TYPE(endian_type)
4737 RIS_SET_CMD(cmd);
4738 RIS_SET_PCORMAC(cmd, endian_type);
4739 RIS_SET_COLOR(cmd, ms->current_read_color);
4740
4741 /* mi->new_image_status = SANE_TRUE; */ /* for testing*/
4742
4743 if ( mi->new_image_status == SANE_TRUE )
4744 {
4745 DBG(30, "scsi_read_image_status: use new image status \n");
4746 dummy_length = 1;
4747 cmd[8] = 1;
4748 }
4749 else
4750 {
4751 DBG(30, "scsi_read_image_status: use old image status \n");
4752 dummy_length = 0;
4753 cmd[8] = 0;
4754 }
4755
4756 if ( md_dump >= 2 )
4757 dump_area2(cmd, sizeof(cmd), "readimagestatus");
4758
4759 status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), &dummy, &dummy_length);
4760
4761 if ( mi->new_image_status == SANE_TRUE )
4762 {
4763 if ( dummy == 0 )
4764 status = SANE_STATUS_GOOD;
4765 else
4766 status = SANE_STATUS_DEVICE_BUSY;
4767 }
4768
4769 /* For some (X6USB) scanner
4770 We say we are going to try to read 1 byte of data (as recommended
4771 in the Microtek SCSI command documentation under "New Image Status")
4772 so that dubious SCSI host adapters (like the one in at least some
4773 Microtek X6 USB scanners) don't get wedged trying to do a zero
4774 length read. However, we do not actually try to read this byte of
4775 data, as that wedges the USB scanner as well.
4776 IOW the SCSI command says we are going to read 1 byte, but in fact
4777 we don't: */
4778 /*cmd[8] = 1;
4779 status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), &dummy, 0); */
4780
4781
4782 if ( status != SANE_STATUS_GOOD )
4783 DBG(1, "scsi_read_image_status: '%s'\n", sane_strstatus(status));
4784
4785 return status;
4786 }
4787
4788 /*---------- scsi_read_shading () --------------------------------------------*/
4789
4790 static SANE_Status
scsi_read_shading(Microtek2_Scanner * ms,uint8_t * buffer,uint32_t length)4791 scsi_read_shading(Microtek2_Scanner *ms, uint8_t *buffer, uint32_t length)
4792 {
4793 uint8_t cmd[RSI_CMD_L];
4794 SANE_Bool endiantype;
4795 SANE_Status status = SANE_STATUS_GOOD;
4796 size_t size;
4797
4798 DBG(30, "scsi_read_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n",
4799 (void *) buffer, length, ms->word, ms->current_color, ms->dark);
4800
4801 size = length;
4802
4803 RSI_SET_CMD(cmd);
4804 ENDIAN_TYPE(endiantype)
4805 RSI_SET_PCORMAC(cmd, endiantype);
4806 RSI_SET_COLOR(cmd, ms->current_color);
4807 RSI_SET_DARK(cmd, ms->dark);
4808 RSI_SET_WORD(cmd, ms->word);
4809 RSI_SET_TRANSFERLENGTH(cmd, size);
4810
4811 if ( md_dump >= 2 )
4812 dump_area2(cmd, RSI_CMD_L, "readshading");
4813
4814 DBG(100, "scsi_read_shading: sfd=%d, cmd=%p, sizeofcmd=%lu,"
4815 "dest=%p, destsize=%lu\n",
4816 ms->sfd, (void *) cmd, (u_long) sizeof(cmd), (void *) buffer,
4817 (u_long) size);
4818
4819 status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), buffer, &size);
4820 if ( status != SANE_STATUS_GOOD )
4821 DBG(1, "scsi_read_shading: '%s'\n", sane_strstatus(status));
4822
4823 if ( md_dump > 3)
4824 dump_area2(buffer,
4825 size,
4826 "readshadingresult");
4827
4828 return status;
4829 }
4830
4831
4832 /*---------- scsi_send_shading () --------------------------------------------*/
4833
4834 static SANE_Status
scsi_send_shading(Microtek2_Scanner * ms,uint8_t * shading_data,uint32_t length,uint8_t dark)4835 scsi_send_shading(Microtek2_Scanner *ms,
4836 uint8_t *shading_data,
4837 uint32_t length,
4838 uint8_t dark)
4839 {
4840 SANE_Bool endiantype;
4841 SANE_Status status;
4842 size_t size;
4843 uint8_t *cmd;
4844
4845
4846 DBG(30, "scsi_send_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n",
4847 (void *) shading_data, length, ms->word, ms->current_color, dark);
4848
4849 cmd = (uint8_t *) malloc(SSI_CMD_L + length);
4850 DBG(100, "scsi_send_shading: cmd=%p, malloc'd %d bytes\n",
4851 (void *) cmd, SSI_CMD_L + length);
4852 if ( cmd == NULL )
4853 {
4854 DBG(1, "scsi_send_shading: Couldn't get buffer for shading table\n");
4855 return SANE_STATUS_NO_MEM;
4856 }
4857
4858 SSI_SET_CMD(cmd);
4859 ENDIAN_TYPE(endiantype)
4860 SSI_SET_PCORMAC(cmd, endiantype);
4861 SSI_SET_COLOR(cmd, ms->current_color);
4862 SSI_SET_DARK(cmd, dark);
4863 SSI_SET_WORD(cmd, ms->word);
4864 SSI_SET_TRANSFERLENGTH(cmd, length);
4865 memcpy(cmd + SSI_CMD_L, shading_data, length);
4866 size = length;
4867
4868 if ( md_dump >= 2 )
4869 dump_area2(cmd, SSI_CMD_L, "sendshading");
4870 if ( md_dump >= 3 )
4871 dump_area2(cmd + SSI_CMD_L, size, "sendshadingdata");
4872
4873 status = sanei_scsi_cmd(ms->sfd, cmd, size + SSI_CMD_L, NULL, 0);
4874 if ( status != SANE_STATUS_GOOD )
4875 DBG(1, "scsi_send_shading: '%s'\n", sane_strstatus(status));
4876
4877 DBG(100, "free cmd at %p\n", (void *) cmd);
4878 free((void *) cmd);
4879
4880 return status;
4881
4882 }
4883
4884
4885 /*---------- scsi_read_system_status() ---------------------------------------*/
4886
4887 static SANE_Status
scsi_read_system_status(Microtek2_Device * md,int fd)4888 scsi_read_system_status(Microtek2_Device *md, int fd)
4889 {
4890 uint8_t cmd[RSS_CMD_L];
4891 uint8_t result[RSS_RESULT_L];
4892 int sfd;
4893 size_t size;
4894 SANE_Status status;
4895
4896 DBG(30, "scsi_read_system_status: md=%p, fd=%d\n", (void *) md, fd);
4897
4898 if ( fd == -1 )
4899 {
4900 status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
4901 if ( status != SANE_STATUS_GOOD )
4902 {
4903 DBG(1, "scsi_read_system_status: open '%s'\n",
4904 sane_strstatus(status));
4905 return status;
4906 }
4907 }
4908 else
4909 sfd = fd;
4910
4911 RSS_CMD(cmd);
4912
4913 if ( md_dump >= 2)
4914 dump_area2(cmd, RSS_CMD_L, "readsystemstatus");
4915
4916 size = sizeof(result);
4917 status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4918
4919 if ( status != SANE_STATUS_GOOD )
4920 {
4921 DBG(1, "scsi_read_system_status: cmd '%s'\n", sane_strstatus(status));
4922 sanei_scsi_close(sfd);
4923 return status;
4924 }
4925
4926 if ( fd == -1 )
4927 sanei_scsi_close(sfd);
4928
4929 if ( md_dump >= 2)
4930 dump_area2(result, size, "readsystemstatusresult");
4931
4932 md->status.sskip = RSS_SSKIP(result);
4933 md->status.ntrack = RSS_NTRACK(result);
4934 md->status.ncalib = RSS_NCALIB(result);
4935 md->status.tlamp = RSS_TLAMP(result);
4936 md->status.flamp = RSS_FLAMP(result);
4937 md->status.rdyman= RSS_RDYMAN(result);
4938 md->status.trdy = RSS_TRDY(result);
4939 md->status.frdy = RSS_FRDY(result);
4940 md->status.adp = RSS_RDYMAN(result);
4941 md->status.detect = RSS_DETECT(result);
4942 md->status.adptime = RSS_ADPTIME(result);
4943 md->status.lensstatus = RSS_LENSSTATUS(result);
4944 md->status.aloff = RSS_ALOFF(result);
4945 md->status.timeremain = RSS_TIMEREMAIN(result);
4946 md->status.tmacnt = RSS_TMACNT(result);
4947 md->status.paper = RSS_PAPER(result);
4948 md->status.adfcnt = RSS_ADFCNT(result);
4949 md->status.currentmode = RSS_CURRENTMODE(result);
4950 md->status.buttoncount = RSS_BUTTONCOUNT(result);
4951
4952 return SANE_STATUS_GOOD;
4953 }
4954
4955
4956 /*---------- scsi_request_sense() --------------------------------------------*/
4957
4958 /* currently not used */
4959
4960 #if 0
4961
4962 static SANE_Status
4963 scsi_request_sense(Microtek2_Scanner *ms)
4964 {
4965 uint8_t requestsense[RQS_CMD_L];
4966 uint8_t buffer[100];
4967 SANE_Status status;
4968 int size;
4969 int asl;
4970 int as_info_length;
4971
4972 DBG(30, "scsi_request_sense: ms=%p\n", (void *) ms);
4973
4974 RQS_CMD(requestsense);
4975 RQS_ALLOCLENGTH(requestsense, 100);
4976
4977 size = sizeof(buffer);
4978 status = sanei_scsi_cmd(ms->sfd, requestsense, sizeof(requestsense),
4979 buffer, &size);
4980
4981 if ( status != SANE_STATUS_GOOD )
4982 {
4983 DBG(1, "scsi_request_sense: '%s'\n", sane_strstatus(status));
4984 return status;
4985 }
4986
4987 if ( md_dump >= 2 )
4988 dump_area2(buffer, size, "requestsenseresult");
4989
4990 dump_area(buffer, RQS_LENGTH(buffer), "RequestSense");
4991 asl = RQS_ASL(buffer);
4992 if ( (as_info_length = RQS_ASINFOLENGTH(buffer)) > 0 )
4993 DBG(25, "scsi_request_sense: info '%.*s'\n",
4994 as_info_length, RQS_ASINFO(buffer));
4995
4996 return SANE_STATUS_GOOD;
4997 }
4998 #endif
4999
5000
5001 /*---------- scsi_send_system_status() ---------------------------------------*/
5002
5003 static SANE_Status
scsi_send_system_status(Microtek2_Device * md,int fd)5004 scsi_send_system_status(Microtek2_Device *md, int fd)
5005 {
5006 uint8_t cmd[SSS_CMD_L + SSS_DATA_L];
5007 uint8_t *pos;
5008 int sfd;
5009 SANE_Status status;
5010
5011
5012 DBG(30, "scsi_send_system_status: md=%p, fd=%d\n", (void *) md, fd);
5013
5014 memset(cmd, 0, SSS_CMD_L + SSS_DATA_L);
5015 if ( fd == -1 )
5016 {
5017 status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
5018 if ( status != SANE_STATUS_GOOD )
5019 {
5020 DBG(1, "scsi_send_system_status: open '%s'\n",
5021 sane_strstatus(status));
5022 return status;
5023 }
5024 }
5025 else
5026 sfd = fd;
5027
5028 SSS_CMD(cmd);
5029 pos = cmd + SSS_CMD_L;
5030 SSS_STICK(pos, md->status.stick);
5031 SSS_NTRACK(pos, md->status.ntrack);
5032 SSS_NCALIB(pos, md->status.ncalib);
5033 SSS_TLAMP(pos, md->status.tlamp);
5034 SSS_FLAMP(pos, md->status.flamp);
5035 SSS_RESERVED17(pos, md->status.reserved17);
5036 SSS_RDYMAN(pos, md->status.rdyman);
5037 SSS_TRDY(pos, md->status.trdy);
5038 SSS_FRDY(pos, md->status.frdy);
5039 SSS_ADP(pos, md->status.adp);
5040 SSS_DETECT(pos, md->status.detect);
5041 SSS_ADPTIME(pos, md->status.adptime);
5042 SSS_LENSSTATUS(pos, md->status.lensstatus);
5043 SSS_ALOFF(pos, md->status.aloff);
5044 SSS_TIMEREMAIN(pos, md->status.timeremain);
5045 SSS_TMACNT(pos, md->status.tmacnt);
5046 SSS_PAPER(pos, md->status.paper);
5047 SSS_ADFCNT(pos, md->status.adfcnt);
5048 SSS_CURRENTMODE(pos, md->status.currentmode);
5049 SSS_BUTTONCOUNT(pos, md->status.buttoncount);
5050
5051 if ( md_dump >= 2)
5052 {
5053 dump_area2(cmd, SSS_CMD_L, "sendsystemstatus");
5054 dump_area2(cmd + SSS_CMD_L, SSS_DATA_L, "sendsystemstatusdata");
5055 }
5056
5057 status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), NULL, 0);
5058 if ( status != SANE_STATUS_GOOD )
5059 DBG(1, "scsi_send_system_status: '%s'\n", sane_strstatus(status));
5060
5061 if ( fd == -1 )
5062 sanei_scsi_close(sfd);
5063 return status;
5064 }
5065
5066
5067 /*---------- scsi_sense_handler() --------------------------------------------*/
5068 /* rewritten 19.12.2001 for better SANE_STATUS return codes */
5069
5070 static SANE_Status
scsi_sense_handler(int fd,u_char * sense,void * arg)5071 scsi_sense_handler (int fd, u_char *sense, void *arg)
5072 {
5073 int as_info_length;
5074 uint8_t sense_key;
5075 uint8_t asc;
5076 uint8_t ascq;
5077
5078
5079 DBG(30, "scsi_sense_handler: fd=%d, sense=%p arg=%p\n",
5080 fd, (void *) sense, arg);
5081
5082 dump_area(sense, RQS_LENGTH(sense), "SenseBuffer");
5083
5084 sense_key = RQS_SENSEKEY(sense);
5085 asc = RQS_ASC(sense);
5086 ascq = RQS_ASCQ(sense);
5087
5088 DBG(5, "scsi_sense_handler: SENSE KEY (0x%02x), "
5089 "ASC (0x%02x), ASCQ (0x%02x)\n", sense_key, asc, ascq);
5090
5091 if ( (as_info_length = RQS_ASINFOLENGTH(sense)) > 0 )
5092 DBG(5,"scsi_sense_handler: info: '%*s'\n",
5093 as_info_length, RQS_ASINFO(sense));
5094
5095 switch ( sense_key )
5096 {
5097 case RQS_SENSEKEY_NOSENSE:
5098 return SANE_STATUS_GOOD;
5099
5100 case RQS_SENSEKEY_HWERR:
5101 case RQS_SENSEKEY_ILLEGAL:
5102 case RQS_SENSEKEY_VENDOR:
5103 if ( asc == 0x4a && ascq == 0x00 )
5104 DBG(5, "scsi_sense_handler: Command phase error\n");
5105 else if ( asc == 0x2c && ascq == 0x00 )
5106 DBG(5, "scsi_sense_handler: Command sequence error\n");
5107 else if ( asc == 0x4b && ascq == 0x00 )
5108 DBG(5, "scsi_sense_handler: Data phase error\n");
5109 else if ( asc == 0x40 )
5110 {
5111 DBG(5, "scsi_sense_handler: Hardware diagnostic failure:\n");
5112 switch ( ascq )
5113 {
5114 case RQS_ASCQ_CPUERR:
5115 DBG(5, "scsi_sense_handler: CPU error\n");
5116 break;
5117 case RQS_ASCQ_SRAMERR:
5118 DBG(5, "scsi_sense_handler: SRAM error\n");
5119 break;
5120 case RQS_ASCQ_DRAMERR:
5121 DBG(5, "scsi_sense_handler: DRAM error\n");
5122 break;
5123 case RQS_ASCQ_DCOFF:
5124 DBG(5, "scsi_sense_handler: DC Offset error\n");
5125 break;
5126 case RQS_ASCQ_GAIN:
5127 DBG(5, "scsi_sense_handler: Gain error\n");
5128 break;
5129 case RQS_ASCQ_POS:
5130 DBG(5, "scsi_sense_handler: Positioning error\n");
5131 break;
5132 default:
5133 DBG(5, "scsi_sense_handler: Unknown combination of ASC"
5134 " (0x%02x) and ASCQ (0x%02x)\n", asc, ascq);
5135 break;
5136 }
5137 }
5138 else if ( asc == 0x00 && ascq == 0x05)
5139 {
5140 DBG(5, "scsi_sense_handler: End of data detected\n");
5141 return SANE_STATUS_EOF;
5142 }
5143 else if ( asc == 0x3d && ascq == 0x00)
5144 DBG(5, "scsi_sense_handler: Invalid bit in IDENTIFY\n");
5145 else if ( asc == 0x2c && ascq == 0x02 )
5146 /* Ok */ DBG(5, "scsi_sense_handler: Invalid comb. of windows specified\n");
5147 else if ( asc == 0x20 && ascq == 0x00 )
5148 /* Ok */ DBG(5, "scsi_sense_handler: Invalid command opcode\n");
5149 else if ( asc == 0x24 && ascq == 0x00 )
5150 /* Ok */ DBG(5, "scsi_sense_handler: Invalid field in CDB\n");
5151 else if ( asc == 0x26 && ascq == 0x00 )
5152 DBG(5, "scsi_sense_handler: Invalid field in the param list\n");
5153 else if ( asc == 0x49 && ascq == 0x00 )
5154 DBG(5, "scsi_sense_handler: Invalid message error\n");
5155 else if ( asc == 0x60 && ascq == 0x00 )
5156 DBG(5, "scsi_sense_handler: Lamp failure\n");
5157 else if ( asc == 0x25 && ascq == 0x00 )
5158 DBG(5, "scsi_sense_handler: Unsupported logic. unit\n");
5159 else if ( asc == 0x53 && ascq == 0x00 )
5160 {
5161 DBG(5, "scsi_sense_handler: ADF paper jam or no paper\n");
5162 return SANE_STATUS_NO_DOCS;
5163 }
5164 else if ( asc == 0x54 && ascq == 0x00 )
5165 {
5166 DBG(5, "scsi_sense_handler: Media bumping\n");
5167 return SANE_STATUS_JAMMED; /* Don't know if this is right! */
5168 }
5169 else if ( asc == 0x55 && ascq == 0x00 )
5170 {
5171 DBG(5, "scsi_sense_handler: Scan Job stopped or cancelled\n");
5172 return SANE_STATUS_CANCELLED;
5173 }
5174 else if ( asc == 0x3a && ascq == 0x00 )
5175 {
5176 DBG(5, "scsi_sense_handler: Media (ADF or TMA) not available\n");
5177 return SANE_STATUS_NO_DOCS;
5178 }
5179 else if ( asc == 0x3a && ascq == 0x01 )
5180 {
5181 DBG(5, "scsi_sense_handler: Door is not closed\n");
5182 return SANE_STATUS_COVER_OPEN;
5183 }
5184 else if ( asc == 0x3a && ascq == 0x02 )
5185 DBG(5, "scsi_sense_handler: Door is not opened\n");
5186 else if ( asc == 0x00 && ascq == 0x00 )
5187 DBG(5, "scsi_sense_handler: No additional sense information\n");
5188 /* Ok */ else if ( asc == 0x1a && ascq == 0x00 )
5189 DBG(5, "scsi_sense_handler: Parameter list length error\n");
5190 else if ( asc == 0x26 && ascq == 0x02 )
5191 DBG(5, "scsi_sense_handler: Parameter value invalid\n");
5192 else if ( asc == 0x03 && ascq == 0x00 )
5193 DBG(5, "scsi_sense_handler: Peripheral device write fault - "
5194 "Firmware Download Error\n");
5195 else if ( asc == 0x2c && ascq == 0x01 )
5196 DBG(5, "scsi_sense_handler: Too many windows specified\n");
5197 else if ( asc == 0x80 && ascq == 0x00 )
5198 DBG(5, "scsi_sense_handler: Target abort scan\n");
5199 else if ( asc == 0x96 && ascq == 0x08 )
5200 {
5201 DBG(5, "scsi_sense_handler: Firewire Device busy\n");
5202 return SANE_STATUS_DEVICE_BUSY;
5203 }
5204 else
5205 DBG(5, "scsi_sense_handler: Unknown combination of SENSE KEY "
5206 "(0x%02x), ASC (0x%02x) and ASCQ (0x%02x)\n",
5207 sense_key, asc, ascq);
5208
5209 return SANE_STATUS_IO_ERROR;
5210
5211 default:
5212 DBG(5, "scsi_sense_handler: Unknown sense key (0x%02x)\n",
5213 sense_key);
5214 return SANE_STATUS_IO_ERROR;
5215 }
5216 }
5217
5218
5219 /*---------- scsi_test_unit_ready() ------------------------------------------*/
5220
5221 static SANE_Status
scsi_test_unit_ready(Microtek2_Device * md)5222 scsi_test_unit_ready(Microtek2_Device *md)
5223 {
5224 SANE_Status status;
5225 uint8_t tur[TUR_CMD_L];
5226 int sfd;
5227
5228
5229 DBG(30, "scsi_test_unit_ready: md=%s\n", md->name);
5230
5231 TUR_CMD(tur);
5232 status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
5233 if ( status != SANE_STATUS_GOOD )
5234 {
5235 DBG(1, "scsi_test_unit_ready: open '%s'\n", sane_strstatus(status));
5236 return status;
5237 }
5238
5239 if ( md_dump >= 2 )
5240 dump_area2(tur, sizeof(tur), "testunitready");
5241
5242 status = sanei_scsi_cmd(sfd, tur, sizeof(tur), NULL, 0);
5243 if ( status != SANE_STATUS_GOOD )
5244 DBG(1, "scsi_test_unit_ready: cmd '%s'\n", sane_strstatus(status));
5245
5246 sanei_scsi_close(sfd);
5247 return status;
5248 }
5249
5250
5251 /*---------- sane_start() ----------------------------------------------------*/
5252
5253 SANE_Status
sane_start(SANE_Handle handle)5254 sane_start(SANE_Handle handle)
5255 {
5256 SANE_Status status = SANE_STATUS_GOOD;
5257 Microtek2_Scanner *ms = handle;
5258 Microtek2_Device *md;
5259 Microtek2_Info *mi;
5260 uint8_t *pos;
5261 int color, rc, retry;
5262
5263 DBG(30, "sane_start: handle=0x%p\n", handle);
5264
5265 md = ms->dev;
5266 mi = &md->info[md->scan_source];
5267 ms->n_control_bytes = md->n_control_bytes;
5268
5269 if ( md->model_flags & MD_READ_CONTROL_BIT )
5270 {
5271 if (ms->control_bytes) free((void *)ms->control_bytes);
5272 ms->control_bytes = (uint8_t *) malloc(ms->n_control_bytes);
5273 DBG(100, "sane_start: ms->control_bytes=%p, malloc'd %lu bytes\n",
5274 (void *) ms->control_bytes, (u_long) ms->n_control_bytes);
5275 if ( ms->control_bytes == NULL )
5276 {
5277 DBG(1, "sane_start: malloc() for control bits failed\n");
5278 status = SANE_STATUS_NO_MEM;
5279 goto cleanup;
5280 }
5281 }
5282
5283 if (ms->sfd < 0) /* first or only pass of this scan */
5284 {
5285 /* open device */
5286 for ( retry = 0; retry < 10; retry++ )
5287 {
5288 status = sanei_scsi_open (md->sane.name, &ms->sfd,
5289 scsi_sense_handler, 0);
5290 if ( status != SANE_STATUS_DEVICE_BUSY )
5291 break;
5292 DBG(30, "sane_start: Scanner busy, trying again\n");
5293 sleep(1);
5294 }
5295 if ( status != SANE_STATUS_GOOD )
5296 {
5297 DBG(1, "sane_start: scsi_open: '%s'\n", sane_strstatus(status));
5298 goto cleanup;
5299 }
5300
5301 status = scsi_read_system_status(md, ms->sfd);
5302 if ( status != SANE_STATUS_GOOD )
5303 goto cleanup;
5304
5305 if ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
5306 DBG(30, "sane_start: backend calibration on\n");
5307 else
5308 DBG(30, "sane_start: backend calibration off\n");
5309
5310 if ( ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
5311 && !( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) )
5312 {
5313 /* Read shading only once - possible with CIS scanners */
5314 /* assuming only CIS scanners use Controlbits */
5315 if ( ( md->shading_table_w == NULL )
5316 || !( md->model_flags & MD_READ_CONTROL_BIT ) )
5317 {
5318 status = get_scan_parameters(ms);
5319 if ( status != SANE_STATUS_GOOD )
5320 goto cleanup;
5321
5322 status = read_shading_image(ms);
5323 if ( status != SANE_STATUS_GOOD )
5324 goto cleanup;
5325 }
5326 }
5327
5328 status = get_scan_parameters(ms);
5329 if ( status != SANE_STATUS_GOOD )
5330 goto cleanup;
5331
5332 status = scsi_read_system_status(md, ms->sfd);
5333 if ( status != SANE_STATUS_GOOD )
5334 goto cleanup;
5335
5336 md->status.aloff |= 128;
5337 md->status.timeremain = 10;
5338
5339 if ( ms->scan_source == MS_SOURCE_FLATBED
5340 || ms->scan_source == MS_SOURCE_ADF )
5341 {
5342 md->status.flamp |= MD_FLAMP_ON;
5343 md->status.tlamp &= ~MD_TLAMP_ON;
5344 }
5345 else
5346 {
5347 md->status.flamp &= ~MD_FLAMP_ON;
5348 md->status.tlamp |= MD_TLAMP_ON;
5349 }
5350
5351 if ( ms->lightlid35 )
5352 {
5353 md->status.flamp &= ~MD_FLAMP_ON;
5354 /* md->status.tlamp |= MD_TLAMP_ON;*/
5355 /* with this line on some scanners (X6, 0x91) the Flamp goes on */
5356 }
5357
5358 if ( ms->no_backtracking )
5359 md->status.ntrack |= MD_NTRACK_ON;
5360 else
5361 md->status.ntrack &= ~MD_NTRACK_ON;
5362
5363 status = scsi_send_system_status(md, ms->sfd);
5364 if ( status != SANE_STATUS_GOOD )
5365 goto cleanup;
5366
5367 /* calculate gamma: we assume, that the gamma values are transferred */
5368 /* with one send gamma command, even if it is a 3 pass scanner */
5369 if ( md->model_flags & MD_NO_GAMMA )
5370 {
5371 ms->lut_size = (int) pow(2.0, (double) ms->depth);
5372 ms->lut_entry_size = ms->depth > 8 ? 2 : 1;
5373 }
5374 else
5375 {
5376 get_lut_size(mi, &ms->lut_size, &ms->lut_entry_size);
5377 }
5378 ms->lut_size_bytes = ms->lut_size * ms->lut_entry_size;
5379 ms->word = (ms->lut_entry_size == 2);
5380
5381 ms->gamma_table = (uint8_t *) malloc(3 * ms->lut_size_bytes );
5382 DBG(100, "sane_start: ms->gamma_table=%p, malloc'd %d bytes\n",
5383 (void *) ms->gamma_table, 3 * ms->lut_size_bytes);
5384 if ( ms->gamma_table == NULL )
5385 {
5386 DBG(1, "sane_start: malloc for gammatable failed\n");
5387 status = SANE_STATUS_NO_MEM;
5388 goto cleanup;
5389 }
5390 for ( color = 0; color < 3; color++ )
5391 {
5392 pos = ms->gamma_table + color * ms->lut_size_bytes;
5393 calculate_gamma(ms, pos, color, ms->gamma_mode);
5394 }
5395
5396 /* Some models ignore the settings for the exposure time, */
5397 /* so we must do it ourselves. Apparently this seems to be */
5398 /* the case for all models that have the chunky data format */
5399
5400 if ( mi->data_format == MI_DATAFMT_CHUNKY )
5401 set_exposure(ms);
5402
5403 if ( ! (md->model_flags & MD_NO_GAMMA) )
5404 {
5405 status = scsi_send_gamma(ms);
5406 if ( status != SANE_STATUS_GOOD )
5407 goto cleanup;
5408 }
5409
5410 status = scsi_set_window(ms, 1);
5411 if ( status != SANE_STATUS_GOOD )
5412 goto cleanup;
5413
5414 ms->scanning = SANE_TRUE;
5415 ms->cancelled = SANE_FALSE;
5416 }
5417
5418 ++ms->current_pass;
5419
5420 status = scsi_read_image_info(ms);
5421 if ( status != SANE_STATUS_GOOD )
5422 goto cleanup;
5423
5424 status = prepare_buffers(ms);
5425 if ( status != SANE_STATUS_GOOD )
5426 goto cleanup;
5427
5428 status = calculate_sane_params(ms);
5429 if ( status != SANE_STATUS_GOOD )
5430 goto cleanup;
5431
5432 if ( !( md->model_flags & MD_NO_RIS_COMMAND ) )
5433 {
5434 /* !!FIXME!! - hack for C6USB because RIS over USB doesn't wait until */
5435 /* scanner ready */
5436 if (mi->model_code == 0x9a)
5437 sleep(2);
5438
5439 status = scsi_wait_for_image(ms);
5440 if ( status != SANE_STATUS_GOOD )
5441 goto cleanup;
5442 }
5443
5444 if ( ms->calib_backend
5445 && ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5446 && ( ( md->shading_table_w == NULL )
5447 || ( ms->mode != md->shading_table_contents )
5448 )
5449 )
5450 {
5451 status = read_cx_shading(ms);
5452 if ( status != SANE_STATUS_GOOD )
5453 goto cleanup;
5454 }
5455
5456 if ( ms->lightlid35 )
5457 /* hopefully this leads to a switched off flatbed lamp with lightlid */
5458 {
5459 status = scsi_read_system_status(md, ms->sfd);
5460 if ( status != SANE_STATUS_GOOD )
5461 goto cleanup;
5462
5463 md->status.flamp &= ~MD_FLAMP_ON;
5464 md->status.tlamp &= ~MD_TLAMP_ON;
5465
5466 status = scsi_send_system_status(md, ms->sfd);
5467 if ( status != SANE_STATUS_GOOD )
5468 goto cleanup;
5469 }
5470
5471 if ( md->model_flags & MD_READ_CONTROL_BIT )
5472 {
5473 status = scsi_read_control_bits(ms);
5474 if ( status != SANE_STATUS_GOOD )
5475 goto cleanup;
5476
5477 if ( ms->calib_backend )
5478 {
5479 status = condense_shading(ms);
5480 if ( status != SANE_STATUS_GOOD )
5481 goto cleanup;
5482 }
5483 }
5484
5485 /* open a pipe and fork a child process, that actually reads the data */
5486 rc = pipe(ms->fd);
5487 if ( rc == -1 )
5488 {
5489 DBG(1, "sane_start: pipe failed\n");
5490 status = SANE_STATUS_IO_ERROR;
5491 goto cleanup;
5492 }
5493
5494 /* create reader routine as new thread or process */
5495 ms->pid = sanei_thread_begin( reader_process,(void*) ms);
5496
5497 if ( !sanei_thread_is_valid (ms->pid) )
5498 {
5499 DBG(1, "sane_start: fork failed\n");
5500 status = SANE_STATUS_IO_ERROR;
5501 goto cleanup;
5502 }
5503
5504 if (sanei_thread_is_forked()) close(ms->fd[1]);
5505
5506 return SANE_STATUS_GOOD;
5507
5508 cleanup:
5509 cleanup_scanner(ms);
5510 return status;
5511 }
5512
5513 /*---------- prepare_buffers -------------------------------------------------*/
5514
5515 static SANE_Status
prepare_buffers(Microtek2_Scanner * ms)5516 prepare_buffers(Microtek2_Scanner *ms)
5517 {
5518 SANE_Status status;
5519 Microtek2_Device *md;
5520 Microtek2_Info *mi;
5521 uint32_t strip_lines;
5522 int i;
5523
5524 status = SANE_STATUS_GOOD;
5525 DBG(30, "prepare_buffers: ms=0x%p\n", (void *) ms);
5526
5527 md = ms->dev;
5528 mi = &md->info[md->scan_source];
5529
5530 /* calculate maximum number of lines to read */
5531 strip_lines = (int) ((double) ms->y_resolution_dpi * md->opts.strip_height);
5532 if ( strip_lines == 0 )
5533 strip_lines = 1;
5534
5535 /* calculate number of lines that fit into the source buffer */
5536 #ifdef TESTBACKEND
5537 ms->src_max_lines = MIN( 5000000 / ms->bpl, strip_lines);
5538 #else
5539 ms->src_max_lines = MIN( sanei_scsi_max_request_size / ms->bpl, strip_lines);
5540 #endif
5541 if ( ms->src_max_lines == 0 )
5542 {
5543 DBG(1, "sane_start: Scan buffer too small\n");
5544 status = SANE_STATUS_IO_ERROR;
5545 goto cleanup;
5546 }
5547
5548 /* allocate buffers */
5549 ms->src_buffer_size = ms->src_max_lines * ms->bpl;
5550
5551 if ( ms->mode == MS_MODE_COLOR && mi->data_format == MI_DATAFMT_LPLSEGREG )
5552 {
5553 /* In this case the data is not necessarily in the order RGB */
5554 /* and there may be different numbers of read red, green and blue */
5555 /* segments. We allocate a second buffer to read new lines in */
5556 /* and hold undelivered pixels in the other buffer */
5557 int extra_buf_size;
5558
5559 extra_buf_size = 2 * ms->bpl * mi->ccd_gap
5560 * (int) ceil( (double) mi->max_yresolution
5561 / (double) mi->opt_resolution);
5562 for ( i = 0; i < 2; i++ )
5563 {
5564 if ( ms->buf.src_buffer[i] )
5565 free((void *) ms->buf.src_buffer[i]);
5566 ms->buf.src_buffer[i] = (uint8_t *) malloc(ms->src_buffer_size
5567 + extra_buf_size);
5568 DBG(100, "prepare_buffers: ms->buf.src_buffer[%d]=%p,"
5569 "malloc'd %d bytes\n", i, (void *) ms->buf.src_buffer[i],
5570 ms->src_buffer_size + extra_buf_size);
5571 if ( ms->buf.src_buffer[i] == NULL )
5572 {
5573 DBG(1, "sane_start: malloc for scan buffer failed\n");
5574 status = SANE_STATUS_NO_MEM;
5575 goto cleanup;
5576 }
5577 }
5578 ms->buf.free_lines = ms->src_max_lines + extra_buf_size / ms->bpl;
5579 ms->buf.free_max_lines = ms->buf.free_lines;
5580 ms->buf.src_buf = ms->buf.src_buffer[0];
5581 ms->buf.current_src = 0; /* index to current buffer */
5582 }
5583 else
5584 {
5585 if ( ms->buf.src_buf )
5586 free((void *) ms->buf.src_buf);
5587 ms->buf.src_buf = malloc(ms->src_buffer_size);
5588 DBG(100, "sane_start: ms->buf.src_buf=%p, malloc'd %d bytes\n",
5589 (void *) ms->buf.src_buf, ms->src_buffer_size);
5590 if ( ms->buf.src_buf == NULL )
5591 {
5592 DBG(1, "sane_start: malloc for scan buffer failed\n");
5593 status = SANE_STATUS_NO_MEM;
5594 goto cleanup;
5595 }
5596 }
5597
5598 for ( i = 0; i < 3; i++ )
5599 {
5600 ms->buf.current_pos[i] = ms->buf.src_buffer[0];
5601 ms->buf.planes[0][i] = 0;
5602 ms->buf.planes[1][i] = 0;
5603 }
5604
5605 /* allocate a temporary buffer for the data, if auto_adjust threshold */
5606 /* is selected. */
5607
5608 if ( ms->auto_adjust == 1 )
5609 {
5610 ms->temporary_buffer = (uint8_t *) malloc(ms->remaining_bytes);
5611 DBG(100, "sane_start: ms->temporary_buffer=%p, malloc'd %d bytes\n",
5612 (void *) ms->temporary_buffer, ms->remaining_bytes);
5613 if ( ms->temporary_buffer == NULL )
5614 {
5615 DBG(1, "sane_start: malloc() for temporary buffer failed\n");
5616 status = SANE_STATUS_NO_MEM;
5617 goto cleanup;
5618 }
5619 }
5620 else
5621 ms->temporary_buffer = NULL;
5622
5623 /* some data formats have additional information in a scan line, which */
5624 /* is not transferred to the frontend; real_bpl is the number of bytes */
5625 /* per line, that is copied into the frontend's buffer */
5626 ms->real_bpl = (uint32_t) ceil( ((double) ms->ppl *
5627 (double) ms->bits_per_pixel_out) / 8.0 );
5628 if ( mi->onepass && ms->mode == MS_MODE_COLOR )
5629 ms->real_bpl *= 3;
5630
5631 ms->real_remaining_bytes = ms->real_bpl * ms->src_remaining_lines;
5632
5633 return SANE_STATUS_GOOD;
5634
5635 cleanup:
5636 cleanup_scanner(ms);
5637 return status;
5638
5639 }
5640 static void
write_shading_buf_pnm(Microtek2_Scanner * ms,uint32_t lines)5641 write_shading_buf_pnm(Microtek2_Scanner *ms, uint32_t lines)
5642 {
5643 FILE *outfile;
5644 uint16_t pixel, color, linenr, factor;
5645 unsigned char img_val_out;
5646 float img_val = 0;
5647 Microtek2_Device *md;
5648 Microtek2_Info *mi;
5649
5650 md = ms->dev;
5651 mi = &md->info[md->scan_source];
5652
5653 if ( mi->depth & MI_HASDEPTH_16 )
5654 factor = 256;
5655 else if ( mi->depth & MI_HASDEPTH_14 )
5656 factor = 64;
5657 else if ( mi->depth & MI_HASDEPTH_12 )
5658 factor = 16;
5659 else if ( mi->depth & MI_HASDEPTH_10 )
5660 factor = 4;
5661 else
5662 factor = 1;
5663 if ( md->model_flags & MD_16BIT_TRANSFER )
5664 factor = 256;
5665
5666 outfile = fopen("shading_buf_w.pnm", "w");
5667 fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n",
5668 mi->geo_width / mi->calib_divisor, lines);
5669 for ( linenr=0; linenr < lines; linenr++ )
5670 {
5671 if (mi->data_format == MI_DATAFMT_LPLSEGREG)
5672 {
5673 DBG(1, "Output of shading buffer unsupported for"
5674 "Segreg Data format\n");
5675 break;
5676 }
5677
5678 for ( pixel=0;
5679 pixel < (uint16_t) (mi->geo_width / mi->calib_divisor);
5680 pixel++)
5681 {
5682 for ( color=0; color < 3; color++ )
5683 {
5684 switch( mi->data_format )
5685 {
5686 case MI_DATAFMT_LPLCONCAT:
5687 if ( md->shading_depth > 8)
5688 img_val = *((uint16_t *) ms->shading_image
5689 + linenr * ( ms->bpl / ms->lut_entry_size )
5690 + mi->color_sequence[color]
5691 * ( ms->bpl / ms->lut_entry_size / 3 )
5692 + pixel);
5693 else
5694 img_val = *((uint8_t *) ms->shading_image
5695 + linenr * ( ms->bpl / ms->lut_entry_size )
5696 + mi->color_sequence[color]
5697 * ( ms->bpl / ms->lut_entry_size / 3 )
5698 + pixel);
5699
5700 break;
5701 case MI_DATAFMT_CHUNKY:
5702 case MI_DATAFMT_9800:
5703 img_val = *((uint16_t *)ms->shading_image
5704 + linenr * 3 * ( mi->geo_width
5705 / mi->calib_divisor )
5706 + 3 * pixel
5707 + mi->color_sequence[color]);
5708 break;
5709 }
5710 img_val /= factor;
5711 img_val_out = (unsigned char)img_val;
5712 fputc(img_val_out, outfile);
5713 }
5714 }
5715 }
5716 fclose(outfile);
5717
5718 return;
5719 }
5720
5721 static void
write_shading_pnm(Microtek2_Scanner * ms)5722 write_shading_pnm(Microtek2_Scanner *ms)
5723 {
5724 FILE *outfile_w = NULL, *outfile_d = NULL;
5725 int pixel, color, line, offset, num_shading_pixels, output_height;
5726 uint16_t img_val, factor;
5727
5728 Microtek2_Device *md;
5729 Microtek2_Info *mi;
5730
5731 output_height = 180;
5732 md = ms->dev;
5733 mi = &md->info[md->scan_source];
5734
5735 DBG(30, "write_shading_pnm: ms=%p\n", (void *) ms);
5736
5737 if ( mi->depth & MI_HASDEPTH_16 )
5738 factor = 256;
5739 else if ( mi->depth & MI_HASDEPTH_14 )
5740 factor = 64;
5741 else if ( mi->depth & MI_HASDEPTH_12 )
5742 factor = 16;
5743 else if ( mi->depth & MI_HASDEPTH_10 )
5744 factor = 4;
5745 else
5746 factor = 1;
5747 if ( md->model_flags & MD_16BIT_TRANSFER )
5748 factor = 256;
5749
5750 if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5751 num_shading_pixels = ms->n_control_bytes * 8;
5752 else
5753 num_shading_pixels = mi->geo_width / mi->calib_divisor;
5754 if ( md->shading_table_w != NULL )
5755 {
5756 outfile_w = fopen("microtek2_shading_w.pnm", "w");
5757 fprintf(outfile_w, "P6\n#imagedata\n%d %d\n255\n",
5758 num_shading_pixels, output_height);
5759 }
5760 if ( md->shading_table_d != NULL )
5761 {
5762 outfile_d = fopen("microtek2_shading_d.pnm", "w");
5763 fprintf(outfile_d, "P6\n#imagedata\n%d %d\n255\n",
5764 num_shading_pixels, output_height);
5765 }
5766 for ( line=0; line < output_height; ++line )
5767 {
5768 for ( pixel=0; pixel < num_shading_pixels ; ++pixel)
5769 {
5770 for ( color=0; color < 3; ++color )
5771 {
5772 offset = mi->color_sequence[color]
5773 * num_shading_pixels
5774 + pixel;
5775 if ( md->shading_table_w != NULL )
5776 {
5777 if ( ms->lut_entry_size == 2 )
5778 {
5779 img_val = *((uint16_t *) md->shading_table_w + offset );
5780 img_val /= factor;
5781 }
5782 else
5783 img_val = *((uint8_t *) md->shading_table_w + offset );
5784 fputc((unsigned char)img_val, outfile_w);
5785 }
5786
5787 if ( md->shading_table_d != NULL )
5788 {
5789 if ( ms->lut_entry_size == 2 )
5790 {
5791 img_val = *((uint16_t *) md->shading_table_d + offset );
5792 img_val /= factor;
5793 }
5794 else
5795 img_val = *((uint8_t *) md->shading_table_d + offset );
5796 fputc((unsigned char)img_val, outfile_d);
5797 }
5798 }
5799 }
5800 }
5801 if ( md->shading_table_w != NULL )
5802 fclose(outfile_w);
5803 if ( md->shading_table_d != NULL )
5804 fclose(outfile_d);
5805
5806 return;
5807 }
5808
5809 static void
write_cshading_pnm(Microtek2_Scanner * ms)5810 write_cshading_pnm(Microtek2_Scanner *ms)
5811 {
5812 FILE *outfile;
5813 Microtek2_Device *md;
5814 Microtek2_Info *mi;
5815 int pixel, color, line, offset, img_val, img_height=30, factor;
5816
5817 md = ms->dev;
5818 mi = &md->info[md->scan_source];
5819
5820 if ( mi->depth & MI_HASDEPTH_16 )
5821 factor = 256;
5822 else if ( mi->depth & MI_HASDEPTH_14 )
5823 factor = 64;
5824 else if ( mi->depth & MI_HASDEPTH_12 )
5825 factor = 16;
5826 else if ( mi->depth & MI_HASDEPTH_10 )
5827 factor = 4;
5828 else
5829 factor = 1;
5830 if ( md->model_flags & MD_16BIT_TRANSFER )
5831 factor = 256;
5832
5833 outfile = fopen("microtek2_cshading_w.pnm", "w");
5834 if ( ms->mode == MS_MODE_COLOR )
5835 fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n", ms->ppl, img_height);
5836 else
5837 fprintf(outfile, "P5\n#imagedata\n%d %d\n255\n", ms->ppl, img_height);
5838
5839 for ( line=0; line < img_height; ++line )
5840 {
5841 for ( pixel=0; pixel < (int)ms->ppl; ++pixel)
5842 {
5843 for ( color=0; color < 3; ++color )
5844 {
5845 offset = color * (int)ms->ppl + pixel;
5846 if ( ms->lut_entry_size == 1 )
5847 img_val = (int) *((uint8_t *)ms->condensed_shading_w + offset);
5848 else
5849 {
5850 img_val = (int) *((uint16_t *)ms->condensed_shading_w
5851 + offset);
5852 img_val /= factor;
5853 }
5854 fputc((unsigned char)img_val, outfile);
5855 if ( ms->mode == MS_MODE_GRAY )
5856 break;
5857 }
5858 }
5859 }
5860 fclose(outfile);
5861
5862 return;
5863 }
5864
5865
5866
5867 /*---------- condense_shading() ----------------------------------------------*/
5868
5869 static SANE_Status
condense_shading(Microtek2_Scanner * ms)5870 condense_shading(Microtek2_Scanner *ms)
5871 {
5872 /* This function extracts the relevant shading pixels from */
5873 /* the shading image according to the 1's in the result of */
5874 /* 'read control bits', and stores them in a memory block. */
5875 /* We will then have as many shading pixels as there are */
5876 /* pixels per line. The order of the pixels in the condensed */
5877 /* shading data block will always be left to right. The color */
5878 /* sequence remains unchanged. */
5879
5880 Microtek2_Device *md;
5881 Microtek2_Info *mi;
5882 uint32_t byte;
5883 uint32_t cond_length; /* bytes per condensed shading line */
5884 int color, count, lfd_bit;
5885 int shad_bplc, shad_pixels; /* bytes per line & color in shading image */
5886 int bit, flag;
5887 uint32_t sh_offset, csh_offset;
5888 int gray_filter_color = 1; /* which color of the shading is taken for gray*/
5889
5890 md = ms->dev;
5891 mi = &md->info[md->scan_source];
5892
5893 DBG(30, "condense_shading: ms=%p, ppl=%d\n", (void *) ms, ms->ppl);
5894 if ( md->shading_table_w == NULL )
5895 {
5896 DBG(1, "condense shading: no shading table found, skip shading\n");
5897 return SANE_STATUS_GOOD;
5898 }
5899
5900 get_lut_size( mi, &ms->lut_size, &ms->lut_entry_size );
5901
5902 if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5903 {
5904 shad_pixels = ms->n_control_bytes * 8;
5905 gray_filter_color = 0; /* 336CX reads only one shading in gray mode*/
5906 }
5907 else
5908 shad_pixels = mi->geo_width;
5909
5910 shad_bplc = shad_pixels * ms->lut_entry_size;
5911
5912 if ( md_dump >= 3 )
5913 {
5914 dump_area2(md->shading_table_w, shad_bplc * 3, "shading_table_w");
5915 if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5916 write_shading_pnm(ms);
5917 }
5918
5919 cond_length = ms->bpl * ms->lut_entry_size;
5920
5921 if ( ms->condensed_shading_w )
5922 {
5923 free((void*) ms->condensed_shading_w );
5924 ms->condensed_shading_w = NULL;
5925 }
5926 ms->condensed_shading_w = (uint8_t *)malloc(cond_length);
5927 DBG(100, "condense_shading: ms->condensed_shading_w=%p,"
5928 "malloc'd %d bytes\n",
5929 (void *) ms->condensed_shading_w, cond_length);
5930 if ( ms->condensed_shading_w == NULL )
5931 {
5932 DBG(1, "condense_shading: malloc for white table failed\n");
5933 return SANE_STATUS_NO_MEM;
5934 }
5935
5936 if ( md->shading_table_d != NULL )
5937 {
5938 if ( md_dump >= 3 )
5939 dump_area2(md->shading_table_d, shad_bplc * 3,
5940 "shading_table_d");
5941
5942 if ( ms->condensed_shading_d )
5943 {
5944 free((void*) ms->condensed_shading_d );
5945 ms->condensed_shading_d = NULL;
5946 }
5947 ms->condensed_shading_d = (uint8_t *)malloc(cond_length);
5948 DBG(100, "condense_shading: ms->condensed_shading_d=%p,"
5949 " malloc'd %d bytes\n",
5950 (void *) ms->condensed_shading_d, cond_length);
5951 if ( ms->condensed_shading_d == NULL )
5952 {
5953 DBG(1, "condense_shading: malloc for dark table failed\n");
5954 return SANE_STATUS_NO_MEM;
5955 }
5956 }
5957
5958 DBG(128, "controlbit offset=%d\n", md->controlbit_offset);
5959
5960 count = 0;
5961
5962 for (lfd_bit = 0; ( lfd_bit < mi->geo_width ) && ( count < (int)ms->ppl );
5963 ++lfd_bit)
5964 {
5965 byte = ( lfd_bit + md->controlbit_offset ) / 8;
5966 bit = ( lfd_bit + md->controlbit_offset ) % 8;
5967
5968 if ( mi->direction & MI_DATSEQ_RTOL )
5969 flag = ((ms->control_bytes[byte] >> bit) & 0x01);
5970 else
5971 flag = ((ms->control_bytes[byte] >> (7 - bit)) & 0x01);
5972
5973 if ( flag == 1 ) /* flag==1 if byte's bit is set */
5974 {
5975 for ( color = 0; color < 3; ++color )
5976 {
5977 if ( ( ms->mode == MS_MODE_COLOR )
5978 || ( ( ms->mode == MS_MODE_GRAY )
5979 && ( color == gray_filter_color ) )
5980 || ( ( ms->mode == MS_MODE_LINEARTFAKE )
5981 && ( color == gray_filter_color ) )
5982 )
5983 {
5984 sh_offset = color * shad_pixels + lfd_bit;
5985 if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5986 sh_offset += md->controlbit_offset;
5987 if ( ms->mode == MS_MODE_COLOR )
5988 csh_offset = color * ms->ppl + count;
5989 else
5990 csh_offset = count;
5991
5992 if ( csh_offset > cond_length )
5993 {
5994 DBG(1, "condense_shading: wrong control bits data, " );
5995 DBG(1, "csh_offset (%d) > cond_length(%d)\n",
5996 csh_offset, cond_length );
5997 csh_offset = cond_length;
5998 }
5999
6000 if ( ms->lut_entry_size == 2 )
6001 {
6002 *((uint16_t *)ms->condensed_shading_w + csh_offset) =
6003 *((uint16_t *)md->shading_table_w
6004 + sh_offset);
6005 if ( ms->condensed_shading_d != NULL )
6006 *((uint16_t *)ms->condensed_shading_d + csh_offset) =
6007 *((uint16_t *)md->shading_table_d
6008 + sh_offset);
6009 }
6010 else
6011 {
6012 *((uint8_t *)ms->condensed_shading_w + csh_offset) =
6013 *((uint8_t *)md->shading_table_w
6014 + sh_offset);
6015 if ( ms->condensed_shading_d != NULL )
6016 *((uint8_t *)ms->condensed_shading_d + csh_offset) =
6017 *((uint8_t *)md->shading_table_d
6018 + sh_offset);
6019 }
6020 }
6021 }
6022 ++count;
6023 }
6024 }
6025
6026 if ( md_dump >= 3 )
6027 {
6028 dump_area2(ms->condensed_shading_w, cond_length, "condensed_shading_w");
6029 if ( ms->condensed_shading_d != NULL )
6030 dump_area2(ms->condensed_shading_d, cond_length,
6031 "condensed_shading_d");
6032
6033 write_cshading_pnm(ms);
6034 }
6035
6036 return SANE_STATUS_GOOD;
6037 }
6038
6039
6040 /*---------- read_shading_image() --------------------------------------------*/
6041
6042 static SANE_Status
read_shading_image(Microtek2_Scanner * ms)6043 read_shading_image(Microtek2_Scanner *ms)
6044 {
6045 SANE_Status status;
6046 Microtek2_Device *md;
6047 Microtek2_Info *mi;
6048 uint32_t lines;
6049 uint8_t *buf;
6050 int max_lines;
6051 int lines_to_read;
6052
6053 DBG(30, "read_shading_image: ms=%p\n", (void *) ms);
6054
6055 md = ms->dev;
6056 mi = &md->info[md->scan_source];
6057
6058
6059 if ( ! MI_WHITE_SHADING_ONLY(mi->shtrnsferequ)
6060 || ( md->model_flags & MD_PHANTOM_C6 ) )
6061
6062 /* Dark shading correction */
6063 /* ~~~~~~~~~~~~~~~~~~~~~~~ */
6064 {
6065 DBG(30, "read_shading_image: reading black data\n");
6066 md->status.ntrack |= MD_NTRACK_ON;
6067 md->status.ncalib &= ~MD_NCALIB_ON;
6068 md->status.flamp |= MD_FLAMP_ON;
6069 if ( md->model_flags & MD_PHANTOM_C6 )
6070 {
6071 md->status.stick |= MD_STICK_ON;
6072 md->status.reserved17 |= MD_RESERVED17_ON;
6073 }
6074
6075 get_calib_params(ms);
6076 if ( md->model_flags & MD_PHANTOM_C6 )
6077 ms->stay = 1;
6078
6079 status = scsi_send_system_status(md, ms->sfd);
6080 if ( status != SANE_STATUS_GOOD )
6081 return status;
6082
6083 status = scsi_set_window(ms, 1);
6084 if ( status != SANE_STATUS_GOOD )
6085 return status;
6086
6087 #ifdef TESTBACKEND
6088 status = scsi_read_sh_image_info(ms);
6089 #else
6090 status = scsi_read_image_info(ms);
6091 #endif
6092 if ( status != SANE_STATUS_GOOD )
6093 return status;
6094
6095 status = scsi_wait_for_image(ms);
6096 if ( status != SANE_STATUS_GOOD )
6097 return status;
6098
6099 status = scsi_read_system_status(md, ms->sfd);
6100 if ( status != SANE_STATUS_GOOD )
6101 return status;
6102
6103 md->status.flamp &= ~MD_FLAMP_ON;
6104
6105 status = scsi_send_system_status(md, ms->sfd);
6106 if ( status != SANE_STATUS_GOOD )
6107 return status;
6108
6109 ms->shading_image = malloc(ms->bpl * ms->src_remaining_lines);
6110 DBG(100, "read shading image: ms->shading_image=%p,"
6111 " malloc'd %d bytes\n",
6112 (void *) ms->shading_image,
6113 ms->bpl * ms->src_remaining_lines);
6114 if ( ms->shading_image == NULL )
6115 {
6116 DBG(1, "read_shading_image: malloc for buffer failed\n");
6117 return SANE_STATUS_NO_MEM;
6118 }
6119
6120 buf = ms->shading_image;
6121
6122 #ifdef TESTBACKEND
6123 max_lines = 5000000 / ms->bpl;
6124 #else
6125 max_lines = sanei_scsi_max_request_size / ms->bpl;
6126 #endif
6127 if ( max_lines == 0 )
6128 {
6129 DBG(1, "read_shading_image: buffer too small\n");
6130 return SANE_STATUS_IO_ERROR;
6131 }
6132 lines = ms->src_remaining_lines;
6133 while ( ms->src_remaining_lines > 0 )
6134 {
6135 lines_to_read = MIN(max_lines, ms->src_remaining_lines);
6136 ms->src_buffer_size = lines_to_read * ms->bpl;
6137 ms->transfer_length = ms->src_buffer_size;
6138 #ifdef TESTBACKEND
6139 status = scsi_read_sh_d_image(ms, buf);
6140 #else
6141 status = scsi_read_image(ms, buf, md->shading_depth>8 ? 2 : 1);
6142 #endif
6143 if ( status != SANE_STATUS_GOOD )
6144 {
6145 DBG(1, "read_shading_image: read image failed: '%s'\n",
6146 sane_strstatus(status));
6147 return status;
6148 }
6149
6150 ms->src_remaining_lines -= lines_to_read;
6151 buf += ms->src_buffer_size;
6152 }
6153
6154 status = prepare_shading_data(ms, lines, &md->shading_table_d);
6155 if ( status != SANE_STATUS_GOOD )
6156 return status;
6157
6158 /* send shading data to the device */
6159 /* Some models use "read_control bit", and the shading must be */
6160 /* applied by the backend later */
6161 if ( ! (md->model_flags & MD_READ_CONTROL_BIT) )
6162 {
6163 status = shading_function(ms, md->shading_table_d);
6164 if ( status != SANE_STATUS_GOOD )
6165 return status;
6166
6167 ms->word = ms->lut_entry_size == 2 ? 1 : 0;
6168 ms->current_color = MS_COLOR_ALL;
6169 status = scsi_send_shading(ms,
6170 md->shading_table_d,
6171 3 * ms->lut_entry_size
6172 * mi->geo_width / mi->calib_divisor,
6173 1);
6174 if ( status != SANE_STATUS_GOOD )
6175 return status;
6176 }
6177
6178 DBG(100, "free memory for ms->shading_image at %p\n",
6179 (void *) ms->shading_image);
6180 free((void *) ms->shading_image);
6181 ms->shading_image = NULL;
6182 }
6183
6184 /* white shading correction */
6185 /* ~~~~~~~~~~~~~~~~~~~~~~~~ */
6186 DBG(30, "read_shading_image: reading white data\n");
6187
6188 /* According to the doc NCalib must be set for white shading data */
6189 /* if we have a black and a white shading correction and must be */
6190 /* cleared if we have only a white shading collection */
6191 if ( ! MI_WHITE_SHADING_ONLY(mi->shtrnsferequ)
6192 || ( md->model_flags & MD_PHANTOM_C6 ) )
6193 md->status.ncalib |= MD_NCALIB_ON;
6194 else
6195 md->status.ncalib &= ~MD_NCALIB_ON;
6196
6197 md->status.flamp |= MD_FLAMP_ON;
6198 /* md->status.tlamp &= ~MD_TLAMP_ON; */
6199 md->status.ntrack |= MD_NTRACK_ON;
6200
6201 if ( md->model_flags & MD_PHANTOM_C6 )
6202 {
6203 md->status.stick &= ~MD_STICK_ON;
6204 md->status.reserved17 |= MD_RESERVED17_ON;
6205 }
6206
6207 get_calib_params(ms);
6208
6209 #ifdef NO_PHANTOMTYPE_SHADING
6210 /* md->status.stick &= ~MD_STICK_ON; */
6211 /* md->status.ncalib &= ~MD_NCALIB_ON; */
6212 /* md->status.reserved17 &= ~MD_RESERVED17_ON; */
6213 ms->rawdat = 0;
6214 #endif
6215
6216 status = scsi_send_system_status(md, ms->sfd);
6217 if ( status != SANE_STATUS_GOOD )
6218 return status;
6219
6220 status = scsi_set_window(ms, 1);
6221 if ( status != SANE_STATUS_GOOD )
6222 return status;
6223
6224 #ifdef TESTBACKEND
6225 status = scsi_read_sh_image_info(ms);
6226 #else
6227 status = scsi_read_image_info(ms);
6228 #endif
6229 if ( status != SANE_STATUS_GOOD )
6230 return status;
6231
6232 status = scsi_wait_for_image(ms);
6233 if ( status != SANE_STATUS_GOOD )
6234 return status;
6235
6236 #ifdef NO_PHANTOMTYPE_SHADING
6237 if ( !( md->model_flags & MD_READ_CONTROL_BIT ) )
6238 {
6239 #endif
6240 status = scsi_read_system_status(md, ms->sfd);
6241 if ( status != SANE_STATUS_GOOD )
6242 return status;
6243 #ifdef NO_PHANTOMTYPE_SHADING
6244 }
6245 #endif
6246
6247 #ifdef NO_PHANTOMTYPE_SHADING
6248 if ( mi->model_code == 0x94 )
6249 status = scsi_read_control_bits(ms);
6250 #endif
6251
6252 ms->shading_image = malloc(ms->bpl * ms->src_remaining_lines);
6253 DBG(100, "read shading image: ms->shading_image=%p, malloc'd %d bytes\n",
6254 (void *) ms->shading_image, ms->bpl * ms->src_remaining_lines);
6255 if ( ms->shading_image == NULL )
6256 {
6257 DBG(1, "read_shading_image: malloc for buffer failed\n");
6258 return SANE_STATUS_NO_MEM;
6259 }
6260
6261 buf = ms->shading_image;
6262 #ifdef TESTBACKEND
6263 max_lines = 5000000 / ms->bpl;
6264 #else
6265 max_lines = sanei_scsi_max_request_size / ms->bpl;
6266 #endif
6267 if ( max_lines == 0 )
6268 {
6269 DBG(1, "read_shading_image: buffer too small\n");
6270 return SANE_STATUS_IO_ERROR;
6271 }
6272 lines = ms->src_remaining_lines;
6273 while ( ms->src_remaining_lines > 0 )
6274 {
6275 lines_to_read = MIN(max_lines, ms->src_remaining_lines);
6276 ms->src_buffer_size = lines_to_read * ms->bpl;
6277 ms->transfer_length = ms->src_buffer_size;
6278
6279 #ifdef TESTBACKEND
6280 status = scsi_read_sh_w_image(ms, buf);
6281 #else
6282 status = scsi_read_image(ms, buf, md->shading_depth>8 ? 2 : 1);
6283 #endif
6284 if ( status != SANE_STATUS_GOOD )
6285 return status;
6286
6287 ms->src_remaining_lines -= lines_to_read;
6288 buf += ms->src_buffer_size;
6289 }
6290
6291 status = prepare_shading_data(ms, lines, &md->shading_table_w);
6292 if ( status != SANE_STATUS_GOOD )
6293 return status;
6294
6295 if ( md_dump >= 3 )
6296 {
6297 write_shading_buf_pnm(ms, lines);
6298 write_shading_pnm(ms);
6299 }
6300
6301 /* send shading data to the device */
6302 /* Some models use "read_control bit", and the shading must be */
6303 /* applied by the backend later */
6304 if ( ! (md->model_flags & MD_READ_CONTROL_BIT) )
6305 {
6306 status = shading_function(ms, md->shading_table_w);
6307 if ( status != SANE_STATUS_GOOD )
6308 return status;
6309
6310 ms->word = ms->lut_entry_size == 2 ? 1 : 0;
6311 ms->current_color = MS_COLOR_ALL;
6312 status = scsi_send_shading(ms,
6313 md->shading_table_w,
6314 3 * ms->lut_entry_size
6315 * mi->geo_width / mi->calib_divisor,
6316 0);
6317 if ( status != SANE_STATUS_GOOD )
6318 return status;
6319 }
6320
6321 ms->rawdat = 0;
6322 ms->stay = 0;
6323 md->status.ncalib |= MD_NCALIB_ON;
6324
6325 if ( md->model_flags & MD_PHANTOM_C6 )
6326 {
6327 md->status.stick &= ~MD_STICK_ON;
6328 md->status.reserved17 &= ~MD_RESERVED17_ON;
6329 }
6330
6331 #ifdef NO_PHANTOMTYPE_SHADING
6332 if (mi->model_code == 0x94)
6333 md->status.ncalib &= ~MD_NCALIB_ON;
6334 #endif
6335
6336 status = scsi_send_system_status(md, ms->sfd);
6337 if ( status != SANE_STATUS_GOOD )
6338 return status;
6339
6340 DBG(100, "free memory for ms->shading_image at %p\n",
6341 (void *) ms->shading_image);
6342 free((void *) ms->shading_image);
6343 ms->shading_image = NULL;
6344
6345 return SANE_STATUS_GOOD;
6346
6347 }
6348
6349 /*---------- prepare_shading_data() ------------------------------------------*/
6350
6351 static SANE_Status
prepare_shading_data(Microtek2_Scanner * ms,uint32_t lines,uint8_t ** data)6352 prepare_shading_data(Microtek2_Scanner *ms, uint32_t lines, uint8_t **data)
6353 {
6354 /* This function calculates one line of black or white shading data */
6355 /* from the shading image. At the end we have one line. The */
6356 /* color sequence is unchanged. */
6357
6358 #define MICROTEK2_CALIB_USE_MEDIAN
6359
6360 Microtek2_Device *md;
6361 Microtek2_Info *mi;
6362 uint32_t length,line;
6363 int color, i;
6364 SANE_Status status;
6365
6366 #ifdef MICROTEK2_CALIB_USE_MEDIAN
6367 uint16_t *sortbuf, value;
6368 #else
6369 uint32_t value;
6370 #endif
6371
6372 DBG(30, "prepare_shading_data: ms=%p, lines=%d, *data=%p\n",
6373 (void *) ms, lines, (void *) *data);
6374
6375 md = ms->dev;
6376 mi = &md->info[md->scan_source];
6377 status = SANE_STATUS_GOOD;
6378
6379 get_lut_size(mi, &ms->lut_size, &ms->lut_entry_size);
6380 length = 3 * ms->lut_entry_size * mi->geo_width / mi->calib_divisor;
6381
6382 if ( *data == NULL )
6383 {
6384 *data = (uint8_t *) malloc(length);
6385 DBG(100, "prepare_shading_data: malloc'd %d bytes at %p\n",
6386 length, (void *) *data);
6387 if ( *data == NULL )
6388 {
6389 DBG(1, "prepare_shading_data: malloc for shading table failed\n");
6390 return SANE_STATUS_NO_MEM;
6391 }
6392 }
6393
6394 #ifdef MICROTEK2_CALIB_USE_MEDIAN
6395 sortbuf = malloc( lines * ms->lut_entry_size );
6396 DBG(100, "prepare_shading_data: sortbuf= %p, malloc'd %d Bytes\n",
6397 (void *) sortbuf, lines * ms->lut_entry_size);
6398 if ( sortbuf == NULL )
6399 {
6400 DBG(1, "prepare_shading_data: malloc for sort buffer failed\n");
6401 return SANE_STATUS_NO_MEM;
6402 }
6403 #endif
6404
6405 switch( mi->data_format )
6406 {
6407 case MI_DATAFMT_LPLCONCAT:
6408 if ( ms->lut_entry_size == 1 )
6409 {
6410 DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n");
6411 return SANE_STATUS_UNSUPPORTED;
6412 }
6413 for ( color = 0; color < 3; color++ )
6414 {
6415 for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6416 {
6417 value = 0;
6418 for ( line = 0; line < lines; line++ )
6419 #ifndef MICROTEK2_CALIB_USE_MEDIAN
6420 /* average the shading lines to get the shading data */
6421 value += *((uint16_t *) ms->shading_image
6422 + line * ( ms->bpl / ms->lut_entry_size )
6423 + color * ( ms->bpl / ms->lut_entry_size / 3 )
6424 + i);
6425 value /= lines;
6426 *((uint16_t *) *data
6427 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6428 (uint16_t) MIN(0xffff, value);
6429 #else
6430 /* use a median filter to get the shading data -- should be better */
6431 *(sortbuf + line ) =
6432 *((uint16_t *) ms->shading_image
6433 + line * ( ms->bpl / ms->lut_entry_size )
6434 + color * ( ms->bpl / ms->lut_entry_size / 3 )
6435 + i);
6436 qsort(sortbuf, lines, sizeof(uint16_t),
6437 (qsortfunc)compare_func_16);
6438 value = *(sortbuf + ( lines - 1 ) / 2 );
6439 *((uint16_t *) *data
6440 + color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6441 #endif
6442 }
6443 }
6444 break;
6445
6446 case MI_DATAFMT_CHUNKY:
6447 case MI_DATAFMT_9800:
6448 if ( ms->lut_entry_size == 1 )
6449 {
6450 DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n");
6451 return SANE_STATUS_UNSUPPORTED;
6452 }
6453 for ( color = 0; color < 3; color++ )
6454 {
6455 for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6456 {
6457 value = 0;
6458 for ( line = 0; line < lines; line++ )
6459 #ifndef MICROTEK2_CALIB_USE_MEDIAN
6460 /* average the shading lines to get the shading data */
6461 value += *((uint16_t *) ms->shading_image
6462 + line * 3 * mi->geo_width / mi->calib_divisor
6463 + 3 * i
6464 + color);
6465
6466 value /= lines;
6467 *((uint16_t *) *data
6468 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6469 (uint16_t) MIN(0xffff, value);
6470 #else
6471 /* use a median filter to get the shading data -- should be better */
6472 *(sortbuf + line ) =
6473 *((uint16_t *) ms->shading_image
6474 + line * 3 * mi->geo_width / mi->calib_divisor
6475 + 3 * i
6476 + color);
6477 qsort(sortbuf, lines, sizeof(uint16_t),
6478 (qsortfunc)compare_func_16);
6479 value = *(sortbuf + ( lines - 1 ) / 2 );
6480 *((uint16_t *) *data
6481 + color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6482 #endif
6483 }
6484 }
6485 break;
6486
6487 case MI_DATAFMT_LPLSEGREG:
6488 for ( color = 0; color < 3; color++ )
6489 {
6490 for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6491 {
6492 value = 0;
6493 if ( ms->lut_entry_size == 1 )
6494 {
6495 for ( line = 0; line < lines; line++ )
6496 value += *((uint8_t *) ms->shading_image
6497 + line * 3 * mi->geo_width / mi->calib_divisor
6498 + 3 * i
6499 + color);
6500
6501 value /= lines;
6502 *((uint8_t *) *data
6503 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6504 (uint8_t) MIN(0xff, value);
6505
6506 }
6507 else
6508 {
6509 for ( line = 0; line < lines; line++ )
6510 value += *((uint16_t *) ms->shading_image
6511 + line * 3 * mi->geo_width / mi->calib_divisor
6512 + 3 * i
6513 + color);
6514
6515 value /= lines;
6516 #ifndef MICROTEK2_CALIB_USE_MEDIAN
6517 *((uint16_t *) *data
6518 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6519 (uint16_t) MIN(0xffff, value);
6520 #else
6521 *((uint16_t *) *data
6522 + color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6523 #endif
6524 }
6525
6526 }
6527 }
6528 break;
6529
6530 default:
6531 DBG(1, "prepare_shading_data: Unsupported data format 0x%02x\n",
6532 mi->data_format);
6533 status = SANE_STATUS_UNSUPPORTED;
6534 }
6535
6536 #ifdef MICROTEK2_CALIB_USE_MEDIAN
6537 DBG(100, "prepare_shading_data: free sortbuf at %p\n", (void *) sortbuf);
6538 free(sortbuf);
6539 sortbuf = NULL;
6540 #endif
6541 return status;
6542 }
6543
6544
6545 /*---------- read_cx_shading() -----------------------------------------------*/
6546
6547 static SANE_Status
read_cx_shading(Microtek2_Scanner * ms)6548 read_cx_shading(Microtek2_Scanner *ms)
6549 {
6550 SANE_Status status;
6551 Microtek2_Device *md;
6552 md = ms->dev;
6553
6554 DBG(30, "read_cx_shading: ms=%p\n",(void *) ms);
6555
6556 md->shading_table_contents = ms->mode;
6557
6558 if ( ms->mode == MS_MODE_COLOR )
6559 ms->current_color = MS_COLOR_ALL;
6560 else
6561 ms->current_color = MS_COLOR_GREEN; /* for grayscale */
6562
6563 ms->word = 1;
6564 ms->dark = 0;
6565
6566 status = read_cx_shading_image(ms);
6567 if ( status != SANE_STATUS_GOOD )
6568 goto cleanup;
6569
6570 ms->word = 0; /* the Windows driver reads dark shading with word=0 */
6571 ms->dark = 1;
6572 status = read_cx_shading_image(ms);
6573 if ( status != SANE_STATUS_GOOD )
6574 goto cleanup;
6575
6576 return SANE_STATUS_GOOD;
6577
6578 cleanup:
6579 cleanup_scanner(ms);
6580 return status;
6581 }
6582
6583
6584 /*---------- read_cx_shading_image() -----------------------------------------*/
6585
6586 static SANE_Status
read_cx_shading_image(Microtek2_Scanner * ms)6587 read_cx_shading_image(Microtek2_Scanner *ms)
6588 {
6589 SANE_Status status;
6590 Microtek2_Device *md;
6591 uint32_t shading_bytes, linesize, buffer_size;
6592 uint8_t *buf;
6593 int max_lines, lines_to_read, remaining_lines;
6594
6595 md = ms->dev;
6596
6597 shading_bytes = ms->n_control_bytes * 8 * md->shading_length;
6598 if ( ms->current_color == MS_COLOR_ALL )
6599 shading_bytes *= 3;
6600 if ( ms->word == 1 )
6601 shading_bytes *= 2;
6602
6603 if ( ms->shading_image )
6604 {
6605 free((void *) ms->shading_image);
6606 ms->shading_image = NULL;
6607 }
6608 ms->shading_image = malloc(shading_bytes);
6609 DBG(100, "read_cx_shading: ms->shading_image=%p, malloc'd %d bytes\n",
6610 (void *) ms->shading_image, shading_bytes);
6611 if ( ms->shading_image == NULL )
6612 {
6613 DBG(1, "read_cx_shading: malloc for cx_shading buffer failed\n");
6614 return SANE_STATUS_NO_MEM;
6615 }
6616
6617 buf = ms->shading_image;
6618
6619 DBG(30, "read_cx_shading_image: ms=%p, shading_bytes=%d\n",
6620 (void *) ms, shading_bytes);
6621
6622 linesize = shading_bytes / md->shading_length;
6623 #ifdef TESTBACKEND
6624 max_lines = 5000000 / linesize;
6625 #else
6626 max_lines = sanei_scsi_max_request_size / linesize;
6627 #endif
6628 /* the following part is like in "read_shading_image" */
6629 remaining_lines = md->shading_length;
6630 while ( remaining_lines > 0 )
6631 {
6632 lines_to_read = MIN(max_lines, remaining_lines);
6633 buffer_size = lines_to_read * linesize;
6634
6635 status = scsi_read_shading(ms, buf, buffer_size);
6636 if ( status != SANE_STATUS_GOOD )
6637 {
6638 DBG(1, "read_cx_shading: '%s'\n", sane_strstatus(status));
6639 return status;
6640 }
6641 remaining_lines -= lines_to_read;
6642 buf += buffer_size;
6643 }
6644
6645 status = calc_cx_shading_line(ms);
6646 if ( status != SANE_STATUS_GOOD )
6647 {
6648 DBG(1, "read_cx_shading: '%s'\n", sane_strstatus(status));
6649 return status;
6650 }
6651
6652 if ( ms->shading_image )
6653 {
6654 DBG(100, "free memory for ms->shading_image at %p\n",
6655 (void *) ms->shading_image);
6656 free((void *) ms->shading_image);
6657 ms->shading_image = NULL;
6658 }
6659
6660 return status;
6661 }
6662
6663 /*---------- calc_cx_shading_line() ------------------------------------------*/
6664 /* calculates the mean value of the shading lines and stores one line of */
6665 /* 8-bit shading data. Scanning direction + color sequence remain as they are */
6666 /* ToDo: more than 8-bit data */
6667
6668 static SANE_Status
calc_cx_shading_line(Microtek2_Scanner * ms)6669 calc_cx_shading_line(Microtek2_Scanner *ms)
6670 {
6671 Microtek2_Device *md;
6672 SANE_Status status;
6673 uint8_t *current_byte, *buf, *shading_table_pointer;
6674 uint8_t color, factor;
6675 uint32_t shading_line_pixels, shading_line_bytes,
6676 shading_data_bytes, line, i, accu, color_offset;
6677 uint16_t *sortbuf, value;
6678
6679 md = ms->dev;
6680 status = SANE_STATUS_GOOD;
6681
6682 sortbuf = malloc( md->shading_length * sizeof(float) );
6683 DBG(100, "calc_cx_shading: sortbuf= %p, malloc'd %lu Bytes\n",
6684 (void *) sortbuf, (u_long) (md->shading_length * sizeof(float)));
6685 if ( sortbuf == NULL )
6686 {
6687 DBG(1, "calc_cx_shading: malloc for sort buffer failed\n");
6688 return SANE_STATUS_NO_MEM;
6689 }
6690
6691 buf = ms->shading_image;
6692 shading_line_pixels = ms->n_control_bytes * 8; /* = 2560 for 330CX */
6693 shading_line_bytes = shading_line_pixels; /* grayscale */
6694 if ( ms->mode == MS_MODE_COLOR ) /* color */
6695 shading_line_bytes *= 3;
6696 shading_data_bytes = shading_line_bytes; /* 8-bit color depth */
6697 if (ms->word == 1) /* > 8-bit color depth */
6698 shading_data_bytes *= 2;
6699 factor = 4; /* shading bit depth = 10bit; shading line bit depth = 8bit */
6700
6701 if (ms->dark == 0) /* white shading data */
6702 {
6703 if ( md->shading_table_w )
6704 free( (void *)md->shading_table_w );
6705 md->shading_table_w = (uint8_t *) malloc(shading_line_bytes);
6706 DBG(100, "calc_cx_shading: md->shading_table_w=%p, malloc'd %d bytes\n",
6707 (void *) md->shading_table_w, shading_line_bytes);
6708 if ( md->shading_table_w == NULL )
6709 {
6710 DBG(100, "calc_cx_shading: malloc for white shadingtable failed\n");
6711 status = SANE_STATUS_NO_MEM;
6712 cleanup_scanner(ms);
6713 }
6714
6715 shading_table_pointer = md->shading_table_w;
6716 }
6717
6718 else /* dark shading data */
6719 {
6720 if ( md->shading_table_d )
6721 free( (void *)md->shading_table_d);
6722 md->shading_table_d = (uint8_t *) malloc(shading_line_bytes);
6723 DBG(100, "calc_cx_shading: md->shading_table_d=%p, malloc'd %d bytes\n",
6724 (void *) md->shading_table_d, shading_line_bytes);
6725
6726 if ( md->shading_table_d == NULL )
6727 {
6728 DBG(1, "calc_cx_shading: malloc for dark shading table failed\n");
6729 status = SANE_STATUS_NO_MEM;
6730 cleanup_scanner(ms);
6731 }
6732
6733 shading_table_pointer = md->shading_table_d;
6734 }
6735
6736 DBG(30, "calc_cx_shading_line: ms=%p\n"
6737 "md->shading_table_w=%p\n"
6738 "md->shading_table_d=%p\n"
6739 "shading_line_bytes=%d\n"
6740 "shading_line_pixels=%d\n"
6741 "shading_table_pointer=%p\n",
6742 (void *) ms, (void *) md->shading_table_w,
6743 (void *) md->shading_table_d, shading_line_bytes,
6744 shading_line_pixels, (void *) shading_table_pointer);
6745
6746 /* calculating the median pixel values over the shading lines */
6747 /* and write them to the shading table */
6748 for (color = 0; color < 3; color++)
6749 {
6750 color_offset = color * shading_line_pixels;
6751 if ( ms->word == 1 )
6752 color_offset *=2;
6753
6754 for (i = 0; i < shading_line_pixels; i++)
6755 {
6756 value = 0;
6757 for (line = 0; line < md->shading_length; line++)
6758 {
6759 current_byte = buf + ( line * shading_data_bytes )
6760 + color_offset + i;
6761 accu = *current_byte;
6762
6763 /* word shading data: the lower bytes per line and color are */
6764 /* transferred first in one block and then the high bytes */
6765 /* in one block */
6766 /* the dark shading data is also 10 bit, but only the */
6767 /* low byte is transferred (ms->word = 0) */
6768 if ( ms->word == 1 )
6769 {
6770 current_byte = buf + ( line * shading_data_bytes )
6771 + color_offset + shading_line_pixels + i;
6772 accu += ( *current_byte * 256 );
6773 }
6774 *( sortbuf + line ) = accu;
6775 }
6776 /* this is the Median filter: sort the values ascending and take the middlest */
6777 qsort(sortbuf, md->shading_length, sizeof(float),
6778 (qsortfunc)compare_func_16);
6779 value = *( sortbuf + ( md->shading_length - 1 ) / 2 );
6780 *shading_table_pointer = (uint8_t) (value / factor);
6781 shading_table_pointer++;
6782 }
6783 if ( ms->mode != MS_MODE_COLOR )
6784 break;
6785 }
6786 return status;
6787 }
6788
6789
6790
6791 /*---------- get_lut_size() --------------------------------------------------*/
6792
6793 static SANE_Status
get_lut_size(Microtek2_Info * mi,int * max_lut_size,int * lut_entry_size)6794 get_lut_size(Microtek2_Info *mi, int *max_lut_size, int *lut_entry_size)
6795 {
6796 /* returns the maximum lookup table size. A device might indicate */
6797 /* several lookup table sizes. */
6798
6799 DBG(30, "get_lut_size: mi=%p\n", (void *) mi);
6800
6801 *max_lut_size = 0;
6802 *lut_entry_size = 0;
6803
6804 /* Normally this function is used for both gamma and shading tables */
6805 /* If, however, the device indicates, that it does not support */
6806 /* lookup tables, we set these values as if the device has a maximum */
6807 /* bitdepth of 12, and these values are only used to determine the */
6808 /* size of the shading table */
6809 if ( MI_LUTCAP_NONE(mi->lut_cap) )
6810 {
6811 *max_lut_size = 4096;
6812 *lut_entry_size = 2;
6813 }
6814
6815 if ( mi->lut_cap & MI_LUTCAP_256B )
6816 {
6817 *max_lut_size = 256;
6818 *lut_entry_size = 1;
6819 }
6820 if ( mi->lut_cap & MI_LUTCAP_1024B )
6821 {
6822 *max_lut_size = 1024;
6823 *lut_entry_size = 1;
6824 }
6825 if ( mi->lut_cap & MI_LUTCAP_1024W )
6826 {
6827 *max_lut_size = 1024;
6828 *lut_entry_size = 2;
6829 }
6830 if ( mi->lut_cap & MI_LUTCAP_4096B )
6831 {
6832 *max_lut_size = 4096;
6833 *lut_entry_size = 1;
6834 }
6835 if ( mi->lut_cap & MI_LUTCAP_4096W )
6836 {
6837 *max_lut_size = 4096;
6838 *lut_entry_size = 2;
6839 }
6840 if ( mi->lut_cap & MI_LUTCAP_64k_W )
6841 {
6842 *max_lut_size = 65536;
6843 *lut_entry_size = 2;
6844 }
6845 if ( mi->lut_cap & MI_LUTCAP_16k_W )
6846 {
6847 *max_lut_size = 16384;
6848 *lut_entry_size = 2;
6849 }
6850 DBG(30, "get_lut_size: mi=%p, lut_size=%d, lut_entry_size=%d\n",
6851 (void *) mi, *max_lut_size, *lut_entry_size);
6852 return SANE_STATUS_GOOD;
6853 }
6854
6855
6856 /*---------- calculate_gamma() -----------------------------------------------*/
6857
6858 static SANE_Status
calculate_gamma(Microtek2_Scanner * ms,uint8_t * pos,int color,char * mode)6859 calculate_gamma(Microtek2_Scanner *ms, uint8_t *pos, int color, char *mode)
6860 {
6861 Microtek2_Device *md;
6862 Microtek2_Info *mi;
6863 double exp;
6864 double mult;
6865 double steps;
6866 unsigned int val;
6867 int i;
6868 int factor; /* take into account the differences between the */
6869 /* possible values for the color and the number */
6870 /* of bits the scanner works with internally. */
6871 /* If depth == 1 handle this as if the maximum */
6872 /* depth was chosen */
6873
6874
6875 DBG(30, "calculate_gamma: ms=%p, pos=%p, color=%d, mode=%s\n",
6876 (void *) ms, (void *) pos, color, mode);
6877
6878 md = ms->dev;
6879 mi = &md->info[md->scan_source];
6880
6881 /* does this work everywhere ? */
6882 if ( md->model_flags & MD_NO_GAMMA )
6883 {
6884 factor = 1;
6885 mult = (double) (ms->lut_size - 1);
6886 }
6887 else
6888 {
6889 if ( mi->depth & MI_HASDEPTH_16 )
6890 {
6891 factor = ms->lut_size / 65536;
6892 mult = 65535.0;
6893 }
6894 else if ( mi->depth & MI_HASDEPTH_14 )
6895 {
6896 factor = ms->lut_size / 16384;
6897 mult = 16383.0;
6898 }
6899 else if ( mi->depth & MI_HASDEPTH_12 )
6900 {
6901 factor = ms->lut_size / 4096;
6902 mult = 4095.0;
6903 }
6904 else if ( mi->depth & MI_HASDEPTH_10 )
6905 {
6906 factor = ms->lut_size / 1024;
6907 mult = 1023.0;
6908 }
6909 else
6910 {
6911 factor = ms->lut_size / 256;
6912 mult = 255.0;
6913 }
6914 }
6915
6916 #if 0
6917 factor = ms->lut_size / (int) pow(2.0, (double) ms->depth);
6918 mult = pow(2.0, (double) ms->depth) - 1.0; /* depending on output size */
6919 #endif
6920
6921 steps = (double) (ms->lut_size - 1); /* depending on input size */
6922
6923 DBG(30, "calculate_gamma: factor=%d, mult =%f, steps=%f, mode=%s\n",
6924 factor, mult, steps, ms->val[OPT_GAMMA_MODE].s);
6925
6926
6927 if ( strcmp(mode, MD_GAMMAMODE_SCALAR) == 0 )
6928 {
6929 int option;
6930
6931 option = OPT_GAMMA_SCALAR;
6932 /* OPT_GAMMA_SCALAR_R follows OPT_GAMMA_SCALAR directly */
6933 if ( ms->val[OPT_GAMMA_BIND].w == SANE_TRUE )
6934 exp = 1.0 / SANE_UNFIX(ms->val[option].w);
6935 else
6936 exp = 1.0 / SANE_UNFIX(ms->val[option + color + 1].w);
6937
6938 for ( i = 0; i < ms->lut_size; i++ )
6939 {
6940 val = (unsigned int) (mult * pow((double) i / steps, exp) + .5);
6941
6942 if ( ms->lut_entry_size == 2 )
6943 *((uint16_t *) pos + i) = (uint16_t) val;
6944 else
6945 *((uint8_t *) pos + i) = (uint8_t) val;
6946 }
6947 }
6948 else if ( strcmp(mode, MD_GAMMAMODE_CUSTOM) == 0 )
6949 {
6950 int option;
6951 SANE_Int *src;
6952
6953 option = OPT_GAMMA_CUSTOM;
6954 if ( ms->val[OPT_GAMMA_BIND].w == SANE_TRUE )
6955 src = ms->val[option].wa;
6956 else
6957 src = ms->val[option + color + 1].wa;
6958
6959 for ( i = 0; i < ms->lut_size; i++ )
6960 {
6961 if ( ms->lut_entry_size == 2 )
6962 *((uint16_t *) pos + i) = (uint16_t) (src[i] / factor);
6963 else
6964 *((uint8_t *) pos + i) = (uint8_t) (src[i] / factor);
6965 }
6966 }
6967 else if ( strcmp(mode, MD_GAMMAMODE_LINEAR) == 0 )
6968 {
6969 for ( i = 0; i < ms->lut_size; i++ )
6970 {
6971 if ( ms->lut_entry_size == 2 )
6972 *((uint16_t *) pos + i) = (uint16_t) (i / factor);
6973 else
6974 *((uint8_t *) pos + i) = (uint8_t) (i / factor);
6975 }
6976 }
6977
6978 return SANE_STATUS_GOOD;
6979 }
6980
6981
6982 /*---------- shading_function() ----------------------------------------------*/
6983
6984 static SANE_Status
shading_function(Microtek2_Scanner * ms,uint8_t * data)6985 shading_function(Microtek2_Scanner *ms, uint8_t *data)
6986 {
6987 Microtek2_Device *md;
6988 Microtek2_Info *mi;
6989 uint32_t value;
6990 int color;
6991 int i;
6992
6993
6994 DBG(40, "shading_function: ms=%p, data=%p\n", (void *) ms, (void *) data);
6995
6996 md = ms->dev;
6997 mi = &md->info[md->scan_source];
6998 /* mi = &md->info[MD_SOURCE_FLATBED]; */
6999
7000 if ( ms->lut_entry_size == 1 )
7001 {
7002 DBG(1, "shading_function: wordsize = 1 unsupported\n");
7003 return SANE_STATUS_IO_ERROR;
7004 }
7005
7006 for ( color = 0; color < 3; color++ )
7007 {
7008 for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++)
7009 {
7010 value = *((uint16_t *) data
7011 + color * ( mi->geo_width / mi->calib_divisor ) + i);
7012 switch ( mi->shtrnsferequ )
7013 {
7014 case 0x00:
7015 /* output == input */
7016 break;
7017
7018 case 0x01:
7019 value = (ms->lut_size * ms->lut_size) / value;
7020 *((uint16_t *) data
7021 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7022 (uint16_t) MIN(0xffff, value);
7023 break;
7024
7025 case 0x11:
7026 value = (ms->lut_size * ms->lut_size)
7027 / (uint32_t) ( (double) value
7028 * ((double) mi->balance[color]
7029 / 255.0));
7030 *((uint16_t *) data
7031 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7032 (uint16_t) MIN(0xffff, value);
7033 break;
7034 case 0x15:
7035 value = (uint32_t) ( ( 1073741824 / (double) value )
7036 * ( (double) mi->balance[color]
7037 / 256.0) );
7038 value = MIN(value, (uint32_t)65535);
7039 *((uint16_t *) data
7040 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7041 (uint16_t) MIN(0xffff, value);
7042 break;
7043
7044 default:
7045 DBG(1, "Unsupported shading transfer function 0x%02x\n",
7046 mi->shtrnsferequ );
7047 break;
7048 }
7049 }
7050 }
7051
7052 return SANE_STATUS_GOOD;
7053 }
7054
7055
7056 /*---------- set_exposure() --------------------------------------------------*/
7057
7058 static void
set_exposure(Microtek2_Scanner * ms)7059 set_exposure(Microtek2_Scanner *ms)
7060 {
7061 /* This function manipulates the colors according to the exposure time */
7062 /* settings on models where they are ignored. Currently this seems to */
7063 /* be the case for all models with the data format chunky data. They */
7064 /* all have tables with two byte gamma output, so for now we ignore */
7065 /* gamma tables with one byte output */
7066
7067 Microtek2_Device *md;
7068 Microtek2_Info *mi;
7069 int color;
7070 int size;
7071 int depth;
7072 int maxval;
7073 int byte;
7074 uint32_t val32;
7075 uint8_t *from;
7076 uint8_t exposure;
7077 uint8_t exposure_rgb[3];
7078
7079
7080 DBG(30, "set_exposure: ms=%p\n", (void *) ms);
7081
7082 md = ms->dev;
7083 mi = &md->info[md->scan_source];
7084
7085 if ( ms->lut_entry_size == 1 )
7086 {
7087 DBG(1, "set_exposure: 1 byte gamma output tables currently ignored\n");
7088 return;
7089 }
7090
7091 if ( mi->depth & MI_HASDEPTH_16 )
7092 depth = 16;
7093 else if ( mi->depth & MI_HASDEPTH_14 )
7094 depth = 14;
7095 else if ( mi->depth & MI_HASDEPTH_12 )
7096 depth = 12;
7097 else if ( mi->depth & MI_HASDEPTH_10 )
7098 depth = 10;
7099 else
7100 depth = 8;
7101
7102 maxval = ( 1 << depth ) - 1;
7103
7104 from = ms->gamma_table;
7105 size = ms->lut_size;
7106
7107 /* first master channel, apply transformation to all colors */
7108 exposure = ms->exposure_m;
7109 for ( byte = 0; byte < ms->lut_size; byte++ )
7110 {
7111 for ( color = 0; color < 3; color++)
7112 {
7113 val32 = (uint32_t) *((uint16_t *) from + color * size + byte);
7114 val32 = MIN(val32 + val32
7115 * (2 * (uint32_t) exposure / 100), (uint32_t) maxval);
7116 *((uint16_t *) from + color * size + byte) = (uint16_t) val32;
7117 }
7118 }
7119
7120 /* and now apply transformation to each channel */
7121
7122 exposure_rgb[0] = ms->exposure_r;
7123 exposure_rgb[1] = ms->exposure_g;
7124 exposure_rgb[2] = ms->exposure_b;
7125 for ( color = 0; color < 3; color++ )
7126 {
7127 for ( byte = 0; byte < size; byte++ )
7128 {
7129 val32 = (uint32_t) *((uint16_t *) from + color * size + byte);
7130 val32 = MIN(val32 + val32
7131 * (2 * (uint32_t) exposure_rgb[color] / 100),
7132 (uint32_t) maxval);
7133 *((uint16_t *) from + color * size + byte) = (uint16_t) val32;
7134 }
7135 }
7136
7137 return;
7138 }
7139
7140
7141 /*---------- reader_process() ------------------------------------------------*/
7142
7143 static int
reader_process(void * data)7144 reader_process(void *data)
7145 {
7146 Microtek2_Scanner *ms = (Microtek2_Scanner *) data;
7147
7148 SANE_Status status;
7149 Microtek2_Info *mi;
7150 Microtek2_Device *md;
7151 struct SIGACTION act;
7152 sigset_t sigterm_set;
7153 static uint8_t *temp_current = NULL;
7154
7155 DBG(30, "reader_process: ms=%p\n", (void *) ms);
7156
7157 md = ms->dev;
7158 mi = &md->info[md->scan_source];
7159
7160 if (sanei_thread_is_forked()) close(ms->fd[0]);
7161
7162 sigemptyset (&sigterm_set);
7163 sigaddset (&sigterm_set, SIGTERM);
7164 memset (&act, 0, sizeof (act));
7165 act.sa_handler = signal_handler;
7166 sigaction (SIGTERM, &act, 0);
7167
7168 ms->fp = fdopen(ms->fd[1], "w");
7169 if ( ms->fp == NULL )
7170 {
7171 DBG(1, "reader_process: fdopen() failed, errno=%d\n", errno);
7172 return SANE_STATUS_IO_ERROR;
7173 }
7174
7175 if ( ms->auto_adjust == 1 )
7176 {
7177 if ( temp_current == NULL )
7178 temp_current = ms->temporary_buffer;
7179 }
7180
7181 while ( ms->src_remaining_lines > 0 )
7182 {
7183
7184 ms->src_lines_to_read = MIN(ms->src_remaining_lines, ms->src_max_lines);
7185 ms->transfer_length = ms->src_lines_to_read * ms->bpl;
7186
7187 DBG(30, "reader_process: transferlength=%d, lines=%d, linelength=%d, "
7188 "real_bpl=%d, srcbuf=%p\n",
7189 ms->transfer_length, ms->src_lines_to_read, ms->bpl,
7190 ms->real_bpl, (void *) ms->buf.src_buf);
7191
7192 sigprocmask (SIG_BLOCK, &sigterm_set, 0);
7193 status = scsi_read_image(ms, ms->buf.src_buf, (ms->depth > 8) ? 2 : 1);
7194 sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
7195 if ( status != SANE_STATUS_GOOD )
7196 return SANE_STATUS_IO_ERROR;
7197
7198 ms->src_remaining_lines -= ms->src_lines_to_read;
7199
7200 /* prepare data for frontend */
7201 switch (ms->mode)
7202 {
7203 case MS_MODE_COLOR:
7204 if ( ! mi->onepass )
7205 /* TODO */
7206 {
7207 DBG(1, "reader_process: 3 pass not yet supported\n");
7208 return SANE_STATUS_IO_ERROR;
7209 }
7210 else
7211 {
7212 switch ( mi->data_format )
7213 {
7214 case MI_DATAFMT_CHUNKY:
7215 case MI_DATAFMT_9800:
7216 status = chunky_proc_data(ms);
7217 if ( status != SANE_STATUS_GOOD )
7218 return status;
7219 break;
7220 case MI_DATAFMT_LPLCONCAT:
7221 status = lplconcat_proc_data(ms);
7222 if ( status != SANE_STATUS_GOOD )
7223 return status;
7224 break;
7225 case MI_DATAFMT_LPLSEGREG:
7226 status = segreg_proc_data(ms);
7227 if ( status != SANE_STATUS_GOOD )
7228 return status;
7229 break;
7230 case MI_DATAFMT_WORDCHUNKY:
7231 status = wordchunky_proc_data(ms);
7232 if ( status != SANE_STATUS_GOOD )
7233 return status;
7234 break;
7235 default:
7236 DBG(1, "reader_process: format %d\n", mi->data_format);
7237 return SANE_STATUS_IO_ERROR;
7238 }
7239 }
7240 break;
7241 case MS_MODE_GRAY:
7242 status = gray_proc_data(ms);
7243 if ( status != SANE_STATUS_GOOD )
7244 return status;
7245 break;
7246 case MS_MODE_HALFTONE:
7247 case MS_MODE_LINEART:
7248 status = proc_onebit_data(ms);
7249 if ( status != SANE_STATUS_GOOD )
7250 return status;
7251 break;
7252 case MS_MODE_LINEARTFAKE:
7253 if ( ms->auto_adjust == 1 )
7254 status = auto_adjust_proc_data(ms, &temp_current);
7255 else
7256 status = lineartfake_proc_data(ms);
7257
7258 if ( status != SANE_STATUS_GOOD )
7259 return status;
7260 break;
7261 default:
7262 DBG(1, "reader_process: Unknown scan mode %d\n", ms->mode);
7263 return SANE_STATUS_IO_ERROR;
7264 }
7265 }
7266
7267 fclose(ms->fp);
7268 return SANE_STATUS_GOOD;
7269 }
7270
7271 /*---------- chunky_proc_data() ----------------------------------------------*/
7272
7273 static SANE_Status
chunky_proc_data(Microtek2_Scanner * ms)7274 chunky_proc_data(Microtek2_Scanner *ms)
7275 {
7276 SANE_Status status;
7277 Microtek2_Device *md;
7278 uint32_t line;
7279 uint8_t *from;
7280 int pad;
7281 int bpp; /* bytes per pixel */
7282 int bits_pp_in; /* bits per pixel input */
7283 int bits_pp_out; /* bits per pixel output */
7284 int bpl_ppl_diff;
7285
7286
7287 DBG(30, "chunky_proc_data: ms=%p\n", (void *) ms);
7288
7289 md = ms->dev;
7290 bits_pp_in = ms->bits_per_pixel_in;
7291 bits_pp_out = ms->bits_per_pixel_out;
7292 pad = (int) ceil( (double) (ms->ppl * bits_pp_in) / 8.0 ) % 2;
7293 bpp = bits_pp_out / 8;
7294
7295 /* Some models have 3 * ppl + 6 bytes per line if the number of pixels */
7296 /* per line is even and 3 * ppl + 3 bytes per line if the number of */
7297 /* pixels per line is odd. According to the documentation it should be */
7298 /* bpl = 3*ppl (even number of pixels) or bpl=3*ppl+1 (odd number of */
7299 /* pixels. Even worse: On different models it is different at which */
7300 /* position in a scanline the image data starts. bpl_ppl_diff tries */
7301 /* to fix this. */
7302
7303 if ( (md->model_flags & MD_OFFSET_2) && pad == 1 )
7304 bpl_ppl_diff = 2;
7305 else
7306 bpl_ppl_diff = 0;
7307
7308 #if 0
7309 if ( md->revision == 1.00 && mi->model_code != 0x81 )
7310 bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp ) - pad;
7311 else
7312 bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp );
7313
7314 if ( md->revision > 1.00 )
7315 bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp );
7316 else
7317 bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp ) - pad;
7318 #endif
7319
7320 from = ms->buf.src_buf;
7321 from += bpl_ppl_diff;
7322
7323 DBG(30, "chunky_proc_data: lines=%d, bpl=%d, ppl=%d, bpp=%d, depth=%d"
7324 " junk=%d\n", ms->src_lines_to_read, ms->bpl, ms->ppl,
7325 bpp, ms->depth, bpl_ppl_diff);
7326
7327 for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7328 {
7329 status = chunky_copy_pixels(ms, from);
7330 if ( status != SANE_STATUS_GOOD )
7331 return status;
7332 from += ms->bpl;
7333 }
7334
7335 return SANE_STATUS_GOOD;
7336 }
7337
7338 /*---------- chunky_copy_pixels() --------------------------------------------*/
7339
7340 static SANE_Status
chunky_copy_pixels(Microtek2_Scanner * ms,uint8_t * from)7341 chunky_copy_pixels(Microtek2_Scanner *ms, uint8_t *from)
7342 {
7343 Microtek2_Device *md;
7344 uint32_t pixel;
7345 int color;
7346
7347 DBG(30, "chunky_copy_pixels: from=%p, pixels=%d, fp=%p, depth=%d\n",
7348 (void *) from, ms->ppl, (void *) ms->fp, ms->depth);
7349
7350 md = ms->dev;
7351 if ( ms->depth > 8 )
7352 {
7353 if ( !( md->model_flags & MD_16BIT_TRANSFER ) )
7354 {
7355 int scale1;
7356 int scale2;
7357 uint16_t val16;
7358
7359 scale1 = 16 - ms->depth;
7360 scale2 = 2 * ms->depth - 16;
7361 for ( pixel = 0; pixel < ms->ppl; pixel++ )
7362 {
7363 for ( color = 0; color < 3; color++ )
7364 {
7365 val16 = *( (uint16_t *) from + 3 * pixel + color );
7366 val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7367 fwrite((void *) &val16, 2, 1, ms->fp);
7368 }
7369 }
7370 }
7371 else
7372 {
7373 fwrite((void *) from, 2, 3 * ms->ppl, ms->fp);
7374 }
7375 }
7376 else if ( ms->depth == 8 )
7377 {
7378 fwrite((void *) from, 1, 3 * ms->ppl, ms->fp);
7379 }
7380 else
7381 {
7382 DBG(1, "chunky_copy_pixels: Unknown depth %d\n", ms->depth);
7383 return SANE_STATUS_IO_ERROR;
7384 }
7385
7386 return SANE_STATUS_GOOD;
7387 }
7388
7389 /*---------- segreg_proc_data() ----------------------------------------------*/
7390
7391 static SANE_Status
segreg_proc_data(Microtek2_Scanner * ms)7392 segreg_proc_data(Microtek2_Scanner *ms)
7393 {
7394 SANE_Status status;
7395 Microtek2_Device *md;
7396 Microtek2_Info *mi;
7397 char colormap[] = "RGB";
7398 uint8_t *from;
7399 uint32_t lines_to_deliver;
7400 int bpp; /* bytes per pixel */
7401 int bpf; /* bytes per frame including color indicator */
7402 int pad;
7403 int colseq2;
7404 int color;
7405 int save_current_src;
7406 int frame;
7407
7408 DBG(30, "segreg_proc_data: ms=%p\n", (void *) ms);
7409
7410 md = ms->dev;
7411 mi = &md->info[md->scan_source];
7412 /* take a trailing junk byte into account */
7413 pad = (int) ceil( (double) (ms->ppl * ms->bits_per_pixel_in) / 8.0 ) % 2;
7414 bpp = ms->bits_per_pixel_out / 8; /* bits_per_pixel_out is either 8 or 16 */
7415 bpf = ms->bpl / 3;
7416
7417 DBG(30, "segreg_proc_data: lines=%d, bpl=%d, ppl=%d, bpf=%d, bpp=%d,\n"
7418 "depth=%d, pad=%d, freelines=%d, calib_backend=%d\n",
7419 ms->src_lines_to_read, ms->bpl, ms->ppl, bpf, bpp,
7420 ms->depth, pad, ms->buf.free_lines, ms->calib_backend);
7421
7422 /* determine how many planes of each color are in the source buffer */
7423 from = ms->buf.src_buf;
7424 for ( frame = 0; frame < 3 * ms->src_lines_to_read; frame++, from += bpf )
7425 {
7426 switch ( *from )
7427 {
7428 case 'R':
7429 ++ms->buf.planes[0][MS_COLOR_RED];
7430 break;
7431 case 'G':
7432 ++ms->buf.planes[0][MS_COLOR_GREEN];
7433 break;
7434 case 'B':
7435 ++ms->buf.planes[0][MS_COLOR_BLUE];
7436 break;
7437 default:
7438 DBG(1, "segreg_proc_data: unknown color indicator (1) "
7439 "0x%02x\n", *from);
7440 return SANE_STATUS_IO_ERROR;
7441 }
7442 }
7443
7444 ms->buf.free_lines -= ms->src_lines_to_read;
7445 save_current_src = ms->buf.current_src;
7446 if ( ms->buf.free_lines < ms->src_max_lines )
7447 {
7448 ms->buf.current_src = !ms->buf.current_src;
7449 ms->buf.src_buf = ms->buf.src_buffer[ms->buf.current_src];
7450 ms->buf.free_lines = ms->buf.free_max_lines;
7451 }
7452 else
7453 ms->buf.src_buf += ms->src_lines_to_read * ms->bpl;
7454
7455 colseq2 = mi->color_sequence[2];
7456 lines_to_deliver = ms->buf.planes[0][colseq2] + ms->buf.planes[1][colseq2];
7457 if ( lines_to_deliver == 0 )
7458 return SANE_STATUS_GOOD;
7459
7460 DBG(30, "segreg_proc_data: planes[0][0]=%d, planes[0][1]=%d, "
7461 "planes[0][2]=%d\n", ms->buf.planes[0][0], ms->buf.planes[0][1],
7462 ms->buf.planes[0][2] );
7463 DBG(30, "segreg_proc_data: planes[1][0]=%d, planes[1][1]=%d, "
7464 "planes[1][2]=%d\n", ms->buf.planes[1][0], ms->buf.planes[1][1],
7465 ms->buf.planes[1][2] );
7466
7467 while ( lines_to_deliver > 0 )
7468 {
7469 for ( color = 0; color < 3; color++ )
7470 {
7471 /* get the position of the next plane for each color */
7472 do
7473 {
7474 if ( *ms->buf.current_pos[color] == colormap[color] )
7475 break;
7476 ms->buf.current_pos[color] += bpf;
7477 } while ( 1 );
7478
7479 ms->buf.current_pos[color] += 2; /* skip color indicator */
7480 }
7481
7482 status = segreg_copy_pixels(ms);
7483 if ( status != SANE_STATUS_GOOD )
7484 {
7485 DBG(1, "segreg_copy_pixels:status %d\n", status);
7486 return status;
7487 }
7488
7489 for ( color = 0; color < 3; color++ )
7490 {
7491 /* skip a padding byte at the end, if present */
7492 ms->buf.current_pos[color] += pad;
7493
7494 if ( ms->buf.planes[1][color] > 0 )
7495 {
7496 --ms->buf.planes[1][color];
7497 if ( ms->buf.planes[1][color] == 0 )
7498 /* we have copied from the prehold buffer and are */
7499 /* done now, we continue with the source buffer */
7500 ms->buf.current_pos[color] =
7501 ms->buf.src_buffer[save_current_src];
7502 }
7503 else
7504 {
7505 --ms->buf.planes[0][color];
7506 if ( ms->buf.planes[0][color] == 0
7507 && ms->buf.current_src != save_current_src )
7508
7509 ms->buf.current_pos[color] =
7510 ms->buf.src_buffer[ms->buf.current_src];
7511 }
7512 }
7513 DBG(100, "planes_to_deliver=%d\n", lines_to_deliver);
7514 --lines_to_deliver;
7515 }
7516
7517 if ( ms->buf.current_src != save_current_src )
7518 {
7519 for ( color = 0; color < 3; color++ )
7520 {
7521 ms->buf.planes[1][color] += ms->buf.planes[0][color];
7522 ms->buf.planes[0][color] = 0;
7523 }
7524 }
7525
7526 DBG(30, "segreg_proc_data: src_buf=%p, free_lines=%d\n",
7527 (void *) ms->buf.src_buf, ms->buf.free_lines);
7528
7529 return SANE_STATUS_GOOD;
7530 }
7531
7532 /*---------- segreg_copy_pixels() --------------------------------------------*/
7533
7534 static SANE_Status
segreg_copy_pixels(Microtek2_Scanner * ms)7535 segreg_copy_pixels(Microtek2_Scanner *ms)
7536 {
7537 Microtek2_Device *md;
7538 Microtek2_Info *mi;
7539 uint32_t pixel;
7540 int color, i, gamma_by_backend, right_to_left, scale1, scale2, bpp_in;
7541 float s_w, s_d; /* shading byte from condensed_shading */
7542 float val, maxval = 0, shading_factor = 0;
7543 uint16_t val16 = 0;
7544 uint8_t val8 = 0;
7545 uint8_t *from_effective;
7546 uint8_t *gamma[3];
7547 float f[3]; /* color balance factor */
7548
7549 md = ms->dev;
7550 mi = &md->info[md->scan_source];
7551 gamma_by_backend = md->model_flags & MD_NO_GAMMA ? 1 : 0;
7552 right_to_left = mi->direction & MI_DATSEQ_RTOL;
7553 scale1 = 16 - ms->depth;
7554 scale2 = 2 * ms->depth - 16;
7555 bpp_in = ( ms->bits_per_pixel_in + 7 ) / 8; /*Bytes per pixel from scanner*/
7556
7557 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
7558 {
7559 maxval = (float) pow(2.0, (float) ms->depth) - 1.0;
7560 s_w = maxval;
7561 s_d = 0.0;
7562 shading_factor = (float) pow(2.0, (double) (md->shading_depth
7563 - ms->depth) );
7564 }
7565
7566 if ( gamma_by_backend )
7567 {
7568 i = (ms->depth > 8) ? 2 : 1;
7569 for ( color = 0; color < 3; color++)
7570 gamma[color] = ms->gamma_table
7571 + i * (int) pow(2.0, (double)ms->depth);
7572 }
7573
7574 DBG(30, "segreg_copy_pixels: pixels=%d\n", ms->ppl);
7575 DBG(100, "segreg_copy_pixels: buffer 0x%p, right_to_left=%d, depth=%d\n",
7576 (void *) ms->buf.current_pos, right_to_left, ms->depth);
7577
7578 for (color = 0; color < 3; color++ )
7579 f[color] = (float) ms->balance[color] / 100.0;
7580
7581 DBG(100, "segreg_copy_pixels: color balance:\n"
7582 " ms->balance[R]=%d, ms->balance[G]=%d, ms->balance[B]=%d\n",
7583 ms->balance[0], ms->balance[1], ms->balance[2]);
7584
7585 for ( pixel = 0; pixel < ms->ppl; pixel++ )
7586 {
7587 for ( color = 0; color < 3; color++ )
7588 {
7589 if ( right_to_left )
7590 from_effective = ms->buf.current_pos[color]
7591 + ( ms->ppl - 1 - pixel ) * bpp_in;
7592 else
7593 from_effective = ms->buf.current_pos[color] + pixel * bpp_in;
7594
7595 if ( ms->depth > 8 )
7596 val = (float) *(uint16_t *)from_effective;
7597 else if ( ms->depth == 8 )
7598 val = (float) *from_effective;
7599 else
7600 {
7601 DBG(1, "segreg_copy_pixels: Unknown depth %d\n", ms->depth);
7602 return SANE_STATUS_IO_ERROR;
7603 }
7604
7605 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
7606 && ( ms->condensed_shading_w != NULL ))
7607 /* apply shading by backend */
7608 {
7609 get_cshading_values(ms,
7610 color,
7611 pixel,
7612 shading_factor,
7613 right_to_left,
7614 &s_d,
7615 &s_w);
7616
7617
7618 if ( s_w == s_d ) s_w = s_d + 1;
7619 if ( val < s_d ) val = s_d;
7620 val = maxval *( val - s_d ) / ( s_w - s_d );
7621
7622 val *= f[color];
7623
7624 /* if scanner doesn't support brightness, contrast */
7625 if ( md->model_flags & MD_NO_ENHANCEMENTS )
7626 {
7627 val += ( ( ms->brightness_m - 128 ) * 2 );
7628 val = ( val - 128 ) * ( ms->contrast_m / 128 ) + 128;
7629 }
7630
7631 val = MAX( 0.0, val);
7632 val = MIN( maxval, val );
7633 }
7634
7635 val16 = (uint16_t) val;
7636 val8 = (uint8_t) val;
7637
7638 /* apply gamma correction if needed */
7639 if ( gamma_by_backend )
7640 {
7641 if ( ms->depth > 8 )
7642 val16 = *((uint16_t *) gamma[color] + val16);
7643 else
7644 val8 = gamma[color][val8];
7645 }
7646
7647 if ( ms->depth > 8 )
7648 {
7649 val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7650 fwrite((void *) &val16, 2, 1, ms->fp);
7651 }
7652 else
7653 {
7654 fputc((unsigned char) val8, ms->fp);
7655 }
7656
7657 }
7658 }
7659 for ( color = 0; color < 3; color++ )
7660 {
7661 ms->buf.current_pos[color] += ms->ppl;
7662 if ( ms->depth > 8 )
7663 ms->buf.current_pos[color] += ms->ppl;
7664 }
7665
7666 return SANE_STATUS_GOOD;
7667
7668 }
7669
7670
7671 /*---------- lplconcat_proc_data() -------------------------------------------*/
7672 static SANE_Status
lplconcat_proc_data(Microtek2_Scanner * ms)7673 lplconcat_proc_data(Microtek2_Scanner *ms)
7674 {
7675 SANE_Status status;
7676 Microtek2_Device *md;
7677 Microtek2_Info *mi;
7678 uint32_t line;
7679 uint8_t *from[3];
7680 uint8_t *save_from[3];
7681 int color;
7682 int bpp;
7683 int gamma_by_backend;
7684 int right_to_left; /* 0=left to right, 1=right to left */
7685
7686
7687 DBG(30, "lplconcat_proc_data: ms=%p\n", (void *) ms);
7688
7689 /* This data format seems to honour the color sequence indicator */
7690
7691 md = ms->dev;
7692 mi = &md->info[md->scan_source];
7693
7694 bpp = ms->bits_per_pixel_out / 8; /* ms->bits_per_pixel_out is 8 or 16 */
7695 right_to_left = mi->direction & MI_DATSEQ_RTOL;
7696 gamma_by_backend = md->model_flags & MD_NO_GAMMA ? 1 : 0;
7697
7698 if ( right_to_left == 1 )
7699 {
7700 for ( color = 0; color < 3; color++ )
7701 {
7702 from[color] = ms->buf.src_buf
7703 + ( mi->color_sequence[color] + 1 ) * ( ms->bpl / 3 )
7704 - bpp - (ms->bpl - 3 * ms->ppl * bpp) / 3;
7705 }
7706 }
7707 else
7708 for ( color = 0; color < 3; color++ )
7709 from[color] = ms->buf.src_buf
7710 + mi->color_sequence[color] * ( ms->bpl / 3 );
7711
7712 for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7713 {
7714 for ( color = 0 ; color < 3; color++ )
7715 save_from[color] = from[color];
7716
7717 status = lplconcat_copy_pixels(ms,
7718 from,
7719 right_to_left,
7720 gamma_by_backend);
7721 if ( status != SANE_STATUS_GOOD )
7722 return status;
7723
7724 for ( color = 0; color < 3; color++ )
7725 from[color] = save_from[color] + ms->bpl;
7726 }
7727
7728 return SANE_STATUS_GOOD;
7729 }
7730
7731
7732 /*---------- lplconcat_copy_pixels() -----------------------------------------*/
7733
7734 static SANE_Status
lplconcat_copy_pixels(Microtek2_Scanner * ms,uint8_t ** from,int right_to_left,int gamma_by_backend)7735 lplconcat_copy_pixels(Microtek2_Scanner *ms,
7736 uint8_t **from,
7737 int right_to_left,
7738 int gamma_by_backend)
7739 {
7740 Microtek2_Device *md;
7741 Microtek2_Info *mi;
7742 uint32_t pixel;
7743 uint16_t val16 = 0;
7744 uint8_t val8 = 0;
7745 uint8_t *gamma[3];
7746 float s_d; /* dark shading pixel */
7747 float s_w; /* white shading pixel */
7748 float shading_factor = 0;
7749 float f[3]; /* color balance factor */
7750 float val, maxval = 0;
7751 int color;
7752 int step, scale1, scale2;
7753 int i;
7754
7755
7756 DBG(30, "lplconcat_copy_pixels: ms=%p, righttoleft=%d, gamma=%d,\n",
7757 (void *) ms, right_to_left, gamma_by_backend);
7758
7759 md = ms->dev;
7760 mi = &md->info[md->scan_source];
7761
7762 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
7763 {
7764 shading_factor = (float) pow(2.0,(double)(md->shading_depth - ms->depth));
7765 maxval = (float) pow(2.0, (double) ms->depth) - 1.0;
7766 s_w = maxval;
7767 s_d = 0.0;
7768 }
7769
7770 step = ( right_to_left == 1 ) ? -1 : 1;
7771 if ( ms->depth > 8 ) step *= 2;
7772 scale1 = 16 - ms->depth;
7773 scale2 = 2 * ms->depth - 16;
7774
7775 if ( gamma_by_backend )
7776 {
7777 i = ( ms->depth > 8 ) ? 2 : 1;
7778 for ( color = 0; color < 3; color++ )
7779 gamma[color] = ms->gamma_table + i * (int) pow(2.0,(double)ms->depth);
7780 }
7781
7782 for (color = 0; color < 3; color++ )
7783 f[color] = (float)ms->balance[color] / 100.0;
7784
7785 DBG(100, "lplconcat_copy_pixels: color balance:\n"
7786 " ms->balance[R]=%d, ms->balance[G]=%d, ms->balance[B]=%d\n",
7787 ms->balance[0], ms->balance[1], ms->balance[2]);
7788
7789 for ( pixel = 0; pixel < ms->ppl; pixel++ )
7790 {
7791 for ( color = 0; color < 3; color++ )
7792 {
7793 if ( ms->depth > 8 )
7794 val = (float) *(uint16_t *) from[color];
7795 else if ( ms->depth == 8 )
7796 val = (float) *from[color];
7797 else
7798 {
7799 DBG(1, "lplconcat_copy_pixels: Unknown depth %d\n", ms->depth);
7800 return SANE_STATUS_IO_ERROR;
7801 }
7802
7803 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
7804 && ( ms->condensed_shading_w != NULL ))
7805 /* apply shading by backend */
7806 {
7807 get_cshading_values(ms,
7808 mi->color_sequence[color],
7809 pixel,
7810 shading_factor,
7811 right_to_left,
7812 &s_d,
7813 &s_w);
7814
7815 if ( val < s_d ) val = s_d;
7816 if ( s_w == s_d ) s_w = s_d + 1;
7817 val = ( maxval * ( val - s_d ) ) / (s_w - s_d);
7818
7819 val *= f[color]; /* apply color balance */
7820
7821 /* if scanner doesn't support brightness, contrast ... */
7822 if ( md->model_flags & MD_NO_ENHANCEMENTS )
7823 {
7824 val += ( ( ms->brightness_m - 128 ) * 2 );
7825 val = ( val - 128 ) * ( ms->contrast_m / 128 ) + 128;
7826 }
7827
7828 if ( val > maxval ) val = maxval;
7829 if ( val < 0.0 ) val = 0.0;
7830 }
7831
7832 val16 = (uint16_t) val;
7833 val8 = (uint8_t) val;
7834
7835 /* apply gamma correction if needed */
7836 if ( gamma_by_backend )
7837 {
7838 if ( ms->depth > 8 )
7839 val16 = *((uint16_t *) gamma[color] + val16);
7840 else
7841 val8 = gamma[color][val8];
7842 }
7843
7844 if ( ms->depth > 8 )
7845 {
7846 val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7847 fwrite((void *) &val16, 2, 1, ms->fp);
7848 }
7849 else
7850 {
7851 fputc((unsigned char) val8, ms->fp);
7852 }
7853 from[color] += step;
7854 }
7855 }
7856 return SANE_STATUS_GOOD;
7857 }
7858
7859
7860
7861
7862 /*---------- wordchunky_proc_data() ------------------------------------------*/
7863
7864 static SANE_Status
wordchunky_proc_data(Microtek2_Scanner * ms)7865 wordchunky_proc_data(Microtek2_Scanner *ms)
7866 {
7867 SANE_Status status;
7868 uint8_t *from;
7869 uint32_t line;
7870
7871
7872 DBG(30, "wordchunky_proc_data: ms=%p\n", (void *) ms);
7873
7874 from = ms->buf.src_buf;
7875 for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7876 {
7877 status = wordchunky_copy_pixels(from, ms->ppl, ms->depth, ms->fp);
7878 if ( status != SANE_STATUS_GOOD )
7879 return status;
7880 from += ms->bpl;
7881 }
7882
7883 return SANE_STATUS_GOOD;
7884 }
7885
7886
7887 /*---------- wordchunky_copy_pixels() ----------------------------------------*/
7888
7889 static SANE_Status
wordchunky_copy_pixels(uint8_t * from,uint32_t pixels,int depth,FILE * fp)7890 wordchunky_copy_pixels(uint8_t *from, uint32_t pixels, int depth, FILE *fp)
7891 {
7892 uint32_t pixel;
7893 int color;
7894
7895 DBG(30, "wordchunky_copy_pixels: from=%p, pixels=%d, depth=%d\n",
7896 (void *) from, pixels, depth);
7897
7898 if ( depth > 8 )
7899 {
7900 int scale1;
7901 int scale2;
7902 uint16_t val16;
7903
7904 scale1 = 16 - depth;
7905 scale2 = 2 * depth - 16;
7906 for ( pixel = 0; pixel < pixels; pixel++ )
7907 {
7908 for ( color = 0; color < 3; color++ )
7909 {
7910 val16 = *(uint16_t *) from;
7911 val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7912 fwrite((void *) &val16, 2, 1, fp);
7913 from += 2;
7914 }
7915 }
7916 }
7917 else if ( depth == 8 )
7918 {
7919 pixel = 0;
7920 do
7921 {
7922 fputc((char ) *from, fp);
7923 fputc((char) *(from + 2), fp);
7924 fputc((char) *(from + 4), fp);
7925 ++pixel;
7926 if ( pixel < pixels )
7927 {
7928 fputc((char) *(from + 1), fp);
7929 fputc((char) *(from + 3), fp);
7930 fputc((char) *(from + 5), fp);
7931 ++pixel;
7932 }
7933 from += 6;
7934 } while ( pixel < pixels );
7935 }
7936 else
7937 {
7938 DBG(1, "wordchunky_copy_pixels: Unknown depth %d\n", depth);
7939 return SANE_STATUS_IO_ERROR;
7940 }
7941
7942 return SANE_STATUS_GOOD;
7943 }
7944
7945
7946 /*---------- gray_proc_data() ------------------------------------------------*/
7947
7948 static SANE_Status
gray_proc_data(Microtek2_Scanner * ms)7949 gray_proc_data(Microtek2_Scanner *ms)
7950 {
7951 SANE_Status status;
7952 Microtek2_Device *md;
7953 Microtek2_Info *mi;
7954 uint8_t *from;
7955 int gamma_by_backend, bpp;
7956 int right_to_left; /* for scanning direction */
7957
7958
7959 DBG(30, "gray_proc_data: lines=%d, bpl=%d, ppl=%d, depth=%d\n",
7960 ms->src_lines_to_read, ms->bpl, ms->ppl, ms->depth);
7961
7962 md = ms->dev;
7963 mi = &md->info[md->scan_source];
7964
7965 gamma_by_backend = md->model_flags & MD_NO_GAMMA ? 1 : 0;
7966 right_to_left = mi->direction & MI_DATSEQ_RTOL;
7967 bpp = ( ms->bits_per_pixel_in + 7 ) / 8;
7968
7969 if ( right_to_left == 1 )
7970 from = ms->buf.src_buf + ms->ppl * bpp - bpp;
7971 else
7972 from = ms->buf.src_buf;
7973
7974 do
7975 {
7976 status = gray_copy_pixels(ms,
7977 from,
7978 right_to_left,
7979 gamma_by_backend);
7980 if ( status != SANE_STATUS_GOOD )
7981 return status;
7982
7983 from += ms->bpl;
7984 --ms->src_lines_to_read;
7985 } while ( ms->src_lines_to_read > 0 );
7986
7987 return SANE_STATUS_GOOD;
7988 }
7989
7990
7991 /*---------- gray_copy_pixels() ----------------------------------------------*/
7992
7993 static SANE_Status
gray_copy_pixels(Microtek2_Scanner * ms,uint8_t * from,int right_to_left,int gamma_by_backend)7994 gray_copy_pixels(Microtek2_Scanner *ms,
7995 uint8_t *from,
7996 int right_to_left,
7997 int gamma_by_backend)
7998 {
7999 Microtek2_Device *md;
8000 uint32_t pixel;
8001 uint16_t val16;
8002 uint8_t val8;
8003 int step, scale1, scale2;
8004 float val, maxval = 0;
8005 float s_w, s_d, shading_factor = 0;
8006
8007 DBG(30, "gray_copy_pixels: pixels=%d, from=%p, fp=%p, depth=%d\n",
8008 ms->ppl, (void *) from, (void *) ms->fp, ms->depth);
8009
8010 md = ms->dev;
8011 step = right_to_left == 1 ? -1 : 1;
8012 if ( ms->depth > 8 ) step *= 2;
8013 val = 0;
8014 scale1 = 16 - ms->depth;
8015 scale2 = 2 * ms->depth - 16;
8016
8017 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
8018 {
8019 maxval = (float) pow(2.0, (float) ms->depth) - 1.0;
8020 s_w = maxval;
8021 s_d = 0.0;
8022 shading_factor = (float) pow(2.0, (double) (md->shading_depth - ms->depth) );
8023 }
8024
8025 if ( ms->depth >= 8 )
8026 {
8027 for ( pixel = 0; pixel < ms->ppl; pixel++ )
8028 {
8029 if ( ms->depth > 8 )
8030 val = (float) *(uint16_t *) from;
8031 if ( ms->depth == 8 )
8032 val = (float) *from;
8033
8034 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
8035 && ( ms->condensed_shading_w != NULL ))
8036 /* apply shading by backend */
8037 {
8038 get_cshading_values(ms,
8039 0,
8040 pixel,
8041 shading_factor,
8042 right_to_left,
8043 &s_d,
8044 &s_w);
8045
8046 if ( val < s_d ) val = s_d;
8047 val = ( val - s_d ) * maxval / (s_w - s_d );
8048 val = MAX( 0.0, val );
8049 val = MIN( maxval, val );
8050 }
8051
8052 if ( ms->depth > 8 )
8053 {
8054 val16 = (uint16_t) val;
8055 if ( gamma_by_backend )
8056 val16 = *((uint16_t *) ms->gamma_table + val16);
8057 if ( !( md->model_flags & MD_16BIT_TRANSFER ) )
8058 val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
8059 fwrite((void *) &val16, 2, 1, ms->fp);
8060 }
8061
8062 if ( ms->depth == 8 )
8063 {
8064 val8 = (uint8_t) val;
8065 if ( gamma_by_backend )
8066 val8 = ms->gamma_table[(int)val8];
8067 fputc((char)val8, ms->fp);
8068 }
8069 from += step;
8070 }
8071 }
8072 else if ( ms->depth == 4 )
8073 {
8074 pixel = 0;
8075 while ( pixel < ms->ppl )
8076 {
8077 fputc((char) ( ((*from >> 4) & 0x0f) | (*from & 0xf0) ), ms->fp);
8078 ++pixel;
8079 if ( pixel < ms->ppl )
8080 fputc((char) ((*from & 0x0f) | ((*from << 4) & 0xf0)), ms->fp);
8081 from += step;
8082 ++pixel;
8083 }
8084 }
8085 else
8086 {
8087 DBG(1, "gray_copy_pixels: Unknown depth %d\n", ms->depth);
8088 return SANE_STATUS_IO_ERROR;
8089 }
8090
8091 return SANE_STATUS_GOOD;
8092 }
8093
8094 /*---------- proc_onebit_data() ----------------------------------------------*/
8095
8096 static SANE_Status
proc_onebit_data(Microtek2_Scanner * ms)8097 proc_onebit_data(Microtek2_Scanner *ms)
8098 {
8099 Microtek2_Device *md;
8100 Microtek2_Info *mi;
8101 uint32_t bytes_to_copy; /* bytes per line to copy */
8102 uint32_t line;
8103 uint32_t byte;
8104 uint32_t ppl;
8105 uint8_t *from;
8106 uint8_t to;
8107 int right_to_left;
8108 int bit;
8109 int toindex;
8110
8111
8112 DBG(30, "proc_onebit_data: ms=%p\n", (void *) ms);
8113
8114 md = ms->dev;
8115 mi = &md->info[md->scan_source];
8116 from = ms->buf.src_buf;
8117 bytes_to_copy = ( ms->ppl + 7 ) / 8 ;
8118 right_to_left = mi->direction & MI_DATSEQ_RTOL;
8119
8120 DBG(30, "proc_onebit_data: bytes_to_copy=%d, lines=%d\n",
8121 bytes_to_copy, ms->src_lines_to_read);
8122
8123 line = 0;
8124 to = 0;
8125 do
8126 {
8127 /* in onebit mode black and white colors are inverted */
8128 if ( right_to_left )
8129 {
8130 /* If the direction is right_to_left, we must skip some */
8131 /* trailing bits at the end of the scan line and invert the */
8132 /* bit sequence. We copy 8 bits into a byte, but these bits */
8133 /* are normally not byte aligned. */
8134
8135 /* Determine the position of the first bit to copy */
8136 ppl = ms->ppl;
8137 byte = ( ppl + 7 ) / 8 - 1;
8138 bit = ppl % 8 - 1;
8139 to = 0;
8140 toindex = 8;
8141
8142 while ( ppl > 0 )
8143 {
8144 to |= ( ( from[byte] >> (7 - bit) ) & 0x01);
8145 --toindex;
8146 if ( toindex == 0 )
8147 {
8148 fputc( (char) ~to, ms->fp);
8149 toindex = 8;
8150 to = 0;
8151 }
8152 else
8153 to <<= 1;
8154
8155 --bit;
8156 if ( bit < 0 )
8157 {
8158 bit = 7;
8159 --byte;
8160 }
8161 --ppl;
8162 }
8163 /* print the last byte of the line, if it was not */
8164 /* completely filled */
8165 bit = ms->ppl % 8;
8166 if ( bit != 0 )
8167 fputc( (char) ~(to << (7 - bit)), ms->fp);
8168 }
8169 else
8170 for ( byte = 0; byte < bytes_to_copy; byte++ )
8171 fputc( (char) ~from[byte], ms->fp);
8172
8173 from += ms->bpl;
8174
8175 } while ( ++line < (uint32_t) ms->src_lines_to_read );
8176
8177 return SANE_STATUS_GOOD;
8178 }
8179
8180
8181 /*---------- lineartfake_proc_data() -----------------------------------------*/
8182
8183 static SANE_Status
lineartfake_proc_data(Microtek2_Scanner * ms)8184 lineartfake_proc_data(Microtek2_Scanner *ms)
8185 {
8186 Microtek2_Device *md;
8187 Microtek2_Info *mi;
8188 SANE_Status status;
8189 uint8_t *from;
8190 int right_to_left;
8191
8192
8193 DBG(30, "lineartfake_proc_data: lines=%d, bpl=%d, ppl=%d, depth=%d\n",
8194 ms->src_lines_to_read, ms->bpl, ms->ppl, ms->depth);
8195
8196 md = ms->dev;
8197 mi = &md->info[md->scan_source];
8198 right_to_left = mi->direction & MI_DATSEQ_RTOL;
8199
8200 if ( right_to_left == 1 )
8201 from = ms->buf.src_buf + ms->ppl - 1;
8202 else
8203 from = ms->buf.src_buf;
8204
8205 do
8206 {
8207 status = lineartfake_copy_pixels(ms,
8208 from,
8209 ms->ppl,
8210 ms->threshold,
8211 right_to_left,
8212 ms->fp);
8213 if ( status != SANE_STATUS_GOOD )
8214 return status;
8215
8216 from += ms->bpl;
8217 --ms->src_lines_to_read;
8218 } while ( ms->src_lines_to_read > 0 );
8219
8220 return SANE_STATUS_GOOD;
8221 }
8222
8223 /*---------- lineartfake_copy_pixels() ---------------------------------------*/
8224
8225 static SANE_Status
lineartfake_copy_pixels(Microtek2_Scanner * ms,uint8_t * from,uint32_t pixels,uint8_t threshold,int right_to_left,FILE * fp)8226 lineartfake_copy_pixels(Microtek2_Scanner *ms,
8227 uint8_t *from,
8228 uint32_t pixels,
8229 uint8_t threshold,
8230 int right_to_left,
8231 FILE *fp)
8232 {
8233 Microtek2_Device *md;
8234 uint32_t pixel;
8235 uint32_t bit;
8236 uint8_t dest;
8237 uint8_t val;
8238 float s_d, s_w, maxval, shading_factor, grayval;
8239 int step;
8240
8241
8242 DBG(30, "lineartfake_copy_pixels: from=%p,pixels=%d,threshold=%d,file=%p\n",
8243 (void *) from, pixels, threshold, (void *) fp);
8244 md = ms->dev;
8245 bit = 0;
8246 dest = 0;
8247 step = right_to_left == 1 ? -1 : 1;
8248 maxval = 255.0;
8249 s_w = maxval;
8250 s_d = 0.0;
8251 shading_factor = (float) pow(2.0, (double) (md->shading_depth - 8) );
8252
8253 for ( pixel = 0; pixel < pixels; pixel++ )
8254 {
8255 if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
8256 && ( ms->condensed_shading_w != NULL ))
8257 /* apply shading by backend */
8258 {
8259 get_cshading_values(ms,
8260 0,
8261 pixel,
8262 shading_factor,
8263 right_to_left,
8264 &s_d,
8265 &s_w);
8266 }
8267 else /* no shading */
8268 {
8269 s_w = maxval;
8270 s_d = 0.0;
8271 }
8272
8273 grayval = (float) *from;
8274
8275 if ( grayval < s_d ) grayval = s_d;
8276 grayval = ( grayval - s_d ) * maxval / (s_w - s_d );
8277 grayval = MAX( 0.0, grayval );
8278 grayval = MIN( maxval, grayval );
8279
8280 if ( (uint8_t)grayval < threshold ) val = 1; else val = 0;
8281 dest = ( dest << 1 ) | val;
8282 bit = ( bit + 1 ) % 8;
8283 if ( bit == 0 ) /* 8 input bytes processed */
8284 {
8285 fputc((char) dest, fp);
8286 dest = 0;
8287 }
8288 from += step;
8289 }
8290
8291 if ( bit != 0 )
8292 {
8293 dest <<= 7 - bit;
8294 fputc((char) dest, fp);
8295 }
8296
8297 return SANE_STATUS_GOOD;
8298 }
8299
8300 /*---------- auto_adjust_proc_data() -----------------------------------------*/
8301
8302 static SANE_Status
auto_adjust_proc_data(Microtek2_Scanner * ms,uint8_t ** temp_current)8303 auto_adjust_proc_data(Microtek2_Scanner *ms, uint8_t **temp_current)
8304 {
8305 Microtek2_Device *md;
8306 Microtek2_Info *mi;
8307 SANE_Status status;
8308 uint8_t *from;
8309 uint32_t line;
8310 uint32_t lines;
8311 uint32_t pixel;
8312 uint32_t threshold;
8313 int right_to_left;
8314
8315
8316 DBG(30, "auto_adjust_proc_data: ms=%p, temp_current=%p\n",
8317 (void *) ms, (void *) *temp_current);
8318
8319 md = ms->dev;
8320 mi = &md->info[md->scan_source];
8321 right_to_left = mi->direction & MI_DATSEQ_RTOL;
8322
8323 memcpy(*temp_current, ms->buf.src_buf, ms->transfer_length);
8324 *temp_current += ms->transfer_length;
8325 threshold = 0;
8326 status = SANE_STATUS_GOOD;
8327
8328 if ( ms->src_remaining_lines == 0 ) /* we have read all the image data, */
8329 { /* calculate threshold value */
8330 for ( pixel = 0; pixel < ms->remaining_bytes; pixel++ )
8331 threshold += *(ms->temporary_buffer + pixel);
8332
8333 threshold /= ms->remaining_bytes;
8334 lines = ms->remaining_bytes / ms->bpl;
8335 for ( line = 0; line < lines; line++ )
8336 {
8337 from = ms->temporary_buffer + line * ms->bpl;
8338 if ( right_to_left == 1 )
8339 from += ms->ppl - 1;
8340 status = lineartfake_copy_pixels(ms,
8341 from,
8342 ms->ppl,
8343 (uint8_t) threshold,
8344 right_to_left,
8345 ms->fp);
8346 }
8347 *temp_current = NULL;
8348 }
8349
8350 return status;
8351 }
8352
8353 /*-------------- get_cshading_values -----------------------------------------*/
8354
8355 static SANE_Status
get_cshading_values(Microtek2_Scanner * ms,uint8_t color,uint32_t pixel,float shading_factor,int right_to_left,float * s_d,float * s_w)8356 get_cshading_values(Microtek2_Scanner *ms,
8357 uint8_t color,
8358 uint32_t pixel,
8359 float shading_factor,
8360 int right_to_left,
8361 float *s_d,
8362 float *s_w)
8363 {
8364 Microtek2_Device *md;
8365 uint32_t csh_offset;
8366
8367 md = ms->dev;
8368
8369 if ( right_to_left == 1 )
8370 csh_offset = (color + 1) * ms->ppl - 1 - pixel;
8371 else
8372 csh_offset = color * ms->ppl + pixel;
8373
8374 if ( ( md->shading_depth > 8 ) && ( ms->lut_entry_size == 2) )
8375 /* condensed shading is 2 byte color data */
8376 {
8377 if ( ms->condensed_shading_d != NULL )
8378 *s_d = (float) *( (uint16_t *)ms->condensed_shading_d
8379 + csh_offset );
8380 else
8381 *s_d = 0.0;
8382
8383 *s_w = (float) *( (uint16_t *)ms->condensed_shading_w
8384 + csh_offset );
8385 *s_w /= shading_factor;
8386 *s_d /= shading_factor;
8387 }
8388
8389 else
8390 /* condensed shading is 8 bit data */
8391 {
8392 *s_w = (float) *( ms->condensed_shading_w + csh_offset );
8393 if ( ms->condensed_shading_d != NULL )
8394 *s_d = (float) *( ms->condensed_shading_d + csh_offset );
8395 else
8396 *s_d = 0.0;
8397 }
8398 return SANE_STATUS_GOOD;
8399 }
8400