• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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