1141cc406Sopenharmony_ci/***************************************************************************
2141cc406Sopenharmony_ci * SANE - Scanner Access Now Easy.
3141cc406Sopenharmony_ci
4141cc406Sopenharmony_ci   microtek2.c
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file (C) 1998, 1999 Bernd Schroeder
7141cc406Sopenharmony_ci   modifications 2000, 2001 Karsten Festag
8141cc406Sopenharmony_ci
9141cc406Sopenharmony_ci   This file is part of the SANE package.
10141cc406Sopenharmony_ci
11141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
12141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
13141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
14141cc406Sopenharmony_ci   License, or (at your option) any later version.
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
17141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
18141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19141cc406Sopenharmony_ci   General Public License for more details.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
22141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
25141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
26141cc406Sopenharmony_ci
27141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
28141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
29141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
30141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
31141cc406Sopenharmony_ci   account of linking the SANE library code into it.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
34141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
35141cc406Sopenharmony_ci   License.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
38141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
39141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
42141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
43141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
44141cc406Sopenharmony_ci
45141cc406Sopenharmony_ci ***************************************************************************
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci   This file implements a SANE backend for Microtek scanners with
48141cc406Sopenharmony_ci   SCSI-2 command set.
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ci   (feedback to:  bernd@aquila.muc.de)
51141cc406Sopenharmony_ci   (              karsten.festag@t-online.de)
52141cc406Sopenharmony_ci ***************************************************************************/
53141cc406Sopenharmony_ci
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#ifdef _AIX
56141cc406Sopenharmony_ci# include <lalloca.h>   /* MUST come first for AIX! */
57141cc406Sopenharmony_ci#endif
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#include "../include/sane/config.h"
60141cc406Sopenharmony_ci#include "../include/lalloca.h"
61141cc406Sopenharmony_ci
62141cc406Sopenharmony_ci#include <stdio.h>
63141cc406Sopenharmony_ci#include <stdlib.h>
64141cc406Sopenharmony_ci#include <string.h>
65141cc406Sopenharmony_ci#include <unistd.h>
66141cc406Sopenharmony_ci#include <fcntl.h>
67141cc406Sopenharmony_ci#include <ctype.h>
68141cc406Sopenharmony_ci#include <sys/types.h>
69141cc406Sopenharmony_ci#include <signal.h>
70141cc406Sopenharmony_ci#include <errno.h>
71141cc406Sopenharmony_ci#include <math.h>
72141cc406Sopenharmony_ci
73141cc406Sopenharmony_ci#include "../include/_stdint.h"
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
76141cc406Sopenharmony_ci#include <sys/stat.h>
77141cc406Sopenharmony_ci#endif
78141cc406Sopenharmony_ci
79141cc406Sopenharmony_ci#include "../include/sane/sane.h"
80141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
81141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
82141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
83141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
84141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
85141cc406Sopenharmony_ci
86141cc406Sopenharmony_ci#ifndef TESTBACKEND
87141cc406Sopenharmony_ci#define BACKEND_NAME microtek2
88141cc406Sopenharmony_ci#else
89141cc406Sopenharmony_ci#define BACKEND_NAME microtek2_test
90141cc406Sopenharmony_ci#endif
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_ci/* for testing*/
93141cc406Sopenharmony_ci/*#define NO_PHANTOMTYPE_SHADING*/
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci#include "microtek2.h"
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
100141cc406Sopenharmony_cistatic SANE_Auth_Callback auth_callback;
101141cc406Sopenharmony_ci#endif
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_cistatic int md_num_devices = 0;          /* number of devices from config file */
104141cc406Sopenharmony_cistatic Microtek2_Device *md_first_dev = NULL;        /* list of known devices */
105141cc406Sopenharmony_cistatic Microtek2_Scanner *ms_first_handle = NULL;    /* list of open scanners */
106141cc406Sopenharmony_ci
107141cc406Sopenharmony_ci/* options that can be configured in the config file */
108141cc406Sopenharmony_cistatic Config_Options md_options =
109141cc406Sopenharmony_ci                               { 1.0, "off", "off", "off", "off", "off", "off"};
110141cc406Sopenharmony_cistatic Config_Temp *md_config_temp = NULL;
111141cc406Sopenharmony_cistatic int md_dump = 0;                 /* from config file: */
112141cc406Sopenharmony_ci                                        /* 1: inquiry + scanner attributes */
113141cc406Sopenharmony_ci                                        /* 2: + all scsi commands and data */
114141cc406Sopenharmony_ci                                        /* 3: + all scan data */
115141cc406Sopenharmony_cistatic int md_dump_clear = 1;
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci/*---------- sane_cancel() ---------------------------------------------------*/
119141cc406Sopenharmony_ci
120141cc406Sopenharmony_civoid
121141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
122141cc406Sopenharmony_ci{
123141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci    DBG(30, "sane_cancel: handle=%p\n", handle);
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci    if ( ms->scanning == SANE_TRUE )
128141cc406Sopenharmony_ci        cleanup_scanner(ms);
129141cc406Sopenharmony_ci    ms->cancelled = SANE_TRUE;
130141cc406Sopenharmony_ci    ms->fd[0] = ms->fd[1] = -1;
131141cc406Sopenharmony_ci}
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci/*---------- sane_close() ----------------------------------------------------*/
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_civoid
138141cc406Sopenharmony_cisane_close (SANE_Handle handle)
139141cc406Sopenharmony_ci{
140141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci    DBG(30, "sane_close: ms=%p\n", (void *) ms);
143141cc406Sopenharmony_ci
144141cc406Sopenharmony_ci    if ( ! ms )
145141cc406Sopenharmony_ci        return;
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_ci    /* free malloc'ed stuff */
148141cc406Sopenharmony_ci    cleanup_scanner(ms);
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci    /* remove Scanner from linked list */
151141cc406Sopenharmony_ci    if ( ms_first_handle == ms )
152141cc406Sopenharmony_ci        ms_first_handle = ms->next;
153141cc406Sopenharmony_ci    else
154141cc406Sopenharmony_ci      {
155141cc406Sopenharmony_ci        Microtek2_Scanner *ts = ms_first_handle;
156141cc406Sopenharmony_ci        while ( (ts != NULL) && (ts->next != ms) )
157141cc406Sopenharmony_ci            ts = ts->next;
158141cc406Sopenharmony_ci        ts->next = ts->next->next; /* == ms->next */
159141cc406Sopenharmony_ci      }
160141cc406Sopenharmony_ci    DBG(100, "free ms at %p\n", (void *) ms);
161141cc406Sopenharmony_ci    free((void *) ms);
162141cc406Sopenharmony_ci    ms = NULL;
163141cc406Sopenharmony_ci}
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci/*---------- sane_exit() -----------------------------------------------------*/
167141cc406Sopenharmony_ci
168141cc406Sopenharmony_civoid
169141cc406Sopenharmony_cisane_exit (void)
170141cc406Sopenharmony_ci{
171141cc406Sopenharmony_ci    Microtek2_Device *next;
172141cc406Sopenharmony_ci    int i;
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ci    DBG(30, "sane_exit:\n");
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci    /* close all leftover Scanners */
177141cc406Sopenharmony_ci    while (ms_first_handle != NULL)
178141cc406Sopenharmony_ci        sane_close(ms_first_handle);
179141cc406Sopenharmony_ci    /* free up device list */
180141cc406Sopenharmony_ci    while (md_first_dev != NULL)
181141cc406Sopenharmony_ci      {
182141cc406Sopenharmony_ci        next = md_first_dev->next;
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci        for ( i = 0; i < 4; i++ )
185141cc406Sopenharmony_ci          {
186141cc406Sopenharmony_ci            if ( md_first_dev->custom_gamma_table[i] )
187141cc406Sopenharmony_ci              {
188141cc406Sopenharmony_ci                DBG(100, "free md_first_dev->custom_gamma_table[%d] at %p\n",
189141cc406Sopenharmony_ci                          i, (void *) md_first_dev->custom_gamma_table[i]);
190141cc406Sopenharmony_ci                free((void *) md_first_dev->custom_gamma_table[i]);
191141cc406Sopenharmony_ci                md_first_dev->custom_gamma_table[i] = NULL;
192141cc406Sopenharmony_ci              }
193141cc406Sopenharmony_ci          }
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci        if ( md_first_dev->shading_table_w )
196141cc406Sopenharmony_ci          {
197141cc406Sopenharmony_ci            DBG(100, "free md_first_dev->shading_table_w at %p\n",
198141cc406Sopenharmony_ci                      (void *) md_first_dev->shading_table_w);
199141cc406Sopenharmony_ci            free((void *) md_first_dev->shading_table_w);
200141cc406Sopenharmony_ci            md_first_dev->shading_table_w = NULL;
201141cc406Sopenharmony_ci          }
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci        if ( md_first_dev->shading_table_d )
204141cc406Sopenharmony_ci          {
205141cc406Sopenharmony_ci            DBG(100, "free md_first_dev->shading_table_d at %p\n",
206141cc406Sopenharmony_ci                      (void *) md_first_dev->shading_table_d);
207141cc406Sopenharmony_ci            free((void *) md_first_dev->shading_table_d);
208141cc406Sopenharmony_ci            md_first_dev->shading_table_d = NULL;
209141cc406Sopenharmony_ci          }
210141cc406Sopenharmony_ci
211141cc406Sopenharmony_ci        DBG(100, "free md_first_dev at %p\n", (void *) md_first_dev);
212141cc406Sopenharmony_ci        free((void *) md_first_dev);
213141cc406Sopenharmony_ci        md_first_dev = next;
214141cc406Sopenharmony_ci      }
215141cc406Sopenharmony_ci    sane_get_devices(NULL, SANE_FALSE);     /* free list of SANE_Devices */
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci    DBG(30, "sane_exit: MICROTEK2 says goodbye.\n");
218141cc406Sopenharmony_ci}
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci/*---------- sane_get_devices()-----------------------------------------------*/
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ciSANE_Status
224141cc406Sopenharmony_cisane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
225141cc406Sopenharmony_ci{
226141cc406Sopenharmony_ci    /* return a list of available devices; available here means that we get */
227141cc406Sopenharmony_ci    /* a positive response to an 'INQUIRY' and possibly to a */
228141cc406Sopenharmony_ci    /* 'READ SCANNER ATTRIBUTE' call */
229141cc406Sopenharmony_ci
230141cc406Sopenharmony_ci    static const SANE_Device **sd_list = NULL;
231141cc406Sopenharmony_ci    Microtek2_Device *md;
232141cc406Sopenharmony_ci    SANE_Status status;
233141cc406Sopenharmony_ci    int index;
234141cc406Sopenharmony_ci
235141cc406Sopenharmony_ci    DBG(30, "sane_get_devices: local_only=%d\n", local_only);
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci    /* this is hack to get the list freed with a call from sane_exit() */
238141cc406Sopenharmony_ci    if ( device_list == NULL )
239141cc406Sopenharmony_ci      {
240141cc406Sopenharmony_ci        if ( sd_list )
241141cc406Sopenharmony_ci          {
242141cc406Sopenharmony_ci            DBG(100, "free sd_list at %p\n", (void *) sd_list);
243141cc406Sopenharmony_ci            free(sd_list);
244141cc406Sopenharmony_ci            sd_list=NULL;
245141cc406Sopenharmony_ci          }
246141cc406Sopenharmony_ci        DBG(30, "sane_get_devices: sd_list_freed\n");
247141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
248141cc406Sopenharmony_ci      }
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci    /* first free old list, if there is one; frontend wants a new list */
251141cc406Sopenharmony_ci    if ( sd_list )
252141cc406Sopenharmony_ci      {
253141cc406Sopenharmony_ci        DBG(100, "free sd_list at %p\n", (void *) sd_list);
254141cc406Sopenharmony_ci        free(sd_list);                            /* free array of pointers */
255141cc406Sopenharmony_ci      }
256141cc406Sopenharmony_ci
257141cc406Sopenharmony_ci    sd_list = (const SANE_Device **)
258141cc406Sopenharmony_ci               malloc( (md_num_devices + 1) * sizeof(SANE_Device **));
259141cc406Sopenharmony_ci    DBG(100, "sane_get_devices: sd_list=%p, malloc'd %lu bytes\n",
260141cc406Sopenharmony_ci	(void *) sd_list, (u_long)  ((md_num_devices + 1) * sizeof(SANE_Device **)));
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci    if ( ! sd_list )
263141cc406Sopenharmony_ci      {
264141cc406Sopenharmony_ci        DBG(1, "sane_get_devices: malloc() for sd_list failed\n");
265141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
266141cc406Sopenharmony_ci      }
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci    *device_list = sd_list;
269141cc406Sopenharmony_ci    index = 0;
270141cc406Sopenharmony_ci    md = md_first_dev;
271141cc406Sopenharmony_ci    while ( md )
272141cc406Sopenharmony_ci      {
273141cc406Sopenharmony_ci        status = attach(md);
274141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
275141cc406Sopenharmony_ci          {
276141cc406Sopenharmony_ci            DBG(10, "sane_get_devices: attach status '%s'\n",
277141cc406Sopenharmony_ci                     sane_strstatus(status));
278141cc406Sopenharmony_ci            md = md->next;
279141cc406Sopenharmony_ci            continue;
280141cc406Sopenharmony_ci          }
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci        /* check whether unit is ready, if so add it to the list */
283141cc406Sopenharmony_ci        status = scsi_test_unit_ready(md);
284141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
285141cc406Sopenharmony_ci          {
286141cc406Sopenharmony_ci            DBG(10, "sane_get_devices: test_unit_ready status '%s'\n",
287141cc406Sopenharmony_ci                     sane_strstatus(status));
288141cc406Sopenharmony_ci            md = md->next;
289141cc406Sopenharmony_ci            continue;
290141cc406Sopenharmony_ci          }
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci        sd_list[index] = &md->sane;
293141cc406Sopenharmony_ci
294141cc406Sopenharmony_ci        ++index;
295141cc406Sopenharmony_ci        md = md->next;
296141cc406Sopenharmony_ci      }
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci    sd_list[index] = NULL;
299141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
300141cc406Sopenharmony_ci}
301141cc406Sopenharmony_ci
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci/*---------- sane_get_parameters() -------------------------------------------*/
304141cc406Sopenharmony_ci
305141cc406Sopenharmony_ciSANE_Status
306141cc406Sopenharmony_cisane_get_parameters(SANE_Handle handle, SANE_Parameters *params)
307141cc406Sopenharmony_ci{
308141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
309141cc406Sopenharmony_ci    Microtek2_Device *md;
310141cc406Sopenharmony_ci    Option_Value *val;
311141cc406Sopenharmony_ci    Microtek2_Info *mi;
312141cc406Sopenharmony_ci    int mode;
313141cc406Sopenharmony_ci    int depth;
314141cc406Sopenharmony_ci    int bits_pp_in;             /* bits per pixel from scanner */
315141cc406Sopenharmony_ci    int bits_pp_out;            /* bits_per_pixel transferred to frontend */
316141cc406Sopenharmony_ci    int bytes_per_line;
317141cc406Sopenharmony_ci    double x_pixel_per_mm;
318141cc406Sopenharmony_ci    double y_pixel_per_mm;
319141cc406Sopenharmony_ci    double x1_pixel;
320141cc406Sopenharmony_ci    double y1_pixel;
321141cc406Sopenharmony_ci    double width_pixel;
322141cc406Sopenharmony_ci    double height_pixel;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci
325141cc406Sopenharmony_ci    DBG(40, "sane_get_parameters: handle=%p, params=%p\n", handle,
326141cc406Sopenharmony_ci	(void *) params);
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci
329141cc406Sopenharmony_ci    md = ms->dev;
330141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
331141cc406Sopenharmony_ci    val= ms->val;
332141cc406Sopenharmony_ci
333141cc406Sopenharmony_ci    if ( ! ms->scanning )            /* get an estimate for the params */
334141cc406Sopenharmony_ci      {
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci        get_scan_mode_and_depth(ms, &mode, &depth, &bits_pp_in, &bits_pp_out);
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci        switch ( mode )
339141cc406Sopenharmony_ci          {
340141cc406Sopenharmony_ci            case MS_MODE_COLOR:
341141cc406Sopenharmony_ci              if ( mi->onepass )
342141cc406Sopenharmony_ci                {
343141cc406Sopenharmony_ci                  ms->params.format = SANE_FRAME_RGB;
344141cc406Sopenharmony_ci                  ms->params.last_frame = SANE_TRUE;
345141cc406Sopenharmony_ci                }
346141cc406Sopenharmony_ci              else
347141cc406Sopenharmony_ci                {
348141cc406Sopenharmony_ci                  ms->params.format = SANE_FRAME_RED;
349141cc406Sopenharmony_ci                  ms->params.last_frame = SANE_FALSE;
350141cc406Sopenharmony_ci                }
351141cc406Sopenharmony_ci              break;
352141cc406Sopenharmony_ci            case MS_MODE_GRAY:
353141cc406Sopenharmony_ci            case MS_MODE_HALFTONE:
354141cc406Sopenharmony_ci            case MS_MODE_LINEART:
355141cc406Sopenharmony_ci            case MS_MODE_LINEARTFAKE:
356141cc406Sopenharmony_ci              ms->params.format = SANE_FRAME_GRAY;
357141cc406Sopenharmony_ci              ms->params.last_frame = SANE_TRUE;
358141cc406Sopenharmony_ci              break;
359141cc406Sopenharmony_ci            default:
360141cc406Sopenharmony_ci              DBG(1, "sane_get_parameters: Unknown scan mode %d\n", mode);
361141cc406Sopenharmony_ci              break;
362141cc406Sopenharmony_ci          }
363141cc406Sopenharmony_ci
364141cc406Sopenharmony_ci      ms->params.depth = (SANE_Int) bits_pp_out;
365141cc406Sopenharmony_ci
366141cc406Sopenharmony_ci      /* calculate lines, pixels per line and bytes per line */
367141cc406Sopenharmony_ci      if ( val[OPT_RESOLUTION_BIND].w == SANE_TRUE )
368141cc406Sopenharmony_ci        {
369141cc406Sopenharmony_ci          x_pixel_per_mm = y_pixel_per_mm =
370141cc406Sopenharmony_ci                SANE_UNFIX(val[OPT_RESOLUTION].w) / MM_PER_INCH;
371141cc406Sopenharmony_ci          DBG(30, "sane_get_parameters: x_res=y_res=%f\n",
372141cc406Sopenharmony_ci                  SANE_UNFIX(val[OPT_RESOLUTION].w));
373141cc406Sopenharmony_ci        }
374141cc406Sopenharmony_ci      else
375141cc406Sopenharmony_ci        {
376141cc406Sopenharmony_ci          x_pixel_per_mm = SANE_UNFIX(val[OPT_RESOLUTION].w) / MM_PER_INCH;
377141cc406Sopenharmony_ci          y_pixel_per_mm = SANE_UNFIX(val[OPT_Y_RESOLUTION].w) / MM_PER_INCH;
378141cc406Sopenharmony_ci          DBG(30, "sane_get_parameters: x_res=%f, y_res=%f\n",
379141cc406Sopenharmony_ci                  SANE_UNFIX(val[OPT_RESOLUTION].w),
380141cc406Sopenharmony_ci                  SANE_UNFIX(val[OPT_Y_RESOLUTION].w));
381141cc406Sopenharmony_ci        }
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci      DBG(30, "sane_get_parameters: x_ppm=%f, y_ppm=%f\n",
384141cc406Sopenharmony_ci               x_pixel_per_mm, y_pixel_per_mm);
385141cc406Sopenharmony_ci
386141cc406Sopenharmony_ci      y1_pixel = SANE_UNFIX(ms->val[OPT_TL_Y].w) * y_pixel_per_mm;
387141cc406Sopenharmony_ci      height_pixel = fabs(SANE_UNFIX(ms->val[OPT_BR_Y].w) * y_pixel_per_mm
388141cc406Sopenharmony_ci                          - y1_pixel) + 0.5;
389141cc406Sopenharmony_ci      ms->params.lines = (SANE_Int) height_pixel;
390141cc406Sopenharmony_ci
391141cc406Sopenharmony_ci      x1_pixel =  SANE_UNFIX(ms->val[OPT_TL_X].w) * x_pixel_per_mm;
392141cc406Sopenharmony_ci      width_pixel = fabs(SANE_UNFIX(ms->val[OPT_BR_X].w) * x_pixel_per_mm
393141cc406Sopenharmony_ci                         - x1_pixel) + 0.5;
394141cc406Sopenharmony_ci      ms->params.pixels_per_line = (SANE_Int) width_pixel;
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci      if ( bits_pp_out == 1 )
398141cc406Sopenharmony_ci          bytes_per_line =  (width_pixel + 7 ) / 8;
399141cc406Sopenharmony_ci      else
400141cc406Sopenharmony_ci        {
401141cc406Sopenharmony_ci          bytes_per_line = ( width_pixel * bits_pp_out ) / 8 ;
402141cc406Sopenharmony_ci          if ( mode == MS_MODE_COLOR && mi->onepass )
403141cc406Sopenharmony_ci              bytes_per_line *= 3;
404141cc406Sopenharmony_ci        }
405141cc406Sopenharmony_ci      ms->params.bytes_per_line = (SANE_Int) bytes_per_line;
406141cc406Sopenharmony_ci    }  /* if ms->scanning */
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  if ( params )
409141cc406Sopenharmony_ci     *params = ms->params;
410141cc406Sopenharmony_ci
411141cc406Sopenharmony_ci  DBG(30,"sane_get_parameters: format=%d, last_frame=%d, lines=%d\n",
412141cc406Sopenharmony_ci        ms->params.format,ms->params.last_frame, ms->params.lines);
413141cc406Sopenharmony_ci  DBG(30,"sane_get_parameters: depth=%d, ppl=%d, bpl=%d\n",
414141cc406Sopenharmony_ci        ms->params.depth,ms->params.pixels_per_line, ms->params.bytes_per_line);
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
417141cc406Sopenharmony_ci}
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci/*---------- sane_get_select_fd() --------------------------------------------*/
421141cc406Sopenharmony_ci
422141cc406Sopenharmony_ciSANE_Status
423141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int *fd)
424141cc406Sopenharmony_ci{
425141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
426141cc406Sopenharmony_ci
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci    DBG(30, "sane_get_select_fd: ms=%p\n", (void *) ms);
429141cc406Sopenharmony_ci
430141cc406Sopenharmony_ci    if ( ! ms->scanning )
431141cc406Sopenharmony_ci      {
432141cc406Sopenharmony_ci        DBG(1, "sane_get_select_fd: Scanner not scanning\n");
433141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
434141cc406Sopenharmony_ci      }
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci    *fd = (SANE_Int) ms->fd[0];
437141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
438141cc406Sopenharmony_ci}
439141cc406Sopenharmony_ci
440141cc406Sopenharmony_ci
441141cc406Sopenharmony_ci/*---------- sane_init() -----------------------------------------------------*/
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ciSANE_Status
444141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
445141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
446141cc406Sopenharmony_ci#else
447141cc406Sopenharmony_cisane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
448141cc406Sopenharmony_ci#endif
449141cc406Sopenharmony_ci{
450141cc406Sopenharmony_ci    Microtek2_Device *md;
451141cc406Sopenharmony_ci    FILE *fp;
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci
454141cc406Sopenharmony_ci    DBG_INIT();
455141cc406Sopenharmony_ci    DBG(1, "sane_init: Microtek2 (v%d.%d build %s) says hello...\n",
456141cc406Sopenharmony_ci           MICROTEK2_MAJOR, MICROTEK2_MINOR, MICROTEK2_BUILD);
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci    if ( version_code )
459141cc406Sopenharmony_ci        *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0);
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
462141cc406Sopenharmony_ci    auth_callback = authorize;
463141cc406Sopenharmony_ci#endif
464141cc406Sopenharmony_ci
465141cc406Sopenharmony_ci    sanei_thread_init();
466141cc406Sopenharmony_ci
467141cc406Sopenharmony_ci    fp = sanei_config_open(MICROTEK2_CONFIG_FILE);
468141cc406Sopenharmony_ci    if ( fp == NULL )
469141cc406Sopenharmony_ci        DBG(10, "sane_init: file not opened: '%s'\n", MICROTEK2_CONFIG_FILE);
470141cc406Sopenharmony_ci    else
471141cc406Sopenharmony_ci      {
472141cc406Sopenharmony_ci        /* check config file for devices and associated options */
473141cc406Sopenharmony_ci        parse_config_file(fp, &md_config_temp);
474141cc406Sopenharmony_ci
475141cc406Sopenharmony_ci        while ( md_config_temp )
476141cc406Sopenharmony_ci          {
477141cc406Sopenharmony_ci            sanei_config_attach_matching_devices(md_config_temp->device,
478141cc406Sopenharmony_ci                                                 attach_one);
479141cc406Sopenharmony_ci            if ( md_config_temp->next )  /* go to next device, if existent */
480141cc406Sopenharmony_ci                md_config_temp = md_config_temp->next;
481141cc406Sopenharmony_ci            else
482141cc406Sopenharmony_ci                break;
483141cc406Sopenharmony_ci          }
484141cc406Sopenharmony_ci
485141cc406Sopenharmony_ci        fclose(fp);
486141cc406Sopenharmony_ci      }
487141cc406Sopenharmony_ci
488141cc406Sopenharmony_ci    if ( md_first_dev == NULL )
489141cc406Sopenharmony_ci      {
490141cc406Sopenharmony_ci        /* config file not found or no valid entry; default to /dev/scanner */
491141cc406Sopenharmony_ci        /* instead of insisting on config file */
492141cc406Sopenharmony_ci	add_device_list("/dev/scanner", &md);
493141cc406Sopenharmony_ci        if ( md )
494141cc406Sopenharmony_ci	    attach(md);
495141cc406Sopenharmony_ci      }
496141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
497141cc406Sopenharmony_ci}
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci
500141cc406Sopenharmony_ci/*---------- sane_open() -----------------------------------------------------*/
501141cc406Sopenharmony_ci
502141cc406Sopenharmony_ciSANE_Status
503141cc406Sopenharmony_cisane_open(SANE_String_Const name, SANE_Handle *handle)
504141cc406Sopenharmony_ci{
505141cc406Sopenharmony_ci    SANE_Status status;
506141cc406Sopenharmony_ci    Microtek2_Scanner *ms;
507141cc406Sopenharmony_ci    Microtek2_Device *md;
508141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
509141cc406Sopenharmony_ci    struct stat st;
510141cc406Sopenharmony_ci    int rc;
511141cc406Sopenharmony_ci#endif
512141cc406Sopenharmony_ci
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci    DBG(30, "sane_open: device='%s'\n", name);
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci    *handle = NULL;
517141cc406Sopenharmony_ci    md = md_first_dev;
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci    if ( name )
520141cc406Sopenharmony_ci      {
521141cc406Sopenharmony_ci        /* add_device_list() returns a pointer to the device struct if */
522141cc406Sopenharmony_ci        /* the device is known or newly added, else it returns NULL */
523141cc406Sopenharmony_ci
524141cc406Sopenharmony_ci        status = add_device_list(name, &md);
525141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
526141cc406Sopenharmony_ci            return status;
527141cc406Sopenharmony_ci      }
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci    if ( ! md )
530141cc406Sopenharmony_ci      {
531141cc406Sopenharmony_ci        DBG(10, "sane_open: invalid device name '%s'\n", name);
532141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
533141cc406Sopenharmony_ci      }
534141cc406Sopenharmony_ci
535141cc406Sopenharmony_ci    /* attach calls INQUIRY and READ SCANNER ATTRIBUTES */
536141cc406Sopenharmony_ci    status = attach(md);
537141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
538141cc406Sopenharmony_ci        return status;
539141cc406Sopenharmony_ci
540141cc406Sopenharmony_ci    ms = malloc(sizeof(Microtek2_Scanner));
541141cc406Sopenharmony_ci    DBG(100, "sane_open: ms=%p, malloc'd %lu bytes\n",
542141cc406Sopenharmony_ci	(void *) ms, (u_long) sizeof(Microtek2_Scanner));
543141cc406Sopenharmony_ci    if ( ms == NULL )
544141cc406Sopenharmony_ci      {
545141cc406Sopenharmony_ci        DBG(1, "sane_open: malloc() for ms failed\n");
546141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
547141cc406Sopenharmony_ci      }
548141cc406Sopenharmony_ci
549141cc406Sopenharmony_ci    memset(ms, 0, sizeof(Microtek2_Scanner));
550141cc406Sopenharmony_ci    ms->dev = md;
551141cc406Sopenharmony_ci    ms->scanning = SANE_FALSE;
552141cc406Sopenharmony_ci    ms->cancelled = SANE_FALSE;
553141cc406Sopenharmony_ci    ms->current_pass = 0;
554141cc406Sopenharmony_ci    ms->sfd = -1;
555141cc406Sopenharmony_ci    sanei_thread_initialize(ms->pid);
556141cc406Sopenharmony_ci    ms->fp = NULL;
557141cc406Sopenharmony_ci    ms->gamma_table = NULL;
558141cc406Sopenharmony_ci    ms->buf.src_buf = ms->buf.src_buffer[0] = ms->buf.src_buffer[1] = NULL;
559141cc406Sopenharmony_ci    ms->control_bytes = NULL;
560141cc406Sopenharmony_ci    ms->shading_image = NULL;
561141cc406Sopenharmony_ci    ms->condensed_shading_w = NULL;
562141cc406Sopenharmony_ci    ms->condensed_shading_d = NULL;
563141cc406Sopenharmony_ci    ms->current_color = MS_COLOR_ALL;
564141cc406Sopenharmony_ci    ms->current_read_color = MS_COLOR_RED;
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci    init_options(ms, MD_SOURCE_FLATBED);
567141cc406Sopenharmony_ci
568141cc406Sopenharmony_ci    /* insert scanner into linked list */
569141cc406Sopenharmony_ci    ms->next = ms_first_handle;
570141cc406Sopenharmony_ci    ms_first_handle = ms;
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci    *handle = ms;
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
575141cc406Sopenharmony_ci    /* check whether the file with the passwords exists. If it doesn't */
576141cc406Sopenharmony_ci    /* exist, we don't use any authorization */
577141cc406Sopenharmony_ci
578141cc406Sopenharmony_ci    rc = stat(PASSWD_FILE, &st);
579141cc406Sopenharmony_ci    if ( rc == -1 && errno == ENOENT )
580141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
581141cc406Sopenharmony_ci    else
582141cc406Sopenharmony_ci      {
583141cc406Sopenharmony_ci        status = do_authorization(md->name);
584141cc406Sopenharmony_ci        return status;
585141cc406Sopenharmony_ci      }
586141cc406Sopenharmony_ci#else
587141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
588141cc406Sopenharmony_ci#endif
589141cc406Sopenharmony_ci}
590141cc406Sopenharmony_ci
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci/*---------- sane_read() -----------------------------------------------------*/
593141cc406Sopenharmony_ci
594141cc406Sopenharmony_ciSANE_Status
595141cc406Sopenharmony_cisane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len )
596141cc406Sopenharmony_ci{
597141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
598141cc406Sopenharmony_ci    SANE_Status status;
599141cc406Sopenharmony_ci    ssize_t nread;
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci
602141cc406Sopenharmony_ci    DBG(30, "sane_read: handle=%p, buf=%p, maxlen=%d\n",
603141cc406Sopenharmony_ci             handle, (void *) buf, maxlen);
604141cc406Sopenharmony_ci
605141cc406Sopenharmony_ci    *len = 0;
606141cc406Sopenharmony_ci
607141cc406Sopenharmony_ci    if ( ! ms->scanning || ms->cancelled )
608141cc406Sopenharmony_ci      {
609141cc406Sopenharmony_ci        if ( ms->cancelled )
610141cc406Sopenharmony_ci          {
611141cc406Sopenharmony_ci            status = SANE_STATUS_CANCELLED;
612141cc406Sopenharmony_ci          }
613141cc406Sopenharmony_ci        else
614141cc406Sopenharmony_ci          {
615141cc406Sopenharmony_ci            DBG(15, "sane_read: Scanner %p not scanning\n", (void *) ms);
616141cc406Sopenharmony_ci            status = SANE_STATUS_IO_ERROR;
617141cc406Sopenharmony_ci          }
618141cc406Sopenharmony_ci        DBG(15, "sane_read: scan cancelled or scanner not scanning->cleanup\n");
619141cc406Sopenharmony_ci        cleanup_scanner(ms);
620141cc406Sopenharmony_ci        return status;
621141cc406Sopenharmony_ci      }
622141cc406Sopenharmony_ci
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci    nread = read(ms->fd[0], (void *) buf, (int) maxlen);
625141cc406Sopenharmony_ci    if ( nread == -1 )
626141cc406Sopenharmony_ci      {
627141cc406Sopenharmony_ci        if ( errno == EAGAIN )
628141cc406Sopenharmony_ci          {
629141cc406Sopenharmony_ci            DBG(30, "sane_read: currently no data available\n");
630141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
631141cc406Sopenharmony_ci          }
632141cc406Sopenharmony_ci        else
633141cc406Sopenharmony_ci          {
634141cc406Sopenharmony_ci            DBG(1, "sane_read: read() failed, errno=%d\n", errno);
635141cc406Sopenharmony_ci            cleanup_scanner(ms);
636141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
637141cc406Sopenharmony_ci          }
638141cc406Sopenharmony_ci      }
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci    if ( nread == 0 )
641141cc406Sopenharmony_ci      {
642141cc406Sopenharmony_ci         DBG(15, "sane_read: read 0 bytes -> EOF\n");
643141cc406Sopenharmony_ci         ms->scanning = SANE_FALSE;
644141cc406Sopenharmony_ci         cleanup_scanner(ms);
645141cc406Sopenharmony_ci         return SANE_STATUS_EOF;
646141cc406Sopenharmony_ci      }
647141cc406Sopenharmony_ci
648141cc406Sopenharmony_ci
649141cc406Sopenharmony_ci    *len = (SANE_Int) nread;
650141cc406Sopenharmony_ci    DBG(30, "sane_read: *len=%d\n", *len);
651141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
652141cc406Sopenharmony_ci}
653141cc406Sopenharmony_ci
654141cc406Sopenharmony_ci
655141cc406Sopenharmony_ci/*---------- sane_set_io_mode() ---------------------------------------------*/
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ciSANE_Status
658141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
659141cc406Sopenharmony_ci{
660141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
661141cc406Sopenharmony_ci    int rc;
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci
664141cc406Sopenharmony_ci    DBG(30, "sane_set_io_mode: handle=%p, nonblocking=%d\n",
665141cc406Sopenharmony_ci             handle, non_blocking);
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci    if ( ! ms->scanning )
668141cc406Sopenharmony_ci      {
669141cc406Sopenharmony_ci        DBG(1, "sane_set_io_mode: Scanner not scanning\n");
670141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
671141cc406Sopenharmony_ci      }
672141cc406Sopenharmony_ci
673141cc406Sopenharmony_ci    rc = fcntl(ms->fd[0], F_SETFL, non_blocking ? O_NONBLOCK : 0);
674141cc406Sopenharmony_ci    if ( rc == -1 )
675141cc406Sopenharmony_ci      {
676141cc406Sopenharmony_ci        DBG(1, "sane_set_io_mode: fcntl() failed\n");
677141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
678141cc406Sopenharmony_ci      }
679141cc406Sopenharmony_ci
680141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
681141cc406Sopenharmony_ci}
682141cc406Sopenharmony_ci
683141cc406Sopenharmony_ci/*---------- add_device_list() -----------------------------------------------*/
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_cistatic SANE_Status
686141cc406Sopenharmony_ciadd_device_list(SANE_String_Const dev_name, Microtek2_Device **mdev)
687141cc406Sopenharmony_ci{
688141cc406Sopenharmony_ci    Microtek2_Device *md;
689141cc406Sopenharmony_ci    SANE_String hdev;
690141cc406Sopenharmony_ci    size_t len;
691141cc406Sopenharmony_ci
692141cc406Sopenharmony_ci
693141cc406Sopenharmony_ci    if ( (hdev = strdup(dev_name)) == NULL)
694141cc406Sopenharmony_ci      {
695141cc406Sopenharmony_ci	DBG(5, "add_device_list: malloc() for hdev failed\n");
696141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
697141cc406Sopenharmony_ci      }
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci    len = strlen(hdev);
700141cc406Sopenharmony_ci    if ( hdev[len - 1] == '\n' )
701141cc406Sopenharmony_ci        hdev[--len] = '\0';
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci    DBG(30, "add_device_list: device='%s'\n", hdev);
704141cc406Sopenharmony_ci
705141cc406Sopenharmony_ci    /* check, if device is already known */
706141cc406Sopenharmony_ci    md = md_first_dev;
707141cc406Sopenharmony_ci    while ( md )
708141cc406Sopenharmony_ci      {
709141cc406Sopenharmony_ci        if ( strcmp(hdev, md->name) == 0 )
710141cc406Sopenharmony_ci          {
711141cc406Sopenharmony_ci	    DBG(30, "add_device_list: device '%s' already in list\n", hdev);
712141cc406Sopenharmony_ci
713141cc406Sopenharmony_ci            *mdev = md;
714141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
715141cc406Sopenharmony_ci          }
716141cc406Sopenharmony_ci        md = md->next;
717141cc406Sopenharmony_ci    }
718141cc406Sopenharmony_ci
719141cc406Sopenharmony_ci    md = (Microtek2_Device *) malloc(sizeof(Microtek2_Device));
720141cc406Sopenharmony_ci    DBG(100, "add_device_list: md=%p, malloc'd %lu bytes\n",
721141cc406Sopenharmony_ci                         (void *) md, (u_long) sizeof(Microtek2_Device));
722141cc406Sopenharmony_ci    if ( md == NULL )
723141cc406Sopenharmony_ci      {
724141cc406Sopenharmony_ci	DBG(1, "add_device_list: malloc() for md failed\n");
725141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
726141cc406Sopenharmony_ci      }
727141cc406Sopenharmony_ci
728141cc406Sopenharmony_ci    /* initialize Device and add it at the beginning of the list */
729141cc406Sopenharmony_ci    memset(md, 0, sizeof(Microtek2_Device));
730141cc406Sopenharmony_ci    md->next = md_first_dev;
731141cc406Sopenharmony_ci    md_first_dev = md;
732141cc406Sopenharmony_ci    md->sane.name = NULL;
733141cc406Sopenharmony_ci    md->sane.vendor = NULL;
734141cc406Sopenharmony_ci    md->sane.model = NULL;
735141cc406Sopenharmony_ci    md->sane.type = NULL;
736141cc406Sopenharmony_ci    md->scan_source = MD_SOURCE_FLATBED;
737141cc406Sopenharmony_ci    md->shading_table_w = NULL;
738141cc406Sopenharmony_ci    md->shading_table_d = NULL;
739141cc406Sopenharmony_ci    strncpy(md->name, hdev, PATH_MAX - 1);
740141cc406Sopenharmony_ci    if ( md_config_temp )
741141cc406Sopenharmony_ci        md->opts = md_config_temp->opts;
742141cc406Sopenharmony_ci    else
743141cc406Sopenharmony_ci        md->opts = md_options;
744141cc406Sopenharmony_ci    ++md_num_devices;
745141cc406Sopenharmony_ci    *mdev = md;
746141cc406Sopenharmony_ci    DBG(100, "free hdev at %p\n", (void *) hdev);
747141cc406Sopenharmony_ci    free(hdev);
748141cc406Sopenharmony_ci
749141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
750141cc406Sopenharmony_ci}
751141cc406Sopenharmony_ci
752141cc406Sopenharmony_ci/*---------- attach() --------------------------------------------------------*/
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_cistatic SANE_Status
755141cc406Sopenharmony_ciattach(Microtek2_Device *md)
756141cc406Sopenharmony_ci{
757141cc406Sopenharmony_ci    /* This function is called from sane_init() to do the inquiry and to read */
758141cc406Sopenharmony_ci    /* the scanner attributes. If one of these calls fails, or if a new */
759141cc406Sopenharmony_ci    /* device is passed in sane_open() this function may also be called */
760141cc406Sopenharmony_ci    /* from sane_open() or sane_get_devices(). */
761141cc406Sopenharmony_ci
762141cc406Sopenharmony_ci    SANE_String model_string;
763141cc406Sopenharmony_ci    SANE_Status status;
764141cc406Sopenharmony_ci    SANE_Byte source_info;
765141cc406Sopenharmony_ci
766141cc406Sopenharmony_ci
767141cc406Sopenharmony_ci    DBG(30, "attach: device='%s'\n", md->name);
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci    status = scsi_inquiry( &md->info[MD_SOURCE_FLATBED], md->name );
770141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
771141cc406Sopenharmony_ci      {
772141cc406Sopenharmony_ci	DBG(1, "attach: '%s'\n", sane_strstatus(status));
773141cc406Sopenharmony_ci        return status;
774141cc406Sopenharmony_ci      }
775141cc406Sopenharmony_ci
776141cc406Sopenharmony_ci    /* We copy the inquiry info into the info structures for each scansource */
777141cc406Sopenharmony_ci    /* like ADF, TMA, STRIPE and SLIDE */
778141cc406Sopenharmony_ci
779141cc406Sopenharmony_ci    for ( source_info = 1; source_info < 5; ++source_info )
780141cc406Sopenharmony_ci        memcpy( &md->info[source_info],
781141cc406Sopenharmony_ci                &md->info[MD_SOURCE_FLATBED],
782141cc406Sopenharmony_ci                sizeof( Microtek2_Info ) );
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_ci    /* Here we should insert a function, that stores all the relevant */
785141cc406Sopenharmony_ci    /* information in the info structure in a more conveniant format */
786141cc406Sopenharmony_ci    /* in the device structure, e.g. the model name with a trailing '\0'. */
787141cc406Sopenharmony_ci
788141cc406Sopenharmony_ci    status = check_inquiry(md, &model_string);
789141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
790141cc406Sopenharmony_ci        return status;
791141cc406Sopenharmony_ci
792141cc406Sopenharmony_ci    md->sane.name = md->name;
793141cc406Sopenharmony_ci    md->sane.vendor = "Microtek";
794141cc406Sopenharmony_ci    md->sane.model = strdup(model_string);
795141cc406Sopenharmony_ci    if ( md->sane.model == NULL )
796141cc406Sopenharmony_ci        DBG(1, "attach: strdup for model string failed\n");
797141cc406Sopenharmony_ci    md->sane.type = "flatbed scanner";
798141cc406Sopenharmony_ci    md->revision = strtod(md->info[MD_SOURCE_FLATBED].revision, NULL);
799141cc406Sopenharmony_ci
800141cc406Sopenharmony_ci    status = scsi_read_attributes(&md->info[0],
801141cc406Sopenharmony_ci                                  md->name, MD_SOURCE_FLATBED);
802141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
803141cc406Sopenharmony_ci      {
804141cc406Sopenharmony_ci	DBG(1, "attach: '%s'\n", sane_strstatus(status));
805141cc406Sopenharmony_ci        return status;
806141cc406Sopenharmony_ci      }
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci    if ( MI_LUTCAP_NONE( md->info[MD_SOURCE_FLATBED].lut_cap) )
809141cc406Sopenharmony_ci        /* no gamma tables */
810141cc406Sopenharmony_ci        md->model_flags |= MD_NO_GAMMA;
811141cc406Sopenharmony_ci
812141cc406Sopenharmony_ci    /* check whether the device supports transparency media adapters */
813141cc406Sopenharmony_ci    if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_TMA )
814141cc406Sopenharmony_ci      {
815141cc406Sopenharmony_ci        status = scsi_read_attributes(&md->info[0],
816141cc406Sopenharmony_ci                                      md->name, MD_SOURCE_TMA);
817141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
818141cc406Sopenharmony_ci            return status;
819141cc406Sopenharmony_ci      }
820141cc406Sopenharmony_ci
821141cc406Sopenharmony_ci    /* check whether the device supports an ADF */
822141cc406Sopenharmony_ci    if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_ADF )
823141cc406Sopenharmony_ci      {
824141cc406Sopenharmony_ci        status = scsi_read_attributes(&md->info[0],
825141cc406Sopenharmony_ci                                      md->name, MD_SOURCE_ADF);
826141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
827141cc406Sopenharmony_ci            return status;
828141cc406Sopenharmony_ci      }
829141cc406Sopenharmony_ci
830141cc406Sopenharmony_ci    /* check whether the device supports STRIPES */
831141cc406Sopenharmony_ci    if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_STRIPE )
832141cc406Sopenharmony_ci      {
833141cc406Sopenharmony_ci        status = scsi_read_attributes(&md->info[0],
834141cc406Sopenharmony_ci                                      md->name, MD_SOURCE_STRIPE);
835141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
836141cc406Sopenharmony_ci            return status;
837141cc406Sopenharmony_ci      }
838141cc406Sopenharmony_ci
839141cc406Sopenharmony_ci    /* check whether the device supports SLIDES */
840141cc406Sopenharmony_ci    if ( md->info[MD_SOURCE_FLATBED].option_device & MI_OPTDEV_SLIDE )
841141cc406Sopenharmony_ci      {
842141cc406Sopenharmony_ci        /* The Phantom 636cx indicates in its attributes that it supports */
843141cc406Sopenharmony_ci        /* slides, but it doesn't. Thus this command would fail. */
844141cc406Sopenharmony_ci
845141cc406Sopenharmony_ci        if ( ! (md->model_flags & MD_NO_SLIDE_MODE) )
846141cc406Sopenharmony_ci          {
847141cc406Sopenharmony_ci            status = scsi_read_attributes(&md->info[0],
848141cc406Sopenharmony_ci                                          md->name, MD_SOURCE_SLIDE);
849141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
850141cc406Sopenharmony_ci                return status;
851141cc406Sopenharmony_ci          }
852141cc406Sopenharmony_ci      }
853141cc406Sopenharmony_ci
854141cc406Sopenharmony_ci    status = scsi_read_system_status(md, -1);
855141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
856141cc406Sopenharmony_ci        return status;
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
859141cc406Sopenharmony_ci}
860141cc406Sopenharmony_ci
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci/*---------- attach_one() ----------------------------------------------------*/
863141cc406Sopenharmony_ci
864141cc406Sopenharmony_cistatic SANE_Status
865141cc406Sopenharmony_ciattach_one (const char *name)
866141cc406Sopenharmony_ci{
867141cc406Sopenharmony_ci    Microtek2_Device *md;
868141cc406Sopenharmony_ci    Microtek2_Device *md_tmp;
869141cc406Sopenharmony_ci
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_ci    DBG(30, "attach_one: name='%s'\n", name);
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci    md_tmp = md_first_dev;
874141cc406Sopenharmony_ci    /* if add_device_list() adds an entry it does this at the beginning */
875141cc406Sopenharmony_ci    /* of the list and thus changes md_first_dev */
876141cc406Sopenharmony_ci    add_device_list(name, &md);
877141cc406Sopenharmony_ci    if ( md_tmp != md_first_dev )
878141cc406Sopenharmony_ci        attach(md);
879141cc406Sopenharmony_ci
880141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
881141cc406Sopenharmony_ci}
882141cc406Sopenharmony_ci
883141cc406Sopenharmony_ci/*---------- cancel_scan() ---------------------------------------------------*/
884141cc406Sopenharmony_ci
885141cc406Sopenharmony_cistatic SANE_Status
886141cc406Sopenharmony_cicancel_scan(Microtek2_Scanner *ms)
887141cc406Sopenharmony_ci{
888141cc406Sopenharmony_ci    SANE_Status status;
889141cc406Sopenharmony_ci
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci    DBG(30, "cancel_scan: ms=%p\n", (void *) ms);
892141cc406Sopenharmony_ci
893141cc406Sopenharmony_ci    /* READ IMAGE with a transferlength of 0 aborts a scan */
894141cc406Sopenharmony_ci    ms->transfer_length = 0;
895141cc406Sopenharmony_ci    status = scsi_read_image(ms, (uint8_t *) NULL, 1);
896141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
897141cc406Sopenharmony_ci      {
898141cc406Sopenharmony_ci        DBG(1, "cancel_scan: cancel failed: '%s'\n", sane_strstatus(status));
899141cc406Sopenharmony_ci        status = SANE_STATUS_IO_ERROR;
900141cc406Sopenharmony_ci      }
901141cc406Sopenharmony_ci    else
902141cc406Sopenharmony_ci        status = SANE_STATUS_CANCELLED;
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci    close(ms->fd[1]);
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci    /* if we are aborting a scan because, for example, we run out
907141cc406Sopenharmony_ci       of material on a feeder, then pid may be already -1 and
908141cc406Sopenharmony_ci       kill(-1, SIGTERM), i.e. killing all our processes, is not
909141cc406Sopenharmony_ci       likely what we really want - --mj, 2001/Nov/19 */
910141cc406Sopenharmony_ci    if (sanei_thread_is_valid (ms->pid))
911141cc406Sopenharmony_ci      {
912141cc406Sopenharmony_ci       sanei_thread_kill(ms->pid);
913141cc406Sopenharmony_ci       sanei_thread_waitpid(ms->pid, NULL);
914141cc406Sopenharmony_ci      }
915141cc406Sopenharmony_ci
916141cc406Sopenharmony_ci    return status;
917141cc406Sopenharmony_ci}
918141cc406Sopenharmony_ci
919141cc406Sopenharmony_ci
920141cc406Sopenharmony_ci/*---------- check_option() --------------------------------------------------*/
921141cc406Sopenharmony_ci
922141cc406Sopenharmony_cistatic void
923141cc406Sopenharmony_cicheck_option(const char *cp, Config_Options *co)
924141cc406Sopenharmony_ci{
925141cc406Sopenharmony_ci    /* This function analyses options in the config file */
926141cc406Sopenharmony_ci
927141cc406Sopenharmony_ci    char *endptr;
928141cc406Sopenharmony_ci
929141cc406Sopenharmony_ci    /* When this function is called, it is already made sure that this */
930141cc406Sopenharmony_ci    /* is an option line, i.e. a line that starts with option */
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_ci    cp = sanei_config_skip_whitespace(cp);     /* skip blanks */
933141cc406Sopenharmony_ci    cp = sanei_config_skip_whitespace(cp + 6); /* skip "option" */
934141cc406Sopenharmony_ci    if ( strncmp(cp, "dump", 4) == 0 && isspace(cp[4]) )
935141cc406Sopenharmony_ci      {
936141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 4);
937141cc406Sopenharmony_ci        if ( *cp )
938141cc406Sopenharmony_ci          {
939141cc406Sopenharmony_ci            md_dump = (int) strtol(cp, &endptr, 10);
940141cc406Sopenharmony_ci            if ( md_dump > 4 || md_dump < 0 )
941141cc406Sopenharmony_ci              {
942141cc406Sopenharmony_ci                md_dump = 1;
943141cc406Sopenharmony_ci                DBG(30, "check_option: setting dump to %d\n", md_dump);
944141cc406Sopenharmony_ci              }
945141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(endptr);
946141cc406Sopenharmony_ci            if ( *cp )
947141cc406Sopenharmony_ci              {
948141cc406Sopenharmony_ci                /* something behind the option value or value wrong */
949141cc406Sopenharmony_ci                md_dump = 1;
950141cc406Sopenharmony_ci                DBG(30, "check_option: option value wrong\n");
951141cc406Sopenharmony_ci              }
952141cc406Sopenharmony_ci          }
953141cc406Sopenharmony_ci        else
954141cc406Sopenharmony_ci          {
955141cc406Sopenharmony_ci            DBG(30, "check_option: missing option value\n");
956141cc406Sopenharmony_ci            /* reasonable fallback */
957141cc406Sopenharmony_ci            md_dump = 1;
958141cc406Sopenharmony_ci          }
959141cc406Sopenharmony_ci      }
960141cc406Sopenharmony_ci    else if ( strncmp(cp, "strip-height", 12) == 0 && isspace(cp[12]) )
961141cc406Sopenharmony_ci      {
962141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 12);
963141cc406Sopenharmony_ci        if ( *cp )
964141cc406Sopenharmony_ci          {
965141cc406Sopenharmony_ci            co->strip_height = strtod(cp, &endptr);
966141cc406Sopenharmony_ci            DBG(30, "check_option: setting strip_height to %f\n",
967141cc406Sopenharmony_ci                     co->strip_height);
968141cc406Sopenharmony_ci            if ( co->strip_height <= 0.0 )
969141cc406Sopenharmony_ci                co->strip_height = 14.0;
970141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(endptr);
971141cc406Sopenharmony_ci            if ( *cp )
972141cc406Sopenharmony_ci              {
973141cc406Sopenharmony_ci                /* something behind the option value or value wrong */
974141cc406Sopenharmony_ci                co->strip_height = 14.0;
975141cc406Sopenharmony_ci                DBG(30, "check_option: option value wrong: %f\n",
976141cc406Sopenharmony_ci                         co->strip_height);
977141cc406Sopenharmony_ci              }
978141cc406Sopenharmony_ci          }
979141cc406Sopenharmony_ci      }
980141cc406Sopenharmony_ci    else if ( strncmp(cp, "no-backtrack-option", 19) == 0
981141cc406Sopenharmony_ci              && isspace(cp[19]) )
982141cc406Sopenharmony_ci      {
983141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 19);
984141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
985141cc406Sopenharmony_ci          {
986141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
987141cc406Sopenharmony_ci            co->no_backtracking = "on";
988141cc406Sopenharmony_ci          }
989141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
990141cc406Sopenharmony_ci          {
991141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
992141cc406Sopenharmony_ci            co->no_backtracking = "off";
993141cc406Sopenharmony_ci          }
994141cc406Sopenharmony_ci        else
995141cc406Sopenharmony_ci            co->no_backtracking = "off";
996141cc406Sopenharmony_ci
997141cc406Sopenharmony_ci        if ( *cp )
998141cc406Sopenharmony_ci          {
999141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1000141cc406Sopenharmony_ci            co->no_backtracking = "off";
1001141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1002141cc406Sopenharmony_ci          }
1003141cc406Sopenharmony_ci      }
1004141cc406Sopenharmony_ci    else if ( strncmp(cp, "lightlid-35", 11) == 0
1005141cc406Sopenharmony_ci              && isspace(cp[11]) )
1006141cc406Sopenharmony_ci      {
1007141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 11);
1008141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
1009141cc406Sopenharmony_ci          {
1010141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
1011141cc406Sopenharmony_ci            co->lightlid35 = "on";
1012141cc406Sopenharmony_ci          }
1013141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
1014141cc406Sopenharmony_ci          {
1015141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
1016141cc406Sopenharmony_ci            co->lightlid35 = "off";
1017141cc406Sopenharmony_ci          }
1018141cc406Sopenharmony_ci        else
1019141cc406Sopenharmony_ci            co->lightlid35 = "off";
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci        if ( *cp )
1022141cc406Sopenharmony_ci          {
1023141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1024141cc406Sopenharmony_ci            co->lightlid35 = "off";
1025141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1026141cc406Sopenharmony_ci          }
1027141cc406Sopenharmony_ci      }
1028141cc406Sopenharmony_ci    else if ( strncmp(cp, "toggle-lamp", 11) == 0
1029141cc406Sopenharmony_ci              && isspace(cp[11]) )
1030141cc406Sopenharmony_ci      {
1031141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 11);
1032141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
1033141cc406Sopenharmony_ci          {
1034141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
1035141cc406Sopenharmony_ci            co->toggle_lamp = "on";
1036141cc406Sopenharmony_ci          }
1037141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
1038141cc406Sopenharmony_ci          {
1039141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
1040141cc406Sopenharmony_ci            co->toggle_lamp = "off";
1041141cc406Sopenharmony_ci          }
1042141cc406Sopenharmony_ci        else
1043141cc406Sopenharmony_ci            co->toggle_lamp = "off";
1044141cc406Sopenharmony_ci
1045141cc406Sopenharmony_ci        if ( *cp )
1046141cc406Sopenharmony_ci          {
1047141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1048141cc406Sopenharmony_ci            co->toggle_lamp = "off";
1049141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1050141cc406Sopenharmony_ci          }
1051141cc406Sopenharmony_ci      }
1052141cc406Sopenharmony_ci    else if ( strncmp(cp, "lineart-autoadjust", 18) == 0
1053141cc406Sopenharmony_ci              && isspace(cp[18]) )
1054141cc406Sopenharmony_ci      {
1055141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 18);
1056141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
1057141cc406Sopenharmony_ci          {
1058141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
1059141cc406Sopenharmony_ci            co->auto_adjust = "on";
1060141cc406Sopenharmony_ci          }
1061141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
1062141cc406Sopenharmony_ci          {
1063141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
1064141cc406Sopenharmony_ci            co->auto_adjust = "off";
1065141cc406Sopenharmony_ci          }
1066141cc406Sopenharmony_ci        else
1067141cc406Sopenharmony_ci            co->auto_adjust = "off";
1068141cc406Sopenharmony_ci
1069141cc406Sopenharmony_ci        if ( *cp )
1070141cc406Sopenharmony_ci          {
1071141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1072141cc406Sopenharmony_ci            co->auto_adjust = "off";
1073141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1074141cc406Sopenharmony_ci          }
1075141cc406Sopenharmony_ci      }
1076141cc406Sopenharmony_ci    else if ( strncmp(cp, "backend-calibration", 19) == 0
1077141cc406Sopenharmony_ci              && isspace(cp[19]) )
1078141cc406Sopenharmony_ci      {
1079141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 19);
1080141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
1081141cc406Sopenharmony_ci          {
1082141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
1083141cc406Sopenharmony_ci            co->backend_calibration = "on";
1084141cc406Sopenharmony_ci          }
1085141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
1086141cc406Sopenharmony_ci          {
1087141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
1088141cc406Sopenharmony_ci            co->backend_calibration = "off";
1089141cc406Sopenharmony_ci          }
1090141cc406Sopenharmony_ci        else
1091141cc406Sopenharmony_ci            co->backend_calibration = "off";
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci        if ( *cp )
1094141cc406Sopenharmony_ci          {
1095141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1096141cc406Sopenharmony_ci            co->backend_calibration = "off";
1097141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1098141cc406Sopenharmony_ci          }
1099141cc406Sopenharmony_ci      }
1100141cc406Sopenharmony_ci    else if ( strncmp(cp, "colorbalance-adjust", 19) == 0
1101141cc406Sopenharmony_ci              && isspace(cp[19]) )
1102141cc406Sopenharmony_ci      {
1103141cc406Sopenharmony_ci        cp = sanei_config_skip_whitespace(cp + 19);
1104141cc406Sopenharmony_ci        if ( strncmp(cp, "on", 2) == 0 )
1105141cc406Sopenharmony_ci          {
1106141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 2);
1107141cc406Sopenharmony_ci            co->colorbalance_adjust = "on";
1108141cc406Sopenharmony_ci          }
1109141cc406Sopenharmony_ci        else if ( strncmp(cp, "off", 3) == 0 )
1110141cc406Sopenharmony_ci          {
1111141cc406Sopenharmony_ci            cp = sanei_config_skip_whitespace(cp + 3);
1112141cc406Sopenharmony_ci            co->colorbalance_adjust = "off";
1113141cc406Sopenharmony_ci          }
1114141cc406Sopenharmony_ci        else
1115141cc406Sopenharmony_ci            co->colorbalance_adjust = "off";
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci        if ( *cp )
1118141cc406Sopenharmony_ci          {
1119141cc406Sopenharmony_ci            /* something behind the option value or value wrong */
1120141cc406Sopenharmony_ci            co->colorbalance_adjust = "off";
1121141cc406Sopenharmony_ci            DBG(30, "check_option: option value wrong: %s\n", cp);
1122141cc406Sopenharmony_ci          }
1123141cc406Sopenharmony_ci      }
1124141cc406Sopenharmony_ci    else
1125141cc406Sopenharmony_ci        DBG(30, "check_option: invalid option in '%s'\n", cp);
1126141cc406Sopenharmony_ci}
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci
1129141cc406Sopenharmony_ci/*---------- check_inquiry() -------------------------------------------------*/
1130141cc406Sopenharmony_ci
1131141cc406Sopenharmony_cistatic SANE_Status
1132141cc406Sopenharmony_cicheck_inquiry(Microtek2_Device *md, SANE_String *model_string)
1133141cc406Sopenharmony_ci{
1134141cc406Sopenharmony_ci    Microtek2_Info *mi;
1135141cc406Sopenharmony_ci
1136141cc406Sopenharmony_ci    DBG(30, "check_inquiry: md=%p\n", (void *) md);
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci    md->n_control_bytes = 0;
1139141cc406Sopenharmony_ci    md->shading_length = 0;
1140141cc406Sopenharmony_ci    md->shading_table_contents = 0;
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci    mi = &md->info[MD_SOURCE_FLATBED];
1143141cc406Sopenharmony_ci    if ( mi->scsi_version != MI_SCSI_II_VERSION )
1144141cc406Sopenharmony_ci      {
1145141cc406Sopenharmony_ci        DBG(1, "check_inquiry: Device is not a SCSI-II device, but 0x%02x\n",
1146141cc406Sopenharmony_ci                mi->scsi_version);
1147141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
1148141cc406Sopenharmony_ci      }
1149141cc406Sopenharmony_ci
1150141cc406Sopenharmony_ci    if ( mi->device_type != MI_DEVTYPE_SCANNER )
1151141cc406Sopenharmony_ci      {
1152141cc406Sopenharmony_ci        DBG(1, "check_inquiry: Device is not a scanner, but 0x%02x\n",
1153141cc406Sopenharmony_ci                mi->device_type);
1154141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
1155141cc406Sopenharmony_ci      }
1156141cc406Sopenharmony_ci
1157141cc406Sopenharmony_ci    if ( strncasecmp("MICROTEK", mi->vendor, INQ_VENDOR_L) != 0
1158141cc406Sopenharmony_ci         && strncmp("        ", mi->vendor, INQ_VENDOR_L) != 0
1159141cc406Sopenharmony_ci         && strncmp("AGFA    ", mi->vendor, INQ_VENDOR_L) != 0 )
1160141cc406Sopenharmony_ci      {
1161141cc406Sopenharmony_ci        DBG(1, "check_inquiry: Device is not a Microtek, but '%.*s'\n",
1162141cc406Sopenharmony_ci                INQ_VENDOR_L, mi->vendor);
1163141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
1164141cc406Sopenharmony_ci      }
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_16 )
1167141cc406Sopenharmony_ci        md->shading_depth = 16;
1168141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_14 )
1169141cc406Sopenharmony_ci        md->shading_depth = 14;
1170141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_12 )
1171141cc406Sopenharmony_ci        md->shading_depth = 12;
1172141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_10 )
1173141cc406Sopenharmony_ci        md->shading_depth = 10;
1174141cc406Sopenharmony_ci    else
1175141cc406Sopenharmony_ci        md->shading_depth = 8;
1176141cc406Sopenharmony_ci
1177141cc406Sopenharmony_ci    switch (mi->model_code)
1178141cc406Sopenharmony_ci      {
1179141cc406Sopenharmony_ci        case 0x81:
1180141cc406Sopenharmony_ci        case 0xab:
1181141cc406Sopenharmony_ci          *model_string = "ScanMaker 4";
1182141cc406Sopenharmony_ci          break;
1183141cc406Sopenharmony_ci        case 0x85:
1184141cc406Sopenharmony_ci          *model_string = "ScanMaker V300 / ColorPage-EP";
1185141cc406Sopenharmony_ci          /* The ScanMaker V300 (FW < 2.70) returns some values for the */
1186141cc406Sopenharmony_ci          /* "read image info" command in only two bytes */
1187141cc406Sopenharmony_ci          /* and doesn't understand read_image_status */
1188141cc406Sopenharmony_ci          md->model_flags |= MD_NO_RIS_COMMAND;
1189141cc406Sopenharmony_ci          if ( md->revision < 2.70 )
1190141cc406Sopenharmony_ci              md->model_flags |= MD_RII_TWO_BYTES;
1191141cc406Sopenharmony_ci          break;
1192141cc406Sopenharmony_ci        case 0x87:
1193141cc406Sopenharmony_ci          *model_string = "ScanMaker 5";
1194141cc406Sopenharmony_ci          md->model_flags |= MD_NO_GAMMA;
1195141cc406Sopenharmony_ci          break;
1196141cc406Sopenharmony_ci        case 0x89:
1197141cc406Sopenharmony_ci          *model_string = "ScanMaker 6400XL";
1198141cc406Sopenharmony_ci          break;
1199141cc406Sopenharmony_ci        case 0x8a:
1200141cc406Sopenharmony_ci          *model_string = "ScanMaker 9600XL";
1201141cc406Sopenharmony_ci          break;
1202141cc406Sopenharmony_ci        case 0x8c:
1203141cc406Sopenharmony_ci          *model_string = "ScanMaker 630 / ScanMaker V600";
1204141cc406Sopenharmony_ci          break;
1205141cc406Sopenharmony_ci        case 0x8d:
1206141cc406Sopenharmony_ci          *model_string = "ScanMaker 336 / ScanMaker V310";
1207141cc406Sopenharmony_ci          break;
1208141cc406Sopenharmony_ci        case 0x90:
1209141cc406Sopenharmony_ci        case 0x92:
1210141cc406Sopenharmony_ci          *model_string = "E3+ / Vobis HighScan";
1211141cc406Sopenharmony_ci          break;
1212141cc406Sopenharmony_ci        case 0x91:
1213141cc406Sopenharmony_ci          *model_string = "ScanMaker X6 / Phantom 636";
1214141cc406Sopenharmony_ci          /* The X6 indicates a data format of segregated data in TMA mode */
1215141cc406Sopenharmony_ci          /* but actually transfers as chunky data */
1216141cc406Sopenharmony_ci          md->model_flags |= MD_DATA_FORMAT_WRONG;
1217141cc406Sopenharmony_ci          if ( md->revision == 1.00 )
1218141cc406Sopenharmony_ci              md->model_flags |= MD_OFFSET_2;
1219141cc406Sopenharmony_ci          break;
1220141cc406Sopenharmony_ci        case 0x93:
1221141cc406Sopenharmony_ci          *model_string = "ScanMaker 336 / ScanMaker V310";
1222141cc406Sopenharmony_ci          break;
1223141cc406Sopenharmony_ci        case 0x70:
1224141cc406Sopenharmony_ci        case 0x71:
1225141cc406Sopenharmony_ci        case 0x94:
1226141cc406Sopenharmony_ci        case 0xa0:
1227141cc406Sopenharmony_ci          *model_string = "Phantom 330cx / Phantom 336cx / SlimScan C3";
1228141cc406Sopenharmony_ci          /* These models do not accept gamma tables. Apparently they */
1229141cc406Sopenharmony_ci          /* read the control bits and do not accept shading tables */
1230141cc406Sopenharmony_ci          /* They also don't support enhancements (contrast, brightness...)*/
1231141cc406Sopenharmony_ci          md->model_flags |= MD_NO_SLIDE_MODE
1232141cc406Sopenharmony_ci                          | MD_NO_GAMMA
1233141cc406Sopenharmony_ci#ifndef NO_PHANTOMTYPE_SHADING
1234141cc406Sopenharmony_ci			  | MD_PHANTOM336CX_TYPE_SHADING
1235141cc406Sopenharmony_ci#endif
1236141cc406Sopenharmony_ci                          | MD_READ_CONTROL_BIT
1237141cc406Sopenharmony_ci                          | MD_NO_ENHANCEMENTS;
1238141cc406Sopenharmony_ci          md->opt_backend_calib_default = SANE_TRUE;
1239141cc406Sopenharmony_ci          md->opt_no_backtrack_default = SANE_TRUE;
1240141cc406Sopenharmony_ci          md->n_control_bytes = 320;
1241141cc406Sopenharmony_ci          md->shading_length = 18;
1242141cc406Sopenharmony_ci          md->shading_depth = 10;
1243141cc406Sopenharmony_ci          md->controlbit_offset = 7;
1244141cc406Sopenharmony_ci          break;
1245141cc406Sopenharmony_ci        case 0x95:
1246141cc406Sopenharmony_ci          *model_string = "ArtixScan 1010";
1247141cc406Sopenharmony_ci          break;
1248141cc406Sopenharmony_ci        case 0x97:
1249141cc406Sopenharmony_ci          *model_string = "ScanMaker 636";
1250141cc406Sopenharmony_ci          break;
1251141cc406Sopenharmony_ci        case 0x98:
1252141cc406Sopenharmony_ci          *model_string = "ScanMaker X6EL";
1253141cc406Sopenharmony_ci          if ( md->revision == 1.00 )
1254141cc406Sopenharmony_ci              md->model_flags |= MD_OFFSET_2;
1255141cc406Sopenharmony_ci          break;
1256141cc406Sopenharmony_ci        case 0x99:
1257141cc406Sopenharmony_ci          *model_string = "ScanMaker X6USB";
1258141cc406Sopenharmony_ci          if ( md->revision == 1.00 )
1259141cc406Sopenharmony_ci              md->model_flags |= MD_OFFSET_2;
1260141cc406Sopenharmony_ci          md->model_flags |= MD_X6_SHORT_TRANSFER;
1261141cc406Sopenharmony_ci          break;
1262141cc406Sopenharmony_ci        case 0x9a:
1263141cc406Sopenharmony_ci          *model_string = "Phantom 636cx / C6";
1264141cc406Sopenharmony_ci          /* The Phantom 636cx says it supports the SLIDE mode, but it */
1265141cc406Sopenharmony_ci          /* doesn't. Thus inquring the attributes for slide mode would */
1266141cc406Sopenharmony_ci          /* fail. Also it does not accept gamma tables. Apparently */
1267141cc406Sopenharmony_ci          /* it reads the control bits and does not accept shading tables */
1268141cc406Sopenharmony_ci          md->model_flags |= MD_NO_SLIDE_MODE
1269141cc406Sopenharmony_ci                          | MD_READ_CONTROL_BIT
1270141cc406Sopenharmony_ci                          | MD_NO_GAMMA
1271141cc406Sopenharmony_ci                          | MD_PHANTOM_C6;
1272141cc406Sopenharmony_ci          md->opt_backend_calib_default = SANE_TRUE;
1273141cc406Sopenharmony_ci          md->opt_no_backtrack_default = SANE_TRUE;
1274141cc406Sopenharmony_ci          md->n_control_bytes = 647;
1275141cc406Sopenharmony_ci          /* md->shading_length = 18; firmware values seem to work better */
1276141cc406Sopenharmony_ci          md->shading_depth = 12;
1277141cc406Sopenharmony_ci          md->controlbit_offset = 18;
1278141cc406Sopenharmony_ci          break;
1279141cc406Sopenharmony_ci        case 0x9d:
1280141cc406Sopenharmony_ci          *model_string = "AGFA Duoscan T1200";
1281141cc406Sopenharmony_ci          break;
1282141cc406Sopenharmony_ci        case 0xa3:
1283141cc406Sopenharmony_ci          *model_string = "ScanMaker V6USL";
1284141cc406Sopenharmony_ci          /* The V6USL does not accept gamma tables */
1285141cc406Sopenharmony_ci          md->model_flags |= MD_NO_GAMMA;
1286141cc406Sopenharmony_ci          break;
1287141cc406Sopenharmony_ci        case 0xa5:
1288141cc406Sopenharmony_ci          *model_string = "ArtixScan 4000t";
1289141cc406Sopenharmony_ci          break;
1290141cc406Sopenharmony_ci        case 0xac:
1291141cc406Sopenharmony_ci          *model_string = "ScanMaker V6UL";
1292141cc406Sopenharmony_ci          /* The V6USL does not accept gamma tables, perhaps the V6UL also */
1293141cc406Sopenharmony_ci          md->model_flags |= MD_NO_GAMMA;
1294141cc406Sopenharmony_ci          break;
1295141cc406Sopenharmony_ci        case 0xaf:
1296141cc406Sopenharmony_ci          *model_string = "SlimScan C3";
1297141cc406Sopenharmony_ci          md->model_flags |= MD_NO_SLIDE_MODE
1298141cc406Sopenharmony_ci                          | MD_NO_GAMMA
1299141cc406Sopenharmony_ci                          | MD_READ_CONTROL_BIT
1300141cc406Sopenharmony_ci                          | MD_NO_ENHANCEMENTS;
1301141cc406Sopenharmony_ci          md->opt_backend_calib_default = SANE_TRUE;
1302141cc406Sopenharmony_ci          md->opt_no_backtrack_default = SANE_TRUE;
1303141cc406Sopenharmony_ci          md->n_control_bytes = 320;
1304141cc406Sopenharmony_ci          md->controlbit_offset = 7;
1305141cc406Sopenharmony_ci          break;
1306141cc406Sopenharmony_ci        case 0xb0:
1307141cc406Sopenharmony_ci          *model_string = "ScanMaker X12USL";
1308141cc406Sopenharmony_ci          md->opt_backend_calib_default = SANE_TRUE;
1309141cc406Sopenharmony_ci          md->model_flags |= MD_16BIT_TRANSFER
1310141cc406Sopenharmony_ci                          | MD_CALIB_DIVISOR_600;
1311141cc406Sopenharmony_ci          break;
1312141cc406Sopenharmony_ci        case 0xb3:
1313141cc406Sopenharmony_ci           *model_string = "ScanMaker 3600";
1314141cc406Sopenharmony_ci           break;
1315141cc406Sopenharmony_ci        case 0xb4:
1316141cc406Sopenharmony_ci           *model_string = "ScanMaker 4700";
1317141cc406Sopenharmony_ci           break;
1318141cc406Sopenharmony_ci        case 0xb6:
1319141cc406Sopenharmony_ci          *model_string = "ScanMaker V6UPL";
1320141cc406Sopenharmony_ci          /* is like V6USL but with USB and Parport interface ?? */
1321141cc406Sopenharmony_ci          md->model_flags |= MD_NO_GAMMA;
1322141cc406Sopenharmony_ci          break;
1323141cc406Sopenharmony_ci        case 0xb8:
1324141cc406Sopenharmony_ci           *model_string = "ScanMaker 3700";
1325141cc406Sopenharmony_ci           break;
1326141cc406Sopenharmony_ci        case 0xde:
1327141cc406Sopenharmony_ci           *model_string = "ScanMaker 9800XL";
1328141cc406Sopenharmony_ci           md->model_flags |= MD_NO_GAMMA
1329141cc406Sopenharmony_ci			   | MD_16BIT_TRANSFER;
1330141cc406Sopenharmony_ci           md->opt_backend_calib_default = SANE_TRUE;
1331141cc406Sopenharmony_ci           md->opt_no_backtrack_default = SANE_TRUE;
1332141cc406Sopenharmony_ci           break;
1333141cc406Sopenharmony_ci        default:
1334141cc406Sopenharmony_ci          DBG(1, "check_inquiry: Model 0x%02x not supported\n", mi->model_code);
1335141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
1336141cc406Sopenharmony_ci      }
1337141cc406Sopenharmony_ci
1338141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1339141cc406Sopenharmony_ci}
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci
1342141cc406Sopenharmony_ci/*---------- cleanup_scanner() -----------------------------------------------*/
1343141cc406Sopenharmony_ci
1344141cc406Sopenharmony_cistatic void
1345141cc406Sopenharmony_cicleanup_scanner(Microtek2_Scanner *ms)
1346141cc406Sopenharmony_ci{
1347141cc406Sopenharmony_ci    DBG(30, "cleanup_scanner: ms=%p, ms->sfd=%d\n", (void *) ms, ms->sfd);
1348141cc406Sopenharmony_ci
1349141cc406Sopenharmony_ci    if ( ms->scanning == SANE_TRUE )
1350141cc406Sopenharmony_ci      cancel_scan(ms);
1351141cc406Sopenharmony_ci
1352141cc406Sopenharmony_ci    if ( ms->sfd != -1 )
1353141cc406Sopenharmony_ci      sanei_scsi_close(ms->sfd);
1354141cc406Sopenharmony_ci    ms->sfd = -1;
1355141cc406Sopenharmony_ci    sanei_thread_invalidate(ms->pid);
1356141cc406Sopenharmony_ci    ms->fp = NULL;
1357141cc406Sopenharmony_ci    ms->current_pass = 0;
1358141cc406Sopenharmony_ci    ms->scanning = SANE_FALSE;
1359141cc406Sopenharmony_ci    ms->cancelled = SANE_FALSE;
1360141cc406Sopenharmony_ci
1361141cc406Sopenharmony_ci    /* free buffers */
1362141cc406Sopenharmony_ci    if ( ms->buf.src_buffer[0] )
1363141cc406Sopenharmony_ci      {
1364141cc406Sopenharmony_ci        DBG(100, "free ms->buf.src_buffer[0] at %p\n",
1365141cc406Sopenharmony_ci                  (void *) ms->buf.src_buffer[0]);
1366141cc406Sopenharmony_ci        free((void *) ms->buf.src_buffer[0]);
1367141cc406Sopenharmony_ci        ms->buf.src_buffer[0] = NULL;
1368141cc406Sopenharmony_ci        ms->buf.src_buf = NULL;
1369141cc406Sopenharmony_ci      }
1370141cc406Sopenharmony_ci    if ( ms->buf.src_buffer[1] )
1371141cc406Sopenharmony_ci      {
1372141cc406Sopenharmony_ci        DBG(100, "free ms->buf.src_buffer[1] at %p\n",
1373141cc406Sopenharmony_ci                  (void *) ms->buf.src_buffer[1]);
1374141cc406Sopenharmony_ci        free((void *) ms->buf.src_buffer[1]);
1375141cc406Sopenharmony_ci        ms->buf.src_buffer[1] = NULL;
1376141cc406Sopenharmony_ci        ms->buf.src_buf = NULL;
1377141cc406Sopenharmony_ci      }
1378141cc406Sopenharmony_ci    if ( ms->buf.src_buf )
1379141cc406Sopenharmony_ci      {
1380141cc406Sopenharmony_ci        DBG(100, "free ms->buf.src_buf at %p\n", (void *) ms->buf.src_buf);
1381141cc406Sopenharmony_ci        free((void *) ms->buf.src_buf);
1382141cc406Sopenharmony_ci        ms->buf.src_buf = NULL;
1383141cc406Sopenharmony_ci      }
1384141cc406Sopenharmony_ci    if ( ms->temporary_buffer )
1385141cc406Sopenharmony_ci      {
1386141cc406Sopenharmony_ci        DBG(100, "free ms->temporary_buffer at %p\n",
1387141cc406Sopenharmony_ci                  (void *) ms->temporary_buffer);
1388141cc406Sopenharmony_ci        free((void *) ms->temporary_buffer);
1389141cc406Sopenharmony_ci        ms->temporary_buffer = NULL;
1390141cc406Sopenharmony_ci      }
1391141cc406Sopenharmony_ci    if ( ms->gamma_table )
1392141cc406Sopenharmony_ci      {
1393141cc406Sopenharmony_ci        DBG(100, "free ms->gamma_table at %p\n", (void *) ms->gamma_table);
1394141cc406Sopenharmony_ci        free((void *) ms->gamma_table);
1395141cc406Sopenharmony_ci        ms->gamma_table = NULL;
1396141cc406Sopenharmony_ci      }
1397141cc406Sopenharmony_ci    if ( ms->control_bytes )
1398141cc406Sopenharmony_ci      {
1399141cc406Sopenharmony_ci        DBG(100, "free ms->control_bytes at %p\n", (void *) ms->control_bytes);
1400141cc406Sopenharmony_ci        free((void *) ms->control_bytes);
1401141cc406Sopenharmony_ci        ms->control_bytes = NULL;
1402141cc406Sopenharmony_ci      }
1403141cc406Sopenharmony_ci    if ( ms->condensed_shading_w )
1404141cc406Sopenharmony_ci      {
1405141cc406Sopenharmony_ci        DBG(100, "free ms->condensed_shading_w at %p\n",
1406141cc406Sopenharmony_ci                  (void *) ms->condensed_shading_w);
1407141cc406Sopenharmony_ci        free((void *) ms->condensed_shading_w);
1408141cc406Sopenharmony_ci        ms->condensed_shading_w = NULL;
1409141cc406Sopenharmony_ci      }
1410141cc406Sopenharmony_ci    if ( ms->condensed_shading_d )
1411141cc406Sopenharmony_ci      {
1412141cc406Sopenharmony_ci        DBG(100, "free ms->condensed_shading_d at %p\n",
1413141cc406Sopenharmony_ci                  (void *) ms->condensed_shading_d);
1414141cc406Sopenharmony_ci        free((void *) ms->condensed_shading_d);
1415141cc406Sopenharmony_ci        ms->condensed_shading_d = NULL;
1416141cc406Sopenharmony_ci      }
1417141cc406Sopenharmony_ci
1418141cc406Sopenharmony_ci    return;
1419141cc406Sopenharmony_ci}
1420141cc406Sopenharmony_ci
1421141cc406Sopenharmony_ci#ifdef HAVE_AUTHORIZATION
1422141cc406Sopenharmony_ci/*---------- do_authorization() ----------------------------------------------*/
1423141cc406Sopenharmony_ci
1424141cc406Sopenharmony_cistatic SANE_Status
1425141cc406Sopenharmony_cido_authorization(char *resource)
1426141cc406Sopenharmony_ci{
1427141cc406Sopenharmony_ci    /* This function implements a simple authorization function. It looks */
1428141cc406Sopenharmony_ci    /* up an entry in the file SANE_PATH_CONFIG_DIR/auth. Such an entry */
1429141cc406Sopenharmony_ci    /* must be of the form device:user:password where password is a crypt() */
1430141cc406Sopenharmony_ci    /* encrypted password. If several users are allowed to access a device */
1431141cc406Sopenharmony_ci    /* an entry must be created for each user. If no entry exists for device */
1432141cc406Sopenharmony_ci    /* or the file does not exist no authentication is necessary. If the */
1433141cc406Sopenharmony_ci    /* file exists, but can't be opened the authentication fails */
1434141cc406Sopenharmony_ci
1435141cc406Sopenharmony_ci    SANE_Status status;
1436141cc406Sopenharmony_ci    FILE *fp;
1437141cc406Sopenharmony_ci    int device_found;
1438141cc406Sopenharmony_ci    char username[SANE_MAX_USERNAME_LEN];
1439141cc406Sopenharmony_ci    char password[SANE_MAX_PASSWORD_LEN];
1440141cc406Sopenharmony_ci    char line[MAX_LINE_LEN];
1441141cc406Sopenharmony_ci    char *linep;
1442141cc406Sopenharmony_ci    char *device;
1443141cc406Sopenharmony_ci    char *user;
1444141cc406Sopenharmony_ci    char *passwd;
1445141cc406Sopenharmony_ci    char *p;
1446141cc406Sopenharmony_ci
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci    DBG(30, "do_authorization: resource=%s\n", resource);
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci    if ( auth_callback == NULL )  /* frontend does not require authorization */
1451141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
1452141cc406Sopenharmony_ci
1453141cc406Sopenharmony_ci    /* first check if an entry exists in for this device. If not, we don't */
1454141cc406Sopenharmony_ci    /* use authorization */
1455141cc406Sopenharmony_ci
1456141cc406Sopenharmony_ci    fp = fopen(PASSWD_FILE, "r");
1457141cc406Sopenharmony_ci    if ( fp == NULL )
1458141cc406Sopenharmony_ci      {
1459141cc406Sopenharmony_ci        if ( errno == ENOENT )
1460141cc406Sopenharmony_ci          {
1461141cc406Sopenharmony_ci            DBG(1, "do_authorization: file not found: %s\n", PASSWD_FILE);
1462141cc406Sopenharmony_ci            return SANE_STATUS_GOOD;
1463141cc406Sopenharmony_ci          }
1464141cc406Sopenharmony_ci        else
1465141cc406Sopenharmony_ci          {
1466141cc406Sopenharmony_ci            DBG(1, "do_authorization: fopen() failed, errno=%d\n", errno);
1467141cc406Sopenharmony_ci            return SANE_STATUS_ACCESS_DENIED;
1468141cc406Sopenharmony_ci          }
1469141cc406Sopenharmony_ci      }
1470141cc406Sopenharmony_ci
1471141cc406Sopenharmony_ci    linep = &line[0];
1472141cc406Sopenharmony_ci    device_found = 0;
1473141cc406Sopenharmony_ci    while ( fgets(line, MAX_LINE_LEN, fp) )
1474141cc406Sopenharmony_ci      {
1475141cc406Sopenharmony_ci        p = index(linep, SEPARATOR);
1476141cc406Sopenharmony_ci        if ( p )
1477141cc406Sopenharmony_ci          {
1478141cc406Sopenharmony_ci            *p = '\0';
1479141cc406Sopenharmony_ci            device = linep;
1480141cc406Sopenharmony_ci            if ( strcmp(device, resource) == 0 )
1481141cc406Sopenharmony_ci              {
1482141cc406Sopenharmony_ci                DBG(2, "equal\n");
1483141cc406Sopenharmony_ci                device_found = 1;
1484141cc406Sopenharmony_ci                break;
1485141cc406Sopenharmony_ci              }
1486141cc406Sopenharmony_ci          }
1487141cc406Sopenharmony_ci      }
1488141cc406Sopenharmony_ci
1489141cc406Sopenharmony_ci    if ( ! device_found )
1490141cc406Sopenharmony_ci      {
1491141cc406Sopenharmony_ci        fclose(fp);
1492141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
1493141cc406Sopenharmony_ci      }
1494141cc406Sopenharmony_ci
1495141cc406Sopenharmony_ci    fseek(fp, 0L, SEEK_SET);
1496141cc406Sopenharmony_ci
1497141cc406Sopenharmony_ci    (*auth_callback) (resource, username, password);
1498141cc406Sopenharmony_ci
1499141cc406Sopenharmony_ci    status = SANE_STATUS_ACCESS_DENIED;
1500141cc406Sopenharmony_ci    do
1501141cc406Sopenharmony_ci      {
1502141cc406Sopenharmony_ci        fgets(line, MAX_LINE_LEN, fp);
1503141cc406Sopenharmony_ci        if ( ! ferror(fp) && ! feof(fp) )
1504141cc406Sopenharmony_ci          {
1505141cc406Sopenharmony_ci            /* neither strsep(3) nor strtok(3) seem to work on my system */
1506141cc406Sopenharmony_ci            p = index(linep, SEPARATOR);
1507141cc406Sopenharmony_ci            if ( p == NULL )
1508141cc406Sopenharmony_ci                continue;
1509141cc406Sopenharmony_ci            *p = '\0';
1510141cc406Sopenharmony_ci            device = linep;
1511141cc406Sopenharmony_ci            if ( strcmp( device, resource) != 0 ) /* not a matching entry */
1512141cc406Sopenharmony_ci                continue;
1513141cc406Sopenharmony_ci
1514141cc406Sopenharmony_ci            linep = ++p;
1515141cc406Sopenharmony_ci            p = index(linep, SEPARATOR);
1516141cc406Sopenharmony_ci            if ( p == NULL )
1517141cc406Sopenharmony_ci                continue;
1518141cc406Sopenharmony_ci
1519141cc406Sopenharmony_ci            *p = '\0';
1520141cc406Sopenharmony_ci            user = linep;
1521141cc406Sopenharmony_ci            if ( strncmp(user, username, SANE_MAX_USERNAME_LEN) != 0 )
1522141cc406Sopenharmony_ci                continue;                  /* username doesn't match */
1523141cc406Sopenharmony_ci
1524141cc406Sopenharmony_ci            linep = ++p;
1525141cc406Sopenharmony_ci            /* rest of the line is considered to be the password */
1526141cc406Sopenharmony_ci            passwd = linep;
1527141cc406Sopenharmony_ci            /* remove newline */
1528141cc406Sopenharmony_ci            *(passwd + strlen(passwd) - 1) = '\0';
1529141cc406Sopenharmony_ci            p = crypt(password, SALT);
1530141cc406Sopenharmony_ci            if ( strcmp(p, passwd) == 0 )
1531141cc406Sopenharmony_ci              {
1532141cc406Sopenharmony_ci                /* authentication ok */
1533141cc406Sopenharmony_ci                status = SANE_STATUS_GOOD;
1534141cc406Sopenharmony_ci                break;
1535141cc406Sopenharmony_ci              }
1536141cc406Sopenharmony_ci            else
1537141cc406Sopenharmony_ci                continue;
1538141cc406Sopenharmony_ci          }
1539141cc406Sopenharmony_ci      } while ( ! ferror(fp) && ! feof(fp) );
1540141cc406Sopenharmony_ci    fclose(fp);
1541141cc406Sopenharmony_ci
1542141cc406Sopenharmony_ci    return status;
1543141cc406Sopenharmony_ci}
1544141cc406Sopenharmony_ci#endif
1545141cc406Sopenharmony_ci
1546141cc406Sopenharmony_ci/*---------- dump_area() -----------------------------------------------------*/
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_cistatic SANE_Status
1549141cc406Sopenharmony_cidump_area(uint8_t *area, int len, char *info)
1550141cc406Sopenharmony_ci{
1551141cc406Sopenharmony_ci    /* this function dumps control or information blocks */
1552141cc406Sopenharmony_ci
1553141cc406Sopenharmony_ci#define BPL    16               /* bytes per line to print */
1554141cc406Sopenharmony_ci
1555141cc406Sopenharmony_ci    int i;
1556141cc406Sopenharmony_ci    int o;
1557141cc406Sopenharmony_ci    int o_limit;
1558141cc406Sopenharmony_ci    char outputline[100];
1559141cc406Sopenharmony_ci    char *outbuf;
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci    if ( ! info[0] )
1562141cc406Sopenharmony_ci        info = "No additional info available";
1563141cc406Sopenharmony_ci
1564141cc406Sopenharmony_ci    DBG(30, "dump_area: %s\n", info);
1565141cc406Sopenharmony_ci
1566141cc406Sopenharmony_ci    outbuf = outputline;
1567141cc406Sopenharmony_ci    o_limit = (len + BPL - 1) / BPL;
1568141cc406Sopenharmony_ci    for ( o = 0; o < o_limit; o++)
1569141cc406Sopenharmony_ci      {
1570141cc406Sopenharmony_ci        sprintf(outbuf, "  %4d: ", o * BPL);
1571141cc406Sopenharmony_ci        outbuf += 8;
1572141cc406Sopenharmony_ci        for ( i=0; i < BPL && (o * BPL + i ) < len; i++)
1573141cc406Sopenharmony_ci          {
1574141cc406Sopenharmony_ci            if ( i == BPL / 2 )
1575141cc406Sopenharmony_ci              {
1576141cc406Sopenharmony_ci                sprintf(outbuf, " ");
1577141cc406Sopenharmony_ci                outbuf +=1;
1578141cc406Sopenharmony_ci              }
1579141cc406Sopenharmony_ci            sprintf(outbuf, "%02x", area[o * BPL + i]);
1580141cc406Sopenharmony_ci            outbuf += 2;
1581141cc406Sopenharmony_ci          }
1582141cc406Sopenharmony_ci
1583141cc406Sopenharmony_ci        sprintf(outbuf, "%*s",  2 * ( 2 + BPL - i), " " );
1584141cc406Sopenharmony_ci        outbuf += (2 * ( 2 + BPL - i));
1585141cc406Sopenharmony_ci        sprintf(outbuf, "%s",  (i == BPL / 2) ? " " : "");
1586141cc406Sopenharmony_ci        outbuf += ((i == BPL / 2) ? 1 : 0);
1587141cc406Sopenharmony_ci
1588141cc406Sopenharmony_ci        for ( i = 0; i < BPL && (o * BPL + i ) < len; i++)
1589141cc406Sopenharmony_ci          {
1590141cc406Sopenharmony_ci            if ( i == BPL / 2 )
1591141cc406Sopenharmony_ci              {
1592141cc406Sopenharmony_ci                sprintf(outbuf, " ");
1593141cc406Sopenharmony_ci                outbuf += 1;
1594141cc406Sopenharmony_ci              }
1595141cc406Sopenharmony_ci            sprintf(outbuf, "%c", isprint(area[o * BPL + i])
1596141cc406Sopenharmony_ci                                  ? area[o * BPL + i]
1597141cc406Sopenharmony_ci                                  : '.');
1598141cc406Sopenharmony_ci            outbuf += 1;
1599141cc406Sopenharmony_ci          }
1600141cc406Sopenharmony_ci        outbuf = outputline;
1601141cc406Sopenharmony_ci        DBG(1, "%s\n", outbuf);
1602141cc406Sopenharmony_ci      }
1603141cc406Sopenharmony_ci
1604141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1605141cc406Sopenharmony_ci}
1606141cc406Sopenharmony_ci
1607141cc406Sopenharmony_ci
1608141cc406Sopenharmony_ci/*---------- dump_area2() ----------------------------------------------------*/
1609141cc406Sopenharmony_ci
1610141cc406Sopenharmony_cistatic SANE_Status
1611141cc406Sopenharmony_cidump_area2(uint8_t *area, int len, char *info)
1612141cc406Sopenharmony_ci{
1613141cc406Sopenharmony_ci
1614141cc406Sopenharmony_ci#define BPL    16               /* bytes per line to print */
1615141cc406Sopenharmony_ci
1616141cc406Sopenharmony_ci    int i;
1617141cc406Sopenharmony_ci    char outputline[100];
1618141cc406Sopenharmony_ci    char *outbuf;
1619141cc406Sopenharmony_ci
1620141cc406Sopenharmony_ci    if ( ! info[0] )
1621141cc406Sopenharmony_ci        info = "No additional info available";
1622141cc406Sopenharmony_ci
1623141cc406Sopenharmony_ci    DBG(1, "[%s]\n", info);
1624141cc406Sopenharmony_ci
1625141cc406Sopenharmony_ci    outbuf = outputline;
1626141cc406Sopenharmony_ci    for ( i = 0; i < len; i++)
1627141cc406Sopenharmony_ci      {
1628141cc406Sopenharmony_ci        sprintf(outbuf, "%02x,", *(area + i));
1629141cc406Sopenharmony_ci        outbuf += 3;
1630141cc406Sopenharmony_ci        if ( ((i+1)%BPL == 0) || (i == len-1) )
1631141cc406Sopenharmony_ci           {
1632141cc406Sopenharmony_ci             outbuf = outputline;
1633141cc406Sopenharmony_ci             DBG(1, "%s\n", outbuf);
1634141cc406Sopenharmony_ci           }
1635141cc406Sopenharmony_ci      }
1636141cc406Sopenharmony_ci
1637141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1638141cc406Sopenharmony_ci}
1639141cc406Sopenharmony_ci
1640141cc406Sopenharmony_ci/*---------- dump_to_file() --------------------------------------------------*/
1641141cc406Sopenharmony_ci/*---  only for debugging, currently not used -----*/
1642141cc406Sopenharmony_ci#if 0
1643141cc406Sopenharmony_cistatic SANE_Status
1644141cc406Sopenharmony_cidump_to_file(uint8_t *area, int len, char *filename, char *mode)
1645141cc406Sopenharmony_ci{
1646141cc406Sopenharmony_ciFILE *out;
1647141cc406Sopenharmony_ciint i;
1648141cc406Sopenharmony_ci
1649141cc406Sopenharmony_ci    out = fopen(filename, mode);
1650141cc406Sopenharmony_ci
1651141cc406Sopenharmony_ci    for ( i = 0; i < len; i++)
1652141cc406Sopenharmony_ci         fputc( *(area + i ), out);
1653141cc406Sopenharmony_ci
1654141cc406Sopenharmony_ci    fclose(out);
1655141cc406Sopenharmony_ci
1656141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1657141cc406Sopenharmony_ci}
1658141cc406Sopenharmony_ci#endif
1659141cc406Sopenharmony_ci
1660141cc406Sopenharmony_ci/*---------- dump_attributes() -----------------------------------------------*/
1661141cc406Sopenharmony_ci
1662141cc406Sopenharmony_cistatic SANE_Status
1663141cc406Sopenharmony_cidump_attributes(Microtek2_Info *mi)
1664141cc406Sopenharmony_ci{
1665141cc406Sopenharmony_ci  /* dump all we know about the scanner */
1666141cc406Sopenharmony_ci
1667141cc406Sopenharmony_ci  int i;
1668141cc406Sopenharmony_ci
1669141cc406Sopenharmony_ci  DBG(30, "dump_attributes: mi=%p\n", (void *) mi);
1670141cc406Sopenharmony_ci  DBG(1, "\n");
1671141cc406Sopenharmony_ci  DBG(1, "Scanner attributes from device structure\n");
1672141cc406Sopenharmony_ci  DBG(1, "========================================\n");
1673141cc406Sopenharmony_ci  DBG(1, "Scanner ID...\n");
1674141cc406Sopenharmony_ci  DBG(1, "~~~~~~~~~~~~~\n");
1675141cc406Sopenharmony_ci  DBG(1, "  Vendor Name%15s: '%s'\n", " ", mi->vendor);
1676141cc406Sopenharmony_ci  DBG(1, "  Model Name%16s: '%s'\n", " ", mi->model);
1677141cc406Sopenharmony_ci  DBG(1, "  Revision%18s: '%s'\n", " ", mi->revision);
1678141cc406Sopenharmony_ci  DBG(1, "  Model Code%16s: 0x%02x\n"," ", mi->model_code);
1679141cc406Sopenharmony_ci  switch(mi->model_code)
1680141cc406Sopenharmony_ci    {
1681141cc406Sopenharmony_ci      case 0x80: DBG(1,  "Redondo 2000XL / ArtixScan 2020\n"); break;
1682141cc406Sopenharmony_ci      case 0x81: DBG(1,  "ScanMaker 4 / Aruba\n"); break;
1683141cc406Sopenharmony_ci      case 0x82: DBG(1,  "Bali\n"); break;
1684141cc406Sopenharmony_ci      case 0x83: DBG(1,  "Washington\n"); break;
1685141cc406Sopenharmony_ci      case 0x84: DBG(1,  "Manhattan\n"); break;
1686141cc406Sopenharmony_ci      case 0x85: DBG(1,  "ScanMaker V300 / Phantom parallel / TR3\n"); break;
1687141cc406Sopenharmony_ci      case 0x86: DBG(1,  "CCP\n"); break;
1688141cc406Sopenharmony_ci      case 0x87: DBG(1,  "Scanmaker V\n"); break;
1689141cc406Sopenharmony_ci      case 0x88: DBG(1,  "Scanmaker VI\n"); break;
1690141cc406Sopenharmony_ci      case 0x89: DBG(1,  "ScanMaker 6400XL / A3-400\n"); break;
1691141cc406Sopenharmony_ci      case 0x8a: DBG(1,  "ScanMaker 9600XL / A3-600\n"); break;
1692141cc406Sopenharmony_ci      case 0x8b: DBG(1,  "Watt\n"); break;
1693141cc406Sopenharmony_ci      case 0x8c: DBG(1,  "ScanMaker V600 / TR6\n"); break;
1694141cc406Sopenharmony_ci      case 0x8d: DBG(1,  "ScanMaker V310 / Tr3 10-bit\n"); break;
1695141cc406Sopenharmony_ci      case 0x8e: DBG(1,  "CCB\n"); break;
1696141cc406Sopenharmony_ci      case 0x8f: DBG(1,  "Sun Rise\n"); break;
1697141cc406Sopenharmony_ci      case 0x90: DBG(1,  "ScanMaker E3+ 10-bit\n"); break;
1698141cc406Sopenharmony_ci      case 0x91: DBG(1,  "ScanMaker X6 / Phantom 636\n"); break;
1699141cc406Sopenharmony_ci      case 0x92: DBG(1,  "ScanMaker E3+ / Vobis Highscan\n"); break;
1700141cc406Sopenharmony_ci      case 0x93: DBG(1,  "ScanMaker V310\n"); break;
1701141cc406Sopenharmony_ci      case 0x94: DBG(1,  "SlimScan C3 / Phantom 330cx / 336cx\n"); break;
1702141cc406Sopenharmony_ci      case 0x95: DBG(1,  "ArtixScan 1010\n"); break;
1703141cc406Sopenharmony_ci      case 0x97: DBG(1,  "ScanMaker V636\n"); break;
1704141cc406Sopenharmony_ci      case 0x98: DBG(1,  "ScanMaker X6EL\n"); break;
1705141cc406Sopenharmony_ci      case 0x99: DBG(1,  "ScanMaker X6 / X6USB\n"); break;
1706141cc406Sopenharmony_ci      case 0x9a: DBG(1,  "SlimScan C6 / Phantom 636cx\n"); break;
1707141cc406Sopenharmony_ci      case 0x9d: DBG(1,  "AGFA DuoScan T1200\n"); break;
1708141cc406Sopenharmony_ci      case 0xa0: DBG(1,  "SlimScan C3 / Phantom 336cx\n"); break;
1709141cc406Sopenharmony_ci      case 0xac: DBG(1,  "ScanMaker V6UL\n"); break;
1710141cc406Sopenharmony_ci      case 0xa3: DBG(1,  "ScanMaker V6USL\n"); break;
1711141cc406Sopenharmony_ci      case 0xaf: DBG(1,  "SlimScan C3 / Phantom 336cx\n"); break;
1712141cc406Sopenharmony_ci      case 0xb0: DBG(1,  "ScanMaker X12USL\n"); break;
1713141cc406Sopenharmony_ci      case 0xb3: DBG(1,  "ScanMaker 3600\n"); break;
1714141cc406Sopenharmony_ci      case 0xb4: DBG(1,  "ScanMaker 4700\n"); break;
1715141cc406Sopenharmony_ci      case 0xb6: DBG(1,  "ScanMaker V6UPL\n"); break;
1716141cc406Sopenharmony_ci      case 0xb8: DBG(1,  "ScanMaker 3700\n"); break;
1717141cc406Sopenharmony_ci      case 0xde: DBG(1,  "ScanMaker 9800XL\n"); break;
1718141cc406Sopenharmony_ci      default:   DBG(1,  "Unknown\n"); break;
1719141cc406Sopenharmony_ci    }
1720141cc406Sopenharmony_ci  DBG(1, "  Device Type Code%10s: 0x%02x (%s),\n", " ",
1721141cc406Sopenharmony_ci                  mi->device_type,
1722141cc406Sopenharmony_ci		  mi->device_type & MI_DEVTYPE_SCANNER ?
1723141cc406Sopenharmony_ci                  "Scanner" : "Unknown type");
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci  switch (mi->scanner_type)
1726141cc406Sopenharmony_ci    {
1727141cc406Sopenharmony_ci      case MI_TYPE_FLATBED:
1728141cc406Sopenharmony_ci          DBG(1, "  Scanner type%14s:%s", " ", " Flatbed scanner\n");
1729141cc406Sopenharmony_ci          break;
1730141cc406Sopenharmony_ci      case MI_TYPE_TRANSPARENCY:
1731141cc406Sopenharmony_ci          DBG(1, "  Scanner type%14s:%s", " ", " Transparency scanner\n");
1732141cc406Sopenharmony_ci          break;
1733141cc406Sopenharmony_ci      case MI_TYPE_SHEEDFEED:
1734141cc406Sopenharmony_ci          DBG(1, "  Scanner type%14s:%s", " ", " Sheet feed scanner\n");
1735141cc406Sopenharmony_ci          break;
1736141cc406Sopenharmony_ci      default:
1737141cc406Sopenharmony_ci          DBG(1, "  Scanner type%14s:%s", " ", " Unknown\n");
1738141cc406Sopenharmony_ci          break;
1739141cc406Sopenharmony_ci    }
1740141cc406Sopenharmony_ci
1741141cc406Sopenharmony_ci  DBG(1, "  Supported options%9s: Automatic document feeder: %s\n",
1742141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_ADF ? "Yes" : "No");
1743141cc406Sopenharmony_ci  DBG(1, "%30sTransparency media adapter: %s\n",
1744141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_TMA ? "Yes" : "No");
1745141cc406Sopenharmony_ci  DBG(1, "%30sAuto paper detecting: %s\n",
1746141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_ADP ? "Yes" : "No");
1747141cc406Sopenharmony_ci  DBG(1, "%30sAdvanced picture system: %s\n",
1748141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_APS ? "Yes" : "No");
1749141cc406Sopenharmony_ci  DBG(1, "%30sStripes: %s\n",
1750141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_STRIPE ? "Yes" : "No");
1751141cc406Sopenharmony_ci  DBG(1, "%30sSlides: %s\n",
1752141cc406Sopenharmony_ci		  " ", mi->option_device & MI_OPTDEV_SLIDE ? "Yes" : "No");
1753141cc406Sopenharmony_ci  DBG(1, "  Scan button%15s: %s\n", " ", mi->scnbuttn ? "Yes" : "No");
1754141cc406Sopenharmony_ci
1755141cc406Sopenharmony_ci  DBG(1, "\n");
1756141cc406Sopenharmony_ci  DBG(1, "  Imaging Capabilities...\n");
1757141cc406Sopenharmony_ci  DBG(1, "  ~~~~~~~~~~~~~~~~~~~~~~~\n");
1758141cc406Sopenharmony_ci  DBG(1, "  Color scanner%6s: %s\n", " ", (mi->color) ? "Yes" : "No");
1759141cc406Sopenharmony_ci  DBG(1, "  Number passes%6s: %d pass%s\n", " ",
1760141cc406Sopenharmony_ci                  (mi->onepass) ? 1 : 3,
1761141cc406Sopenharmony_ci                  (mi->onepass) ? "" : "es");
1762141cc406Sopenharmony_ci  DBG(1, "  Resolution%9s: X-max: %5d dpi\n%35sY-max: %5d dpi\n",
1763141cc406Sopenharmony_ci                  " ", mi->max_xresolution, " ",mi->max_yresolution);
1764141cc406Sopenharmony_ci  DBG(1, "  Geometry%11s: Geometric width: %5d pts (%2.2f'')\n", " ",
1765141cc406Sopenharmony_ci          mi->geo_width, (float) mi->geo_width / (float) mi->opt_resolution);
1766141cc406Sopenharmony_ci  DBG(1, "%23sGeometric height:%5d pts (%2.2f'')\n", " ",
1767141cc406Sopenharmony_ci          mi->geo_height, (float) mi->geo_height / (float) mi->opt_resolution);
1768141cc406Sopenharmony_ci  DBG(1, "  Optical resolution%1s: %d\n", " ", mi->opt_resolution);
1769141cc406Sopenharmony_ci
1770141cc406Sopenharmony_ci  DBG(1, "  Modes%14s: Lineart:     %s\n%35sHalftone:     %s\n", " ",
1771141cc406Sopenharmony_ci		  (mi->scanmode & MI_HASMODE_LINEART) ? " Yes" : " No", " ",
1772141cc406Sopenharmony_ci		  (mi->scanmode & MI_HASMODE_HALFTONE) ? "Yes" : "No");
1773141cc406Sopenharmony_ci
1774141cc406Sopenharmony_ci  DBG(1, "%23sGray:     %s\n%35sColor:     %s\n", " ",
1775141cc406Sopenharmony_ci		  (mi->scanmode & MI_HASMODE_GRAY) ? "    Yes" : "    No", " ",
1776141cc406Sopenharmony_ci		  (mi->scanmode & MI_HASMODE_COLOR) ? "   Yes" : "   No");
1777141cc406Sopenharmony_ci
1778141cc406Sopenharmony_ci  DBG(1, "  Depths%14s: Nibble Gray:  %s\n",
1779141cc406Sopenharmony_ci		  " ", (mi->depth & MI_HASDEPTH_NIBBLE) ? "Yes" : "No");
1780141cc406Sopenharmony_ci  DBG(1, "%23s10-bit-color: %s\n",
1781141cc406Sopenharmony_ci                  " ", (mi->depth & MI_HASDEPTH_10) ? "Yes" : "No");
1782141cc406Sopenharmony_ci  DBG(1, "%23s12-bit-color: %s\n", " ",
1783141cc406Sopenharmony_ci		  (mi->depth & MI_HASDEPTH_12) ? "Yes" : "No");
1784141cc406Sopenharmony_ci  DBG(1, "%23s14-bit-color: %s\n", " ",
1785141cc406Sopenharmony_ci		  (mi->depth & MI_HASDEPTH_14) ? "Yes" : "No");
1786141cc406Sopenharmony_ci  DBG(1, "%23s16-bit-color: %s\n", " ",
1787141cc406Sopenharmony_ci		  (mi->depth & MI_HASDEPTH_16) ? "Yes" : "No");
1788141cc406Sopenharmony_ci  DBG(1, "  d/l of HT pattern%2s: %s\n",
1789141cc406Sopenharmony_ci                  " ", (mi->has_dnldptrn) ? "Yes" : "No");
1790141cc406Sopenharmony_ci  DBG(1, "  Builtin HT pattern%1s: %d\n", " ", mi->grain_slct);
1791141cc406Sopenharmony_ci
1792141cc406Sopenharmony_ci  if ( MI_LUTCAP_NONE(mi->lut_cap) )
1793141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   : None\n");
1794141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_256B )
1795141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   :  256 bytes\n");
1796141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_1024B )
1797141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   : 1024 bytes\n");
1798141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_1024W )
1799141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   : 1024 words\n");
1800141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_4096B )
1801141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   : 4096 bytes\n");
1802141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_4096W )
1803141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   : 4096 words\n");
1804141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_64k_W )
1805141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   :  64k words\n");
1806141cc406Sopenharmony_ci  if ( mi->lut_cap & MI_LUTCAP_16k_W )
1807141cc406Sopenharmony_ci      DBG(1, "  LUT capabilities   :  16k words\n");
1808141cc406Sopenharmony_ci  DBG(1, "\n");
1809141cc406Sopenharmony_ci  DBG(1, "  Miscellaneous capabilities...\n");
1810141cc406Sopenharmony_ci  DBG(1, "  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
1811141cc406Sopenharmony_ci  if ( mi->onepass)
1812141cc406Sopenharmony_ci    {
1813141cc406Sopenharmony_ci      switch(mi->data_format)
1814141cc406Sopenharmony_ci        {
1815141cc406Sopenharmony_ci	  case MI_DATAFMT_CHUNKY:
1816141cc406Sopenharmony_ci              DBG(1, "  Data format        :%s",
1817141cc406Sopenharmony_ci                     " Chunky data, R, G & B in one pixel\n");
1818141cc406Sopenharmony_ci              break;
1819141cc406Sopenharmony_ci	  case MI_DATAFMT_LPLCONCAT:
1820141cc406Sopenharmony_ci              DBG(1, "  Data format        :%s",
1821141cc406Sopenharmony_ci                     " Line by line in concatenated sequence,\n");
1822141cc406Sopenharmony_ci              DBG(1, "%23swithout color indicator\n", " ");
1823141cc406Sopenharmony_ci              break;
1824141cc406Sopenharmony_ci	  case MI_DATAFMT_LPLSEGREG:
1825141cc406Sopenharmony_ci              DBG(1, "  Data format        :%s",
1826141cc406Sopenharmony_ci                     " Line by line in segregated sequence,\n");
1827141cc406Sopenharmony_ci              DBG(1, "%23swith color indicator\n", " ");
1828141cc406Sopenharmony_ci              break;
1829141cc406Sopenharmony_ci	  case MI_DATAFMT_WORDCHUNKY:
1830141cc406Sopenharmony_ci              DBG(1, "  Data format        : Word chunky data\n");
1831141cc406Sopenharmony_ci              break;
1832141cc406Sopenharmony_ci          default:
1833141cc406Sopenharmony_ci              DBG(1, "  Data format        : Unknown\n");
1834141cc406Sopenharmony_ci          break;
1835141cc406Sopenharmony_ci        }
1836141cc406Sopenharmony_ci    }
1837141cc406Sopenharmony_ci  else
1838141cc406Sopenharmony_ci      DBG(1, "No information with 3-pass scanners\n");
1839141cc406Sopenharmony_ci
1840141cc406Sopenharmony_ci  DBG(1, "  Color Sequence%17s: \n", " ");
1841141cc406Sopenharmony_ci  for ( i = 0; i < RSA_COLORSEQUENCE_L; i++)
1842141cc406Sopenharmony_ci    {
1843141cc406Sopenharmony_ci      switch(mi->color_sequence[i])
1844141cc406Sopenharmony_ci        {
1845141cc406Sopenharmony_ci	  case MI_COLSEQ_RED:   DBG(1,"%34s%s\n", " ","R"); break;
1846141cc406Sopenharmony_ci	  case MI_COLSEQ_GREEN: DBG(1,"%34s%s\n", " ","G"); break;
1847141cc406Sopenharmony_ci	  case MI_COLSEQ_BLUE:  DBG(1,"%34s%s\n", " ","B"); break;
1848141cc406Sopenharmony_ci        }
1849141cc406Sopenharmony_ci    }
1850141cc406Sopenharmony_ci  if ( mi->new_image_status == SANE_TRUE )
1851141cc406Sopenharmony_ci      DBG(1, "  Using new ReadImageStatus format\n");
1852141cc406Sopenharmony_ci  else
1853141cc406Sopenharmony_ci      DBG(1, "  Using old ReadImageStatus format\n");
1854141cc406Sopenharmony_ci  if ( mi->direction & MI_DATSEQ_RTOL )
1855141cc406Sopenharmony_ci      DBG(1, "  Scanning direction             : right to left\n");
1856141cc406Sopenharmony_ci  else
1857141cc406Sopenharmony_ci      DBG(1, "  Scanning direction             : left to right\n");
1858141cc406Sopenharmony_ci  DBG(1, "  CCD gap%24s: %d lines\n", " ", mi->ccd_gap);
1859141cc406Sopenharmony_ci  DBG(1, "  CCD pixels%21s: %d\n", " ", mi->ccd_pixels);
1860141cc406Sopenharmony_ci  DBG(1, "  Calib white stripe location%4s: %d\n",
1861141cc406Sopenharmony_ci                  " ",  mi->calib_white);
1862141cc406Sopenharmony_ci  DBG(1, "  Max calib space%16s: %d\n", " ", mi->calib_space);
1863141cc406Sopenharmony_ci  DBG(1, "  Number of lens%17s: %d\n", " ", mi->nlens);
1864141cc406Sopenharmony_ci  DBG(1, "  Max number of windows%10s: %d\n", " ", mi->nwindows);
1865141cc406Sopenharmony_ci  DBG(1, "  Shading transfer function%6s: 0x%02x\n", " ",mi->shtrnsferequ);
1866141cc406Sopenharmony_ci  DBG(1, "  Red balance%20s: %d\n", " ", mi->balance[0]);
1867141cc406Sopenharmony_ci  DBG(1, "  Green balance%18s: %d\n", " ", mi->balance[1]);
1868141cc406Sopenharmony_ci  DBG(1, "  Blue balance%19s: %d\n", " " , mi->balance[2]);
1869141cc406Sopenharmony_ci  DBG(1, "  Buffer type%20s: %s\n",
1870141cc406Sopenharmony_ci                  " ",  mi->buftype ? "Ping-Pong" : "Ring");
1871141cc406Sopenharmony_ci  DBG(1, "  FEPROM%25s: %s\n", " ", mi->feprom ? "Yes" : "No");
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci  md_dump_clear = 0;
1874141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
1875141cc406Sopenharmony_ci}
1876141cc406Sopenharmony_ci
1877141cc406Sopenharmony_ci/*---------- max_string_size() -----------------------------------------------*/
1878141cc406Sopenharmony_ci
1879141cc406Sopenharmony_cistatic size_t
1880141cc406Sopenharmony_cimax_string_size (const SANE_String_Const strings[])
1881141cc406Sopenharmony_ci{
1882141cc406Sopenharmony_ci  size_t size;
1883141cc406Sopenharmony_ci  size_t max_size = 0;
1884141cc406Sopenharmony_ci  int i;
1885141cc406Sopenharmony_ci
1886141cc406Sopenharmony_ci  for (i = 0; strings[i]; ++i) {
1887141cc406Sopenharmony_ci    size = strlen(strings[i]) + 1; /* +1 because NUL counts as part of string */
1888141cc406Sopenharmony_ci    if (size > max_size) max_size = size;
1889141cc406Sopenharmony_ci  }
1890141cc406Sopenharmony_ci  return max_size;
1891141cc406Sopenharmony_ci}
1892141cc406Sopenharmony_ci
1893141cc406Sopenharmony_ci/*---------- parse_config_file() ---------------------------------------------*/
1894141cc406Sopenharmony_ci
1895141cc406Sopenharmony_cistatic void
1896141cc406Sopenharmony_ciparse_config_file(FILE *fp, Config_Temp **ct)
1897141cc406Sopenharmony_ci{
1898141cc406Sopenharmony_ci    /* builds a list of device names with associated options from the */
1899141cc406Sopenharmony_ci    /* config file for later use, when building the list of devices. */
1900141cc406Sopenharmony_ci    /* ct->device = NULL indicates global options (valid for all devices */
1901141cc406Sopenharmony_ci
1902141cc406Sopenharmony_ci    char s[PATH_MAX];
1903141cc406Sopenharmony_ci    Config_Options global_opts;
1904141cc406Sopenharmony_ci    Config_Temp *hct1;
1905141cc406Sopenharmony_ci    Config_Temp *hct2;
1906141cc406Sopenharmony_ci
1907141cc406Sopenharmony_ci
1908141cc406Sopenharmony_ci    DBG(30, "parse_config_file: fp=%p\n", (void *) fp);
1909141cc406Sopenharmony_ci
1910141cc406Sopenharmony_ci    *ct = hct1 = NULL;
1911141cc406Sopenharmony_ci
1912141cc406Sopenharmony_ci    /* first read global options and store them in global_opts */
1913141cc406Sopenharmony_ci    /* initialize global_opts with default values */
1914141cc406Sopenharmony_ci
1915141cc406Sopenharmony_ci    global_opts = md_options;
1916141cc406Sopenharmony_ci
1917141cc406Sopenharmony_ci    while ( sanei_config_read(s, sizeof(s), fp) )
1918141cc406Sopenharmony_ci      {
1919141cc406Sopenharmony_ci        DBG(100, "parse_config_file: read line: %s\n", s);
1920141cc406Sopenharmony_ci        if ( *s == '#' || *s == '\0' )  /* ignore empty lines and comments */
1921141cc406Sopenharmony_ci            continue;
1922141cc406Sopenharmony_ci
1923141cc406Sopenharmony_ci        if ( strncmp( sanei_config_skip_whitespace(s), "option ", 7) == 0
1924141cc406Sopenharmony_ci          || strncmp( sanei_config_skip_whitespace(s), "option\t", 7) == 0 )
1925141cc406Sopenharmony_ci          {
1926141cc406Sopenharmony_ci            DBG(100, "parse_config_file: found global option %s\n", s);
1927141cc406Sopenharmony_ci            check_option(s, &global_opts);
1928141cc406Sopenharmony_ci          }
1929141cc406Sopenharmony_ci        else                /* it is considered a new device */
1930141cc406Sopenharmony_ci            break;
1931141cc406Sopenharmony_ci      }
1932141cc406Sopenharmony_ci
1933141cc406Sopenharmony_ci    if ( ferror(fp) || feof(fp) )
1934141cc406Sopenharmony_ci      {
1935141cc406Sopenharmony_ci        if ( ferror(fp) )
1936141cc406Sopenharmony_ci            DBG(1, "parse_config_file: fread failed: errno=%d\n", errno);
1937141cc406Sopenharmony_ci
1938141cc406Sopenharmony_ci        return;
1939141cc406Sopenharmony_ci      }
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci    while ( ! feof(fp) && ! ferror(fp) )
1942141cc406Sopenharmony_ci      {
1943141cc406Sopenharmony_ci        if ( *s == '#' || *s == '\0' )  /* ignore empty lines and comments */
1944141cc406Sopenharmony_ci          {
1945141cc406Sopenharmony_ci            sanei_config_read(s, sizeof(s), fp);
1946141cc406Sopenharmony_ci            continue;
1947141cc406Sopenharmony_ci          }
1948141cc406Sopenharmony_ci
1949141cc406Sopenharmony_ci        if ( strncmp( sanei_config_skip_whitespace(s), "option ", 7) == 0
1950141cc406Sopenharmony_ci          || strncmp( sanei_config_skip_whitespace(s), "option\t", 7) == 0 )
1951141cc406Sopenharmony_ci          {
1952141cc406Sopenharmony_ci            /* when we enter this loop for the first time we allocate */
1953141cc406Sopenharmony_ci            /* memory, because the line surely contains a device name, */
1954141cc406Sopenharmony_ci            /* so hct1 is always != NULL at this point */
1955141cc406Sopenharmony_ci            DBG(100, "parse_config_file: found device option %s\n", s);
1956141cc406Sopenharmony_ci            check_option(s, &hct1->opts);
1957141cc406Sopenharmony_ci          }
1958141cc406Sopenharmony_ci
1959141cc406Sopenharmony_ci
1960141cc406Sopenharmony_ci        else                /* it is considered a new device */
1961141cc406Sopenharmony_ci          {
1962141cc406Sopenharmony_ci            DBG(100, "parse_config_file: found device %s\n", s);
1963141cc406Sopenharmony_ci            hct2 = (Config_Temp *) malloc(sizeof(Config_Temp));
1964141cc406Sopenharmony_ci            if ( hct2 == NULL )
1965141cc406Sopenharmony_ci              {
1966141cc406Sopenharmony_ci                DBG(1, "parse_config_file: malloc() failed\n");
1967141cc406Sopenharmony_ci                return;
1968141cc406Sopenharmony_ci              }
1969141cc406Sopenharmony_ci
1970141cc406Sopenharmony_ci            if ( *ct == NULL )   /* first element */
1971141cc406Sopenharmony_ci                *ct = hct1 = hct2;
1972141cc406Sopenharmony_ci
1973141cc406Sopenharmony_ci            hct1->next = hct2;
1974141cc406Sopenharmony_ci            hct1 = hct2;
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_ci            hct1->device = strdup(s);
1977141cc406Sopenharmony_ci            hct1->opts = global_opts;
1978141cc406Sopenharmony_ci            hct1->next = NULL;
1979141cc406Sopenharmony_ci          }
1980141cc406Sopenharmony_ci        sanei_config_read(s, sizeof(s), fp);
1981141cc406Sopenharmony_ci      }
1982141cc406Sopenharmony_ci    /* set filepointer to the beginning of the file */
1983141cc406Sopenharmony_ci    fseek(fp, 0L, SEEK_SET);
1984141cc406Sopenharmony_ci    return;
1985141cc406Sopenharmony_ci}
1986141cc406Sopenharmony_ci
1987141cc406Sopenharmony_ci
1988141cc406Sopenharmony_ci/*---------- signal_handler() ------------------------------------------------*/
1989141cc406Sopenharmony_ci
1990141cc406Sopenharmony_cistatic void
1991141cc406Sopenharmony_cisignal_handler (int signal)
1992141cc406Sopenharmony_ci{
1993141cc406Sopenharmony_ci  if ( signal == SIGTERM )
1994141cc406Sopenharmony_ci    {
1995141cc406Sopenharmony_ci      sanei_scsi_req_flush_all ();
1996141cc406Sopenharmony_ci      _exit (SANE_STATUS_GOOD);
1997141cc406Sopenharmony_ci    }
1998141cc406Sopenharmony_ci}
1999141cc406Sopenharmony_ci
2000141cc406Sopenharmony_ci/*---------- init_options() --------------------------------------------------*/
2001141cc406Sopenharmony_ci
2002141cc406Sopenharmony_cistatic SANE_Status
2003141cc406Sopenharmony_ciinit_options(Microtek2_Scanner *ms, uint8_t current_scan_source)
2004141cc406Sopenharmony_ci{
2005141cc406Sopenharmony_ci    /* This function is called every time, when the scan source changes. */
2006141cc406Sopenharmony_ci    /* The option values, that possibly change, are then reinitialized,  */
2007141cc406Sopenharmony_ci    /* whereas the option descriptors and option values that never */
2008141cc406Sopenharmony_ci    /* change are not */
2009141cc406Sopenharmony_ci
2010141cc406Sopenharmony_ci    SANE_Option_Descriptor *sod;
2011141cc406Sopenharmony_ci    SANE_Status status;
2012141cc406Sopenharmony_ci    Option_Value *val;
2013141cc406Sopenharmony_ci    Microtek2_Device *md;
2014141cc406Sopenharmony_ci    Microtek2_Info *mi;
2015141cc406Sopenharmony_ci    int tablesize;
2016141cc406Sopenharmony_ci    int option_size;
2017141cc406Sopenharmony_ci    int max_gamma_value;
2018141cc406Sopenharmony_ci    int color;
2019141cc406Sopenharmony_ci    int i;
2020141cc406Sopenharmony_ci    static int first_call = 1;     /* indicates, whether option */
2021141cc406Sopenharmony_ci                                   /* descriptors must be initialized */
2022141cc406Sopenharmony_ci       /* cannot be used as after a sane_close the sod's must be initialized */
2023141cc406Sopenharmony_ci
2024141cc406Sopenharmony_ci    DBG(30, "init_options: handle=%p, source=%d\n", (void *) ms,
2025141cc406Sopenharmony_ci	current_scan_source);
2026141cc406Sopenharmony_ci
2027141cc406Sopenharmony_ci    sod = ms->sod;
2028141cc406Sopenharmony_ci    val = ms->val;
2029141cc406Sopenharmony_ci    md = ms->dev;
2030141cc406Sopenharmony_ci    mi = &md->info[current_scan_source];
2031141cc406Sopenharmony_ci
2032141cc406Sopenharmony_ci    /* needed for gamma calculation */
2033141cc406Sopenharmony_ci    get_lut_size(mi, &md->max_lut_size, &md->lut_entry_size);
2034141cc406Sopenharmony_ci
2035141cc406Sopenharmony_ci    /* calculate new values, where possibly needed */
2036141cc406Sopenharmony_ci
2037141cc406Sopenharmony_ci    /* Scan source */
2038141cc406Sopenharmony_ci    if ( val[OPT_SOURCE].s )
2039141cc406Sopenharmony_ci        free((void *) val[OPT_SOURCE].s);
2040141cc406Sopenharmony_ci    i = 0;
2041141cc406Sopenharmony_ci    md->scansource_list[i] = (SANE_String) MD_SOURCESTRING_FLATBED;
2042141cc406Sopenharmony_ci    if ( current_scan_source == MD_SOURCE_FLATBED )
2043141cc406Sopenharmony_ci        val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2044141cc406Sopenharmony_ci    if ( md->status.adfcnt )
2045141cc406Sopenharmony_ci      {
2046141cc406Sopenharmony_ci        md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_ADF;
2047141cc406Sopenharmony_ci        if ( current_scan_source == MD_SOURCE_ADF )
2048141cc406Sopenharmony_ci            val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2049141cc406Sopenharmony_ci      }
2050141cc406Sopenharmony_ci    if ( md->status.tmacnt )
2051141cc406Sopenharmony_ci      {
2052141cc406Sopenharmony_ci        md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_TMA;
2053141cc406Sopenharmony_ci        if ( current_scan_source == MD_SOURCE_TMA )
2054141cc406Sopenharmony_ci            val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2055141cc406Sopenharmony_ci      }
2056141cc406Sopenharmony_ci    if ( mi->option_device & MI_OPTDEV_STRIPE )
2057141cc406Sopenharmony_ci      {
2058141cc406Sopenharmony_ci        md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_STRIPE;
2059141cc406Sopenharmony_ci        if ( current_scan_source == MD_SOURCE_STRIPE )
2060141cc406Sopenharmony_ci            val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2061141cc406Sopenharmony_ci      }
2062141cc406Sopenharmony_ci
2063141cc406Sopenharmony_ci    /* Comment this out as long as I do not know in which bit */
2064141cc406Sopenharmony_ci    /* it is indicated, whether a slide adapter is connected */
2065141cc406Sopenharmony_ci#if 0
2066141cc406Sopenharmony_ci    if ( mi->option_device & MI_OPTDEV_SLIDE )
2067141cc406Sopenharmony_ci      {
2068141cc406Sopenharmony_ci        md->scansource_list[++i] = (SANE_String) MD_SOURCESTRING_SLIDE;
2069141cc406Sopenharmony_ci        if ( current_scan_source == MD_SOURCE_SLIDE )
2070141cc406Sopenharmony_ci            val[OPT_SOURCE].s = (SANE_String) strdup(md->scansource_list[i]);
2071141cc406Sopenharmony_ci      }
2072141cc406Sopenharmony_ci#endif
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_ci    md->scansource_list[++i] = NULL;
2075141cc406Sopenharmony_ci
2076141cc406Sopenharmony_ci    /* Scan mode */
2077141cc406Sopenharmony_ci    if ( val[OPT_MODE].s )
2078141cc406Sopenharmony_ci        free((void *) val[OPT_MODE].s);
2079141cc406Sopenharmony_ci
2080141cc406Sopenharmony_ci    i = 0;
2081141cc406Sopenharmony_ci    if ( (mi->scanmode & MI_HASMODE_COLOR) )
2082141cc406Sopenharmony_ci      {
2083141cc406Sopenharmony_ci	md->scanmode_list[i] = (SANE_String) MD_MODESTRING_COLOR;
2084141cc406Sopenharmony_ci        val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2085141cc406Sopenharmony_ci        ++i;
2086141cc406Sopenharmony_ci      }
2087141cc406Sopenharmony_ci
2088141cc406Sopenharmony_ci    if ( mi->scanmode & MI_HASMODE_GRAY )
2089141cc406Sopenharmony_ci      {
2090141cc406Sopenharmony_ci	md->scanmode_list[i] = (SANE_String) MD_MODESTRING_GRAY;
2091141cc406Sopenharmony_ci        if ( ! (mi->scanmode & MI_HASMODE_COLOR ) )
2092141cc406Sopenharmony_ci            val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2093141cc406Sopenharmony_ci        ++i;
2094141cc406Sopenharmony_ci      }
2095141cc406Sopenharmony_ci
2096141cc406Sopenharmony_ci    if ( mi->scanmode & MI_HASMODE_HALFTONE )
2097141cc406Sopenharmony_ci      {
2098141cc406Sopenharmony_ci	md->scanmode_list[i] = (SANE_String) MD_MODESTRING_HALFTONE;
2099141cc406Sopenharmony_ci        if ( ! (mi->scanmode & MI_HASMODE_COLOR )
2100141cc406Sopenharmony_ci            && ! (mi->scanmode & MI_HASMODE_GRAY ) )
2101141cc406Sopenharmony_ci            val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2102141cc406Sopenharmony_ci        ++i;
2103141cc406Sopenharmony_ci      }
2104141cc406Sopenharmony_ci
2105141cc406Sopenharmony_ci    /* Always enable a lineart mode. Some models (X6, FW 1.40) say */
2106141cc406Sopenharmony_ci    /* that they have no lineart mode. In this case we will do a grayscale */
2107141cc406Sopenharmony_ci    /* scan and convert it to onebit data */
2108141cc406Sopenharmony_ci    md->scanmode_list[i] = (SANE_String) MD_MODESTRING_LINEART;
2109141cc406Sopenharmony_ci    if ( ! (mi->scanmode & MI_HASMODE_COLOR )
2110141cc406Sopenharmony_ci        && ! (mi->scanmode & MI_HASMODE_GRAY )
2111141cc406Sopenharmony_ci        && ! (mi->scanmode & MI_HASMODE_HALFTONE ) )
2112141cc406Sopenharmony_ci        val[OPT_MODE].s = strdup(md->scanmode_list[i]);
2113141cc406Sopenharmony_ci    ++i;
2114141cc406Sopenharmony_ci    md->scanmode_list[i] = NULL;
2115141cc406Sopenharmony_ci
2116141cc406Sopenharmony_ci    /* bitdepth */
2117141cc406Sopenharmony_ci    i = 0;
2118141cc406Sopenharmony_ci
2119141cc406Sopenharmony_ci#if 0
2120141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_NIBBLE )
2121141cc406Sopenharmony_ci        md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_4;
2122141cc406Sopenharmony_ci#endif
2123141cc406Sopenharmony_ci
2124141cc406Sopenharmony_ci    md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_8;
2125141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_10 )
2126141cc406Sopenharmony_ci        md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_10;
2127141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_12 )
2128141cc406Sopenharmony_ci        md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_12;
2129141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_14 )
2130141cc406Sopenharmony_ci        md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_14;
2131141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_16 )
2132141cc406Sopenharmony_ci        md->bitdepth_list[++i] = (SANE_Int) MD_DEPTHVAL_16;
2133141cc406Sopenharmony_ci
2134141cc406Sopenharmony_ci    md->bitdepth_list[0] = i;
2135141cc406Sopenharmony_ci    if (  md->bitdepth_list[1] == (SANE_Int) MD_DEPTHVAL_8 )
2136141cc406Sopenharmony_ci        val[OPT_BITDEPTH].w = md->bitdepth_list[1];
2137141cc406Sopenharmony_ci    else
2138141cc406Sopenharmony_ci        val[OPT_BITDEPTH].w = md->bitdepth_list[2];
2139141cc406Sopenharmony_ci
2140141cc406Sopenharmony_ci    /* Halftone */
2141141cc406Sopenharmony_ci    md->halftone_mode_list[0] = (SANE_String) MD_HALFTONE0;
2142141cc406Sopenharmony_ci    md->halftone_mode_list[1] = (SANE_String) MD_HALFTONE1;
2143141cc406Sopenharmony_ci    md->halftone_mode_list[2] = (SANE_String) MD_HALFTONE2;
2144141cc406Sopenharmony_ci    md->halftone_mode_list[3] = (SANE_String) MD_HALFTONE3;
2145141cc406Sopenharmony_ci    md->halftone_mode_list[4] = (SANE_String) MD_HALFTONE4;
2146141cc406Sopenharmony_ci    md->halftone_mode_list[5] = (SANE_String) MD_HALFTONE5;
2147141cc406Sopenharmony_ci    md->halftone_mode_list[6] = (SANE_String) MD_HALFTONE6;
2148141cc406Sopenharmony_ci    md->halftone_mode_list[7] = (SANE_String) MD_HALFTONE7;
2149141cc406Sopenharmony_ci    md->halftone_mode_list[8] = (SANE_String) MD_HALFTONE8;
2150141cc406Sopenharmony_ci    md->halftone_mode_list[9] = (SANE_String) MD_HALFTONE9;
2151141cc406Sopenharmony_ci    md->halftone_mode_list[10] = (SANE_String) MD_HALFTONE10;
2152141cc406Sopenharmony_ci    md->halftone_mode_list[11] = (SANE_String) MD_HALFTONE11;
2153141cc406Sopenharmony_ci    md->halftone_mode_list[12] = NULL;
2154141cc406Sopenharmony_ci    if ( val[OPT_HALFTONE].s )
2155141cc406Sopenharmony_ci        free((void *) val[OPT_HALFTONE].s);
2156141cc406Sopenharmony_ci    val[OPT_HALFTONE].s = strdup(md->halftone_mode_list[0]);
2157141cc406Sopenharmony_ci
2158141cc406Sopenharmony_ci    /* Resolution */
2159141cc406Sopenharmony_ci    md->x_res_range_dpi.min = SANE_FIX(10.0);
2160141cc406Sopenharmony_ci    md->x_res_range_dpi.max = SANE_FIX(mi->max_xresolution);
2161141cc406Sopenharmony_ci    md->x_res_range_dpi.quant = SANE_FIX(1.0);
2162141cc406Sopenharmony_ci    val[OPT_RESOLUTION].w = MIN(MD_RESOLUTION_DEFAULT, md->x_res_range_dpi.max);
2163141cc406Sopenharmony_ci
2164141cc406Sopenharmony_ci    md->y_res_range_dpi.min = SANE_FIX(10.0);
2165141cc406Sopenharmony_ci    md->y_res_range_dpi.max = SANE_FIX(mi->max_yresolution);
2166141cc406Sopenharmony_ci    md->y_res_range_dpi.quant = SANE_FIX(1.0);
2167141cc406Sopenharmony_ci    val[OPT_Y_RESOLUTION].w = val[OPT_RESOLUTION].w; /* bind is default */
2168141cc406Sopenharmony_ci
2169141cc406Sopenharmony_ci    /* Preview mode */
2170141cc406Sopenharmony_ci    val[OPT_PREVIEW].w = SANE_FALSE;
2171141cc406Sopenharmony_ci
2172141cc406Sopenharmony_ci    /* Geometry */
2173141cc406Sopenharmony_ci    md->x_range_mm.min = SANE_FIX(0.0);
2174141cc406Sopenharmony_ci    md->x_range_mm.max = SANE_FIX((double) mi->geo_width
2175141cc406Sopenharmony_ci                                  / (double) mi->opt_resolution
2176141cc406Sopenharmony_ci                                  * MM_PER_INCH);
2177141cc406Sopenharmony_ci    md->x_range_mm.quant = SANE_FIX(0.0);
2178141cc406Sopenharmony_ci    md->y_range_mm.min = SANE_FIX(0.0);
2179141cc406Sopenharmony_ci    md->y_range_mm.max = SANE_FIX((double) mi->geo_height
2180141cc406Sopenharmony_ci                                  / (double) mi->opt_resolution
2181141cc406Sopenharmony_ci                                  * MM_PER_INCH);
2182141cc406Sopenharmony_ci    md->y_range_mm.quant = SANE_FIX(0.0);
2183141cc406Sopenharmony_ci    val[OPT_TL_X].w = SANE_FIX(0.0);
2184141cc406Sopenharmony_ci    val[OPT_TL_Y].w = SANE_FIX(0.0);
2185141cc406Sopenharmony_ci    val[OPT_BR_X].w = md->x_range_mm.max;
2186141cc406Sopenharmony_ci    val[OPT_BR_Y].w = md->y_range_mm.max;
2187141cc406Sopenharmony_ci
2188141cc406Sopenharmony_ci    /* Enhancement group */
2189141cc406Sopenharmony_ci    val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2190141cc406Sopenharmony_ci    val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2191141cc406Sopenharmony_ci    val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2192141cc406Sopenharmony_ci
2193141cc406Sopenharmony_ci    /* Gamma */
2194141cc406Sopenharmony_ci    /* linear gamma must come first */
2195141cc406Sopenharmony_ci    i = 0;
2196141cc406Sopenharmony_ci    md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_LINEAR;
2197141cc406Sopenharmony_ci    md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_SCALAR;
2198141cc406Sopenharmony_ci    md->gammamode_list[i++] = (SANE_String) MD_GAMMAMODE_CUSTOM;
2199141cc406Sopenharmony_ci    if ( val[OPT_GAMMA_MODE].s )
2200141cc406Sopenharmony_ci        free((void *) val[OPT_GAMMA_MODE].s);
2201141cc406Sopenharmony_ci    val[OPT_GAMMA_MODE].s = strdup(md->gammamode_list[0]);
2202141cc406Sopenharmony_ci
2203141cc406Sopenharmony_ci    md->gammamode_list[i] = NULL;
2204141cc406Sopenharmony_ci
2205141cc406Sopenharmony_ci    /* bind gamma */
2206141cc406Sopenharmony_ci    val[OPT_GAMMA_BIND].w = SANE_TRUE;
2207141cc406Sopenharmony_ci    val[OPT_GAMMA_SCALAR].w = MD_GAMMA_DEFAULT;
2208141cc406Sopenharmony_ci    val[OPT_GAMMA_SCALAR_R].w = MD_GAMMA_DEFAULT;
2209141cc406Sopenharmony_ci    val[OPT_GAMMA_SCALAR_G].w = MD_GAMMA_DEFAULT;
2210141cc406Sopenharmony_ci    val[OPT_GAMMA_SCALAR_B].w = MD_GAMMA_DEFAULT;
2211141cc406Sopenharmony_ci
2212141cc406Sopenharmony_ci    /* If the device supports gamma tables, we allocate memory according */
2213141cc406Sopenharmony_ci    /* to lookup table capabilities, otherwise we allocate 4096 elements */
2214141cc406Sopenharmony_ci    /* which is sufficient for a color depth of 12. If the device */
2215141cc406Sopenharmony_ci    /* does not support gamma tables, we fill the table according to */
2216141cc406Sopenharmony_ci    /* the actual bit depth, i.e. 256 entries with a range of 0..255 */
2217141cc406Sopenharmony_ci    /* if the actual bit depth is 8, for example. This will hopefully*/
2218141cc406Sopenharmony_ci    /* make no trouble if the bit depth is 1. */
2219141cc406Sopenharmony_ci    if ( md->model_flags & MD_NO_GAMMA )
2220141cc406Sopenharmony_ci      {
2221141cc406Sopenharmony_ci        tablesize = 4096;
2222141cc406Sopenharmony_ci        option_size = (int) pow(2.0, (double) val[OPT_BITDEPTH].w );
2223141cc406Sopenharmony_ci        max_gamma_value = option_size - 1;
2224141cc406Sopenharmony_ci      }
2225141cc406Sopenharmony_ci    else
2226141cc406Sopenharmony_ci      {
2227141cc406Sopenharmony_ci        tablesize = md->max_lut_size;
2228141cc406Sopenharmony_ci        option_size = tablesize;
2229141cc406Sopenharmony_ci        max_gamma_value = md->max_lut_size - 1;
2230141cc406Sopenharmony_ci      }
2231141cc406Sopenharmony_ci
2232141cc406Sopenharmony_ci    for ( color = 0; color < 4; color++ )
2233141cc406Sopenharmony_ci      {
2234141cc406Sopenharmony_ci        /* index 0 is used if bind gamma == true, index 1 to 3 */
2235141cc406Sopenharmony_ci        /* if bind gamma == false */
2236141cc406Sopenharmony_ci        if ( md->custom_gamma_table[color] )
2237141cc406Sopenharmony_ci            free((void *) md->custom_gamma_table[color]);
2238141cc406Sopenharmony_ci        md->custom_gamma_table[color] =
2239141cc406Sopenharmony_ci                              (SANE_Int *) malloc(tablesize * sizeof(SANE_Int));
2240141cc406Sopenharmony_ci        DBG(100, "init_options: md->custom_gamma_table[%d]=%p, malloc'd %lu bytes\n",
2241141cc406Sopenharmony_ci            color, (void *) md->custom_gamma_table[color], (u_long) (tablesize * sizeof(SANE_Int)));
2242141cc406Sopenharmony_ci        if ( md->custom_gamma_table[color] == NULL )
2243141cc406Sopenharmony_ci          {
2244141cc406Sopenharmony_ci            DBG(1, "init_options: malloc for custom gamma table failed\n");
2245141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
2246141cc406Sopenharmony_ci          }
2247141cc406Sopenharmony_ci
2248141cc406Sopenharmony_ci        for ( i = 0; i < max_gamma_value; i++ )
2249141cc406Sopenharmony_ci            md->custom_gamma_table[color][i] = i;
2250141cc406Sopenharmony_ci      }
2251141cc406Sopenharmony_ci
2252141cc406Sopenharmony_ci    md->custom_gamma_range.min = 0;
2253141cc406Sopenharmony_ci    md->custom_gamma_range.max =  max_gamma_value;
2254141cc406Sopenharmony_ci    md->custom_gamma_range.quant = 1;
2255141cc406Sopenharmony_ci
2256141cc406Sopenharmony_ci    sod[OPT_GAMMA_CUSTOM].size = option_size * sizeof (SANE_Int);
2257141cc406Sopenharmony_ci    sod[OPT_GAMMA_CUSTOM_R].size = option_size * sizeof (SANE_Int);
2258141cc406Sopenharmony_ci    sod[OPT_GAMMA_CUSTOM_G].size = option_size * sizeof (SANE_Int);
2259141cc406Sopenharmony_ci    sod[OPT_GAMMA_CUSTOM_B].size = option_size * sizeof (SANE_Int);
2260141cc406Sopenharmony_ci
2261141cc406Sopenharmony_ci    val[OPT_GAMMA_CUSTOM].wa = &md->custom_gamma_table[0][0];
2262141cc406Sopenharmony_ci    val[OPT_GAMMA_CUSTOM_R].wa = &md->custom_gamma_table[1][0];
2263141cc406Sopenharmony_ci    val[OPT_GAMMA_CUSTOM_G].wa = &md->custom_gamma_table[2][0];
2264141cc406Sopenharmony_ci    val[OPT_GAMMA_CUSTOM_B].wa = &md->custom_gamma_table[3][0];
2265141cc406Sopenharmony_ci
2266141cc406Sopenharmony_ci    /* Shadow, midtone, highlight, exposure time */
2267141cc406Sopenharmony_ci    md->channel_list[0] = (SANE_String) MD_CHANNEL_MASTER;
2268141cc406Sopenharmony_ci    md->channel_list[1] = (SANE_String) MD_CHANNEL_RED;
2269141cc406Sopenharmony_ci    md->channel_list[2] = (SANE_String) MD_CHANNEL_GREEN;
2270141cc406Sopenharmony_ci    md->channel_list[3] = (SANE_String) MD_CHANNEL_BLUE;
2271141cc406Sopenharmony_ci    md->channel_list[4] = NULL;
2272141cc406Sopenharmony_ci    if ( val[OPT_CHANNEL].s )
2273141cc406Sopenharmony_ci        free((void *) val[OPT_CHANNEL].s);
2274141cc406Sopenharmony_ci    val[OPT_CHANNEL].s = strdup(md->channel_list[0]);
2275141cc406Sopenharmony_ci    val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2276141cc406Sopenharmony_ci    val[OPT_SHADOW_R].w = MD_SHADOW_DEFAULT;
2277141cc406Sopenharmony_ci    val[OPT_SHADOW_G].w = MD_SHADOW_DEFAULT;
2278141cc406Sopenharmony_ci    val[OPT_SHADOW_B].w = MD_SHADOW_DEFAULT;
2279141cc406Sopenharmony_ci    val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2280141cc406Sopenharmony_ci    val[OPT_MIDTONE_R].w = MD_MIDTONE_DEFAULT;
2281141cc406Sopenharmony_ci    val[OPT_MIDTONE_G].w = MD_MIDTONE_DEFAULT;
2282141cc406Sopenharmony_ci    val[OPT_MIDTONE_B].w = MD_MIDTONE_DEFAULT;
2283141cc406Sopenharmony_ci    val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2284141cc406Sopenharmony_ci    val[OPT_HIGHLIGHT_R].w = MD_HIGHLIGHT_DEFAULT;
2285141cc406Sopenharmony_ci    val[OPT_HIGHLIGHT_G].w = MD_HIGHLIGHT_DEFAULT;
2286141cc406Sopenharmony_ci    val[OPT_HIGHLIGHT_B].w = MD_HIGHLIGHT_DEFAULT;
2287141cc406Sopenharmony_ci    val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2288141cc406Sopenharmony_ci    val[OPT_EXPOSURE_R].w = MD_EXPOSURE_DEFAULT;
2289141cc406Sopenharmony_ci    val[OPT_EXPOSURE_G].w = MD_EXPOSURE_DEFAULT;
2290141cc406Sopenharmony_ci    val[OPT_EXPOSURE_B].w = MD_EXPOSURE_DEFAULT;
2291141cc406Sopenharmony_ci
2292141cc406Sopenharmony_ci    /* special options */
2293141cc406Sopenharmony_ci    val[OPT_RESOLUTION_BIND].w = SANE_TRUE;
2294141cc406Sopenharmony_ci
2295141cc406Sopenharmony_ci    /* enable/disable option for backtracking */
2296141cc406Sopenharmony_ci    val[OPT_DISABLE_BACKTRACK].w = md->opt_no_backtrack_default;
2297141cc406Sopenharmony_ci
2298141cc406Sopenharmony_ci    /* enable/disable calibration by backend */
2299141cc406Sopenharmony_ci    val[OPT_CALIB_BACKEND].w = md->opt_backend_calib_default;
2300141cc406Sopenharmony_ci
2301141cc406Sopenharmony_ci    /* turn off the lamp during a scan */
2302141cc406Sopenharmony_ci    val[OPT_LIGHTLID35].w = SANE_FALSE;
2303141cc406Sopenharmony_ci
2304141cc406Sopenharmony_ci    /* auto adjustment of threshold during a lineart scan */
2305141cc406Sopenharmony_ci    val[OPT_AUTOADJUST].w = SANE_FALSE;
2306141cc406Sopenharmony_ci
2307141cc406Sopenharmony_ci    /* color balance (100% means no correction) */
2308141cc406Sopenharmony_ci    val[OPT_BALANCE_R].w = SANE_FIX(100);
2309141cc406Sopenharmony_ci    val[OPT_BALANCE_G].w = SANE_FIX(100);
2310141cc406Sopenharmony_ci    val[OPT_BALANCE_B].w = SANE_FIX(100);
2311141cc406Sopenharmony_ci
2312141cc406Sopenharmony_ci    if ( first_call )
2313141cc406Sopenharmony_ci      {
2314141cc406Sopenharmony_ci        /* initialize option descriptors and ranges */
2315141cc406Sopenharmony_ci
2316141cc406Sopenharmony_ci        /* Percentage range for brightness, contrast */
2317141cc406Sopenharmony_ci        md->percentage_range.min = 0 << SANE_FIXED_SCALE_SHIFT;
2318141cc406Sopenharmony_ci        md->percentage_range.max = 200 << SANE_FIXED_SCALE_SHIFT;
2319141cc406Sopenharmony_ci        md->percentage_range.quant = 1 << SANE_FIXED_SCALE_SHIFT;
2320141cc406Sopenharmony_ci
2321141cc406Sopenharmony_ci        md->threshold_range.min = 1;
2322141cc406Sopenharmony_ci        md->threshold_range.max = 255;
2323141cc406Sopenharmony_ci        md->threshold_range.quant = 1;
2324141cc406Sopenharmony_ci
2325141cc406Sopenharmony_ci        md->scalar_gamma_range.min = SANE_FIX(0.1);
2326141cc406Sopenharmony_ci        md->scalar_gamma_range.max = SANE_FIX(4.0);
2327141cc406Sopenharmony_ci        md->scalar_gamma_range.quant = SANE_FIX(0.1);
2328141cc406Sopenharmony_ci
2329141cc406Sopenharmony_ci        md->shadow_range.min = 0;
2330141cc406Sopenharmony_ci        md->shadow_range.max = 253;
2331141cc406Sopenharmony_ci        md->shadow_range.quant = 1;
2332141cc406Sopenharmony_ci
2333141cc406Sopenharmony_ci        md->midtone_range.min = 1;
2334141cc406Sopenharmony_ci        md->midtone_range.max = 254;
2335141cc406Sopenharmony_ci        md->midtone_range.quant = 1;
2336141cc406Sopenharmony_ci
2337141cc406Sopenharmony_ci        md->highlight_range.min = 2;
2338141cc406Sopenharmony_ci        md->highlight_range.max = 255;
2339141cc406Sopenharmony_ci        md->highlight_range.quant = 1;
2340141cc406Sopenharmony_ci
2341141cc406Sopenharmony_ci        md->exposure_range.min = 0;
2342141cc406Sopenharmony_ci        md->exposure_range.max = 510;
2343141cc406Sopenharmony_ci        md->exposure_range.quant = 2;
2344141cc406Sopenharmony_ci
2345141cc406Sopenharmony_ci        md->balance_range.min = 0;
2346141cc406Sopenharmony_ci        md->balance_range.max = 200 << SANE_FIXED_SCALE_SHIFT;
2347141cc406Sopenharmony_ci        md->balance_range.quant = 1 << SANE_FIXED_SCALE_SHIFT;
2348141cc406Sopenharmony_ci
2349141cc406Sopenharmony_ci        /* default for most options */
2350141cc406Sopenharmony_ci        for ( i = 0; i < NUM_OPTIONS; i++ )
2351141cc406Sopenharmony_ci          {
2352141cc406Sopenharmony_ci            sod[i].type = SANE_TYPE_FIXED;
2353141cc406Sopenharmony_ci            sod[i].unit = SANE_UNIT_NONE;
2354141cc406Sopenharmony_ci            sod[i].size = sizeof(SANE_Fixed);
2355141cc406Sopenharmony_ci            sod[i].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
2356141cc406Sopenharmony_ci            sod[i].constraint_type = SANE_CONSTRAINT_RANGE;
2357141cc406Sopenharmony_ci          }
2358141cc406Sopenharmony_ci
2359141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS;
2360141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
2361141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
2362141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].type = SANE_TYPE_INT;
2363141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].size = sizeof (SANE_Int);
2364141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
2365141cc406Sopenharmony_ci        sod[OPT_NUM_OPTS].constraint_type = SANE_CONSTRAINT_NONE;
2366141cc406Sopenharmony_ci        val[OPT_NUM_OPTS].w = NUM_OPTIONS;      /* NUM_OPTIONS is no option */
2367141cc406Sopenharmony_ci        DBG(255, "sod=%p\n", (void *) sod);
2368141cc406Sopenharmony_ci        DBG(255, "OPT_NUM_OPTS=%d\n", OPT_NUM_OPTS);
2369141cc406Sopenharmony_ci        DBG(255, "SANE_CAP_SOFT_DETECT=%d\n", SANE_CAP_SOFT_DETECT);
2370141cc406Sopenharmony_ci        DBG(255, "OPT_NUM_OPTS.cap=%d\n", sod[0].cap);
2371141cc406Sopenharmony_ci
2372141cc406Sopenharmony_ci        /* The Scan Mode Group */
2373141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].title = M_TITLE_SCANMODEGRP;
2374141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
2375141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].size = 0;
2376141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].desc = "";
2377141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].cap = 0;
2378141cc406Sopenharmony_ci        sod[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2379141cc406Sopenharmony_ci
2380141cc406Sopenharmony_ci        /* Scan source */
2381141cc406Sopenharmony_ci        sod[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
2382141cc406Sopenharmony_ci        sod[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
2383141cc406Sopenharmony_ci        sod[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
2384141cc406Sopenharmony_ci        sod[OPT_SOURCE].type = SANE_TYPE_STRING;
2385141cc406Sopenharmony_ci        sod[OPT_SOURCE].size = max_string_size(md->scansource_list);
2386141cc406Sopenharmony_ci        /* if there is only one scan source, deactivate option */
2387141cc406Sopenharmony_ci        if ( md->scansource_list[1] == NULL )
2388141cc406Sopenharmony_ci            sod[OPT_SOURCE].cap |= SANE_CAP_INACTIVE;
2389141cc406Sopenharmony_ci        sod[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2390141cc406Sopenharmony_ci        sod[OPT_SOURCE].constraint.string_list = md->scansource_list;
2391141cc406Sopenharmony_ci
2392141cc406Sopenharmony_ci        /* Scan mode */
2393141cc406Sopenharmony_ci        sod[OPT_MODE].name = SANE_NAME_SCAN_MODE;
2394141cc406Sopenharmony_ci        sod[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
2395141cc406Sopenharmony_ci        sod[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
2396141cc406Sopenharmony_ci        sod[OPT_MODE].type = SANE_TYPE_STRING;
2397141cc406Sopenharmony_ci        sod[OPT_MODE].size = max_string_size(md->scanmode_list);
2398141cc406Sopenharmony_ci        sod[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2399141cc406Sopenharmony_ci        sod[OPT_MODE].constraint.string_list = md->scanmode_list;
2400141cc406Sopenharmony_ci
2401141cc406Sopenharmony_ci        /* Bit depth */
2402141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].name = SANE_NAME_BIT_DEPTH;
2403141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].title = SANE_TITLE_BIT_DEPTH;
2404141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].desc = SANE_DESC_BIT_DEPTH;
2405141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].type = SANE_TYPE_INT;
2406141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].unit = SANE_UNIT_BIT;
2407141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].size = sizeof(SANE_Int);
2408141cc406Sopenharmony_ci        /* if we have only 8 bit color deactivate this option */
2409141cc406Sopenharmony_ci        if ( md->bitdepth_list[0] == 1 )
2410141cc406Sopenharmony_ci            sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2411141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST;
2412141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].constraint.word_list = md->bitdepth_list;
2413141cc406Sopenharmony_ci
2414141cc406Sopenharmony_ci        /* Halftone */
2415141cc406Sopenharmony_ci        sod[OPT_HALFTONE].name = SANE_NAME_HALFTONE;
2416141cc406Sopenharmony_ci        sod[OPT_HALFTONE].title = SANE_TITLE_HALFTONE;
2417141cc406Sopenharmony_ci        sod[OPT_HALFTONE].desc = SANE_DESC_HALFTONE;
2418141cc406Sopenharmony_ci        sod[OPT_HALFTONE].type = SANE_TYPE_STRING;
2419141cc406Sopenharmony_ci        sod[OPT_HALFTONE].size = max_string_size(md->halftone_mode_list);
2420141cc406Sopenharmony_ci        sod[OPT_HALFTONE].cap  |= SANE_CAP_INACTIVE;
2421141cc406Sopenharmony_ci        sod[OPT_HALFTONE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2422141cc406Sopenharmony_ci        sod[OPT_HALFTONE].constraint.string_list = md->halftone_mode_list;
2423141cc406Sopenharmony_ci
2424141cc406Sopenharmony_ci        /* Resolution */
2425141cc406Sopenharmony_ci        sod[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
2426141cc406Sopenharmony_ci        sod[OPT_RESOLUTION].title = SANE_TITLE_SCAN_X_RESOLUTION;
2427141cc406Sopenharmony_ci        sod[OPT_RESOLUTION].desc = SANE_DESC_SCAN_X_RESOLUTION;
2428141cc406Sopenharmony_ci        sod[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
2429141cc406Sopenharmony_ci        sod[OPT_RESOLUTION].constraint.range = &md->x_res_range_dpi;
2430141cc406Sopenharmony_ci
2431141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].name = SANE_NAME_SCAN_Y_RESOLUTION;
2432141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].title = SANE_TITLE_SCAN_Y_RESOLUTION;
2433141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].desc = SANE_DESC_SCAN_Y_RESOLUTION;
2434141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].unit = SANE_UNIT_DPI;
2435141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
2436141cc406Sopenharmony_ci        sod[OPT_Y_RESOLUTION].constraint.range = &md->y_res_range_dpi;
2437141cc406Sopenharmony_ci
2438141cc406Sopenharmony_ci        /* Preview */
2439141cc406Sopenharmony_ci        sod[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
2440141cc406Sopenharmony_ci        sod[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
2441141cc406Sopenharmony_ci        sod[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
2442141cc406Sopenharmony_ci        sod[OPT_PREVIEW].type = SANE_TYPE_BOOL;
2443141cc406Sopenharmony_ci        sod[OPT_PREVIEW].size = sizeof(SANE_Bool);
2444141cc406Sopenharmony_ci        sod[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
2445141cc406Sopenharmony_ci
2446141cc406Sopenharmony_ci        /* Geometry group, for scan area selection */
2447141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].title = M_TITLE_GEOMGRP;
2448141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
2449141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].size = 0;
2450141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].desc = "";
2451141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
2452141cc406Sopenharmony_ci        sod[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2453141cc406Sopenharmony_ci
2454141cc406Sopenharmony_ci        sod[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
2455141cc406Sopenharmony_ci        sod[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
2456141cc406Sopenharmony_ci        sod[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
2457141cc406Sopenharmony_ci        sod[OPT_TL_X].unit = SANE_UNIT_MM;
2458141cc406Sopenharmony_ci        sod[OPT_TL_X].constraint.range = &md->x_range_mm;
2459141cc406Sopenharmony_ci
2460141cc406Sopenharmony_ci        sod[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
2461141cc406Sopenharmony_ci        sod[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
2462141cc406Sopenharmony_ci        sod[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
2463141cc406Sopenharmony_ci        sod[OPT_TL_Y].unit = SANE_UNIT_MM;
2464141cc406Sopenharmony_ci        sod[OPT_TL_Y].constraint.range = &md->y_range_mm;
2465141cc406Sopenharmony_ci
2466141cc406Sopenharmony_ci        sod[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
2467141cc406Sopenharmony_ci        sod[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
2468141cc406Sopenharmony_ci        sod[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
2469141cc406Sopenharmony_ci        sod[OPT_BR_X].unit = SANE_UNIT_MM;
2470141cc406Sopenharmony_ci        sod[OPT_BR_X].constraint.range = &md->x_range_mm;
2471141cc406Sopenharmony_ci
2472141cc406Sopenharmony_ci        sod[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
2473141cc406Sopenharmony_ci        sod[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
2474141cc406Sopenharmony_ci        sod[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
2475141cc406Sopenharmony_ci        sod[OPT_BR_Y].unit = SANE_UNIT_MM;
2476141cc406Sopenharmony_ci        sod[OPT_BR_Y].constraint.range = &md->y_range_mm;
2477141cc406Sopenharmony_ci
2478141cc406Sopenharmony_ci        /* Enhancement group */
2479141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].title = M_TITLE_ENHANCEGRP;
2480141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
2481141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].desc = "";
2482141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].size = 0;
2483141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].cap = 0;
2484141cc406Sopenharmony_ci        sod[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2485141cc406Sopenharmony_ci
2486141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
2487141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
2488141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
2489141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT;
2490141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].constraint.range = &md->percentage_range;
2491141cc406Sopenharmony_ci
2492141cc406Sopenharmony_ci        sod[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
2493141cc406Sopenharmony_ci        sod[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
2494141cc406Sopenharmony_ci        sod[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
2495141cc406Sopenharmony_ci        sod[OPT_CONTRAST].unit = SANE_UNIT_PERCENT;
2496141cc406Sopenharmony_ci        sod[OPT_CONTRAST].constraint.range = &md->percentage_range;
2497141cc406Sopenharmony_ci
2498141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
2499141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
2500141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
2501141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].type = SANE_TYPE_INT;
2502141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].size = sizeof(SANE_Int);
2503141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2504141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].constraint.range = &md->threshold_range;
2505141cc406Sopenharmony_ci
2506141cc406Sopenharmony_ci        /* automatically adjust threshold for a lineart scan */
2507141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].name = M_NAME_AUTOADJUST;
2508141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].title = M_TITLE_AUTOADJUST;
2509141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].desc = M_DESC_AUTOADJUST;
2510141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].type = SANE_TYPE_BOOL;
2511141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].size = sizeof(SANE_Bool);
2512141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].constraint_type = SANE_CONSTRAINT_NONE;
2513141cc406Sopenharmony_ci        if ( strncmp(md->opts.auto_adjust, "off", 3) == 0 )
2514141cc406Sopenharmony_ci            sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2515141cc406Sopenharmony_ci
2516141cc406Sopenharmony_ci        /* Gamma */
2517141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].title = "Gamma";
2518141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].desc = "";
2519141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].type = SANE_TYPE_GROUP;
2520141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].size = 0;
2521141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].cap = 0;
2522141cc406Sopenharmony_ci        sod[OPT_GAMMA_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2523141cc406Sopenharmony_ci
2524141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].name = M_NAME_GAMMA_MODE;
2525141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].title = M_TITLE_GAMMA_MODE;
2526141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].desc = M_DESC_GAMMA_MODE;
2527141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].type = SANE_TYPE_STRING;
2528141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].size = max_string_size(md->gammamode_list);
2529141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2530141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].constraint.string_list = md->gammamode_list;
2531141cc406Sopenharmony_ci
2532141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].name = M_NAME_GAMMA_BIND;
2533141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].title = M_TITLE_GAMMA_BIND;
2534141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].desc = M_DESC_GAMMA_BIND;
2535141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].type = SANE_TYPE_BOOL;
2536141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].size = sizeof(SANE_Bool);
2537141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].constraint_type = SANE_CONSTRAINT_NONE;
2538141cc406Sopenharmony_ci
2539141cc406Sopenharmony_ci        /* this is active if gamma_bind == true and gammamode == scalar */
2540141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].name = M_NAME_GAMMA_SCALAR;
2541141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].title = M_TITLE_GAMMA_SCALAR;
2542141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].desc = M_DESC_GAMMA_SCALAR;
2543141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
2544141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].constraint.range = &md->scalar_gamma_range;
2545141cc406Sopenharmony_ci
2546141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].name = M_NAME_GAMMA_SCALAR_R;
2547141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].title = M_TITLE_GAMMA_SCALAR_R;
2548141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].desc = M_DESC_GAMMA_SCALAR_R;
2549141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
2550141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].constraint.range = &md->scalar_gamma_range;
2551141cc406Sopenharmony_ci
2552141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].name = M_NAME_GAMMA_SCALAR_G;
2553141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].title = M_TITLE_GAMMA_SCALAR_G;
2554141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].desc = M_DESC_GAMMA_SCALAR_G;
2555141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
2556141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].constraint.range = &md->scalar_gamma_range;
2557141cc406Sopenharmony_ci
2558141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].name = M_NAME_GAMMA_SCALAR_B;
2559141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].title = M_TITLE_GAMMA_SCALAR_B;
2560141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].desc = M_DESC_GAMMA_SCALAR_B;
2561141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
2562141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].constraint.range = &md->scalar_gamma_range;
2563141cc406Sopenharmony_ci
2564141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].name = SANE_NAME_GAMMA_VECTOR;
2565141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].title = SANE_TITLE_GAMMA_VECTOR;
2566141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].desc = SANE_DESC_GAMMA_VECTOR;
2567141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].type = SANE_TYPE_INT;
2568141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
2569141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].size = option_size * sizeof (SANE_Int);
2570141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].constraint.range = &md->custom_gamma_range;
2571141cc406Sopenharmony_ci
2572141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].name = SANE_NAME_GAMMA_VECTOR_R;
2573141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].title = SANE_TITLE_GAMMA_VECTOR_R;
2574141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].desc = SANE_DESC_GAMMA_VECTOR_R;
2575141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].type = SANE_TYPE_INT;
2576141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
2577141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].size = option_size * sizeof (SANE_Int);
2578141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].constraint.range = &md->custom_gamma_range;
2579141cc406Sopenharmony_ci
2580141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].name = SANE_NAME_GAMMA_VECTOR_G;
2581141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].title = SANE_TITLE_GAMMA_VECTOR_G;
2582141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].desc = SANE_DESC_GAMMA_VECTOR_G;
2583141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].type = SANE_TYPE_INT;
2584141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
2585141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].size = option_size * sizeof (SANE_Int);
2586141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].constraint.range = &md->custom_gamma_range;
2587141cc406Sopenharmony_ci
2588141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].name = SANE_NAME_GAMMA_VECTOR_B;
2589141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].title = SANE_TITLE_GAMMA_VECTOR_B;
2590141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].desc = SANE_DESC_GAMMA_VECTOR_B;
2591141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].type = SANE_TYPE_INT;
2592141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
2593141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].size = option_size * sizeof (SANE_Int);
2594141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].constraint.range = &md->custom_gamma_range;
2595141cc406Sopenharmony_ci
2596141cc406Sopenharmony_ci        /* Shadow, midtone, highlight */
2597141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].title = M_TITLE_SMHGRP;
2598141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].desc = "";
2599141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].type = SANE_TYPE_GROUP;
2600141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].size = 0;
2601141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].cap = 0;
2602141cc406Sopenharmony_ci        sod[OPT_SMH_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
2603141cc406Sopenharmony_ci
2604141cc406Sopenharmony_ci        sod[OPT_CHANNEL].name = M_NAME_CHANNEL;
2605141cc406Sopenharmony_ci        sod[OPT_CHANNEL].title = M_TITLE_CHANNEL;
2606141cc406Sopenharmony_ci        sod[OPT_CHANNEL].desc = M_DESC_CHANNEL;
2607141cc406Sopenharmony_ci        sod[OPT_CHANNEL].type = SANE_TYPE_STRING;
2608141cc406Sopenharmony_ci        sod[OPT_CHANNEL].size = max_string_size(md->channel_list);
2609141cc406Sopenharmony_ci        sod[OPT_CHANNEL].constraint_type = SANE_CONSTRAINT_STRING_LIST;
2610141cc406Sopenharmony_ci        sod[OPT_CHANNEL].constraint.string_list = md->channel_list;
2611141cc406Sopenharmony_ci
2612141cc406Sopenharmony_ci        sod[OPT_SHADOW].name = SANE_NAME_SHADOW;
2613141cc406Sopenharmony_ci        sod[OPT_SHADOW].title = SANE_TITLE_SHADOW;
2614141cc406Sopenharmony_ci        sod[OPT_SHADOW].desc = SANE_DESC_SHADOW;
2615141cc406Sopenharmony_ci        sod[OPT_SHADOW].type = SANE_TYPE_INT;
2616141cc406Sopenharmony_ci        sod[OPT_SHADOW].size = sizeof(SANE_Int);
2617141cc406Sopenharmony_ci        sod[OPT_SHADOW].constraint.range = &md->shadow_range;
2618141cc406Sopenharmony_ci
2619141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].name = SANE_NAME_SHADOW_R;
2620141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].title = SANE_TITLE_SHADOW_R;
2621141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].desc = SANE_DESC_SHADOW_R;
2622141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].type = SANE_TYPE_INT;
2623141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].size = sizeof(SANE_Int);
2624141cc406Sopenharmony_ci        sod[OPT_SHADOW_R].constraint.range = &md->shadow_range;
2625141cc406Sopenharmony_ci
2626141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].name = SANE_NAME_SHADOW_G;
2627141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].title = SANE_TITLE_SHADOW_G;
2628141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].desc = SANE_DESC_SHADOW_G;
2629141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].type = SANE_TYPE_INT;
2630141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].size = sizeof(SANE_Int);
2631141cc406Sopenharmony_ci        sod[OPT_SHADOW_G].constraint.range = &md->shadow_range;
2632141cc406Sopenharmony_ci
2633141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].name = SANE_NAME_SHADOW_B;
2634141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].title = SANE_TITLE_SHADOW_B;
2635141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].desc = SANE_DESC_SHADOW_B;
2636141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].type = SANE_TYPE_INT;
2637141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].size = sizeof(SANE_Int);
2638141cc406Sopenharmony_ci        sod[OPT_SHADOW_B].constraint.range = &md->shadow_range;
2639141cc406Sopenharmony_ci
2640141cc406Sopenharmony_ci        sod[OPT_MIDTONE].name = M_NAME_MIDTONE;
2641141cc406Sopenharmony_ci        sod[OPT_MIDTONE].title = M_TITLE_MIDTONE;
2642141cc406Sopenharmony_ci        sod[OPT_MIDTONE].desc = M_DESC_MIDTONE;
2643141cc406Sopenharmony_ci        sod[OPT_MIDTONE].type = SANE_TYPE_INT;
2644141cc406Sopenharmony_ci        sod[OPT_MIDTONE].size = sizeof(SANE_Int);
2645141cc406Sopenharmony_ci        sod[OPT_MIDTONE].constraint.range = &md->midtone_range;
2646141cc406Sopenharmony_ci
2647141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].name = M_NAME_MIDTONE_R;
2648141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].title = M_TITLE_MIDTONE_R;
2649141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].desc = M_DESC_MIDTONE_R;
2650141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].type = SANE_TYPE_INT;
2651141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].size = sizeof(SANE_Int);
2652141cc406Sopenharmony_ci        sod[OPT_MIDTONE_R].constraint.range = &md->midtone_range;
2653141cc406Sopenharmony_ci
2654141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].name = M_NAME_MIDTONE_G;
2655141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].title = M_TITLE_MIDTONE_G;
2656141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].desc = M_DESC_MIDTONE_G;
2657141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].type = SANE_TYPE_INT;
2658141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].size = sizeof(SANE_Int);
2659141cc406Sopenharmony_ci        sod[OPT_MIDTONE_G].constraint.range = &md->midtone_range;
2660141cc406Sopenharmony_ci
2661141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].name = M_NAME_MIDTONE_B;
2662141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].title = M_TITLE_MIDTONE_B;
2663141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].desc = M_DESC_MIDTONE_B;
2664141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].type = SANE_TYPE_INT;
2665141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].size = sizeof(SANE_Int);
2666141cc406Sopenharmony_ci        sod[OPT_MIDTONE_B].constraint.range = &md->midtone_range;
2667141cc406Sopenharmony_ci
2668141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].name = SANE_NAME_HIGHLIGHT;
2669141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].title = SANE_TITLE_HIGHLIGHT;
2670141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].desc = SANE_DESC_HIGHLIGHT;
2671141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].type = SANE_TYPE_INT;
2672141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].size = sizeof(SANE_Int);
2673141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].constraint.range = &md->highlight_range;
2674141cc406Sopenharmony_ci
2675141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].name = SANE_NAME_HIGHLIGHT_R;
2676141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].title = SANE_TITLE_HIGHLIGHT_R;
2677141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].desc = SANE_DESC_HIGHLIGHT_R;
2678141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].type = SANE_TYPE_INT;
2679141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].size = sizeof(SANE_Int);
2680141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_R].constraint.range = &md->highlight_range;
2681141cc406Sopenharmony_ci
2682141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].name = SANE_NAME_HIGHLIGHT_G;
2683141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].title = SANE_TITLE_HIGHLIGHT_G;
2684141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].desc = SANE_DESC_HIGHLIGHT_G;
2685141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].type = SANE_TYPE_INT;
2686141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].size = sizeof(SANE_Int);
2687141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_G].constraint.range = &md->highlight_range;
2688141cc406Sopenharmony_ci
2689141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].name = SANE_NAME_HIGHLIGHT_B;
2690141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].title = SANE_TITLE_HIGHLIGHT_B;
2691141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].desc = SANE_DESC_HIGHLIGHT_B;
2692141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].type = SANE_TYPE_INT;
2693141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].size = sizeof(SANE_Int);
2694141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT_B].constraint.range = &md->highlight_range;
2695141cc406Sopenharmony_ci
2696141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].name = SANE_NAME_SCAN_EXPOS_TIME;
2697141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].title = SANE_TITLE_SCAN_EXPOS_TIME;
2698141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].desc = SANE_DESC_SCAN_EXPOS_TIME;
2699141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].type = SANE_TYPE_INT;
2700141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].unit = SANE_UNIT_PERCENT;
2701141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].size = sizeof(SANE_Int);
2702141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].constraint.range = &md->exposure_range;
2703141cc406Sopenharmony_ci
2704141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].name = SANE_NAME_SCAN_EXPOS_TIME_R;
2705141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].title = SANE_TITLE_SCAN_EXPOS_TIME_R;
2706141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].desc = SANE_DESC_SCAN_EXPOS_TIME_R;
2707141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].type = SANE_TYPE_INT;
2708141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].unit = SANE_UNIT_PERCENT;
2709141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].size = sizeof(SANE_Int);
2710141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_R].constraint.range = &md->exposure_range;
2711141cc406Sopenharmony_ci
2712141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].name = SANE_NAME_SCAN_EXPOS_TIME_G;
2713141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].title = SANE_TITLE_SCAN_EXPOS_TIME_G;
2714141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].desc = SANE_DESC_SCAN_EXPOS_TIME_G;
2715141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].type = SANE_TYPE_INT;
2716141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].unit = SANE_UNIT_PERCENT;
2717141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].size = sizeof(SANE_Int);
2718141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_G].constraint.range = &md->exposure_range;
2719141cc406Sopenharmony_ci
2720141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].name = SANE_NAME_SCAN_EXPOS_TIME_B;
2721141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].title = SANE_TITLE_SCAN_EXPOS_TIME_B;
2722141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].desc = SANE_DESC_SCAN_EXPOS_TIME_B;
2723141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].type = SANE_TYPE_INT;
2724141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].unit = SANE_UNIT_PERCENT;
2725141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].size = sizeof(SANE_Int);
2726141cc406Sopenharmony_ci        sod[OPT_EXPOSURE_B].constraint.range = &md->exposure_range;
2727141cc406Sopenharmony_ci
2728141cc406Sopenharmony_ci        /* The Special Options Group */
2729141cc406Sopenharmony_ci        sod[OPT_SPECIAL].title = M_TITLE_SPECIALGRP;
2730141cc406Sopenharmony_ci        sod[OPT_SPECIAL].type = SANE_TYPE_GROUP;
2731141cc406Sopenharmony_ci        sod[OPT_SPECIAL].size = 0;
2732141cc406Sopenharmony_ci        sod[OPT_SPECIAL].desc = "";
2733141cc406Sopenharmony_ci        sod[OPT_SPECIAL].cap = SANE_CAP_ADVANCED;
2734141cc406Sopenharmony_ci        sod[OPT_SPECIAL].constraint_type = SANE_CONSTRAINT_NONE;
2735141cc406Sopenharmony_ci
2736141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].name = SANE_NAME_RESOLUTION_BIND;
2737141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].title = SANE_TITLE_RESOLUTION_BIND;
2738141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].desc = SANE_DESC_RESOLUTION_BIND;
2739141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].type = SANE_TYPE_BOOL;
2740141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].size = sizeof(SANE_Bool);
2741141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].cap |= SANE_CAP_ADVANCED;
2742141cc406Sopenharmony_ci        sod[OPT_RESOLUTION_BIND].constraint_type = SANE_CONSTRAINT_NONE;
2743141cc406Sopenharmony_ci
2744141cc406Sopenharmony_ci        /* enable/disable option for backtracking */
2745141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].name = M_NAME_NOBACKTRACK;
2746141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].title = M_TITLE_NOBACKTRACK;
2747141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].desc = M_DESC_NOBACKTRACK;
2748141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].type = SANE_TYPE_BOOL;
2749141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].size = sizeof(SANE_Bool);
2750141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].cap |= SANE_CAP_ADVANCED;
2751141cc406Sopenharmony_ci        sod[OPT_DISABLE_BACKTRACK].constraint_type = SANE_CONSTRAINT_NONE;
2752141cc406Sopenharmony_ci        if ( strncmp(md->opts.no_backtracking, "off", 3) == 0 )
2753141cc406Sopenharmony_ci            sod[OPT_DISABLE_BACKTRACK].cap |= SANE_CAP_INACTIVE;
2754141cc406Sopenharmony_ci
2755141cc406Sopenharmony_ci        /* calibration by driver */
2756141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].name = M_NAME_CALIBBACKEND;
2757141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].title = M_TITLE_CALIBBACKEND;
2758141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].desc = M_DESC_CALIBBACKEND;
2759141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].type = SANE_TYPE_BOOL;
2760141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].size = sizeof(SANE_Bool);
2761141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].cap |= SANE_CAP_ADVANCED;
2762141cc406Sopenharmony_ci        sod[OPT_CALIB_BACKEND].constraint_type = SANE_CONSTRAINT_NONE;
2763141cc406Sopenharmony_ci        if ( strncmp(md->opts.backend_calibration, "off", 3) == 0 )
2764141cc406Sopenharmony_ci            sod[OPT_CALIB_BACKEND].cap |= SANE_CAP_INACTIVE;
2765141cc406Sopenharmony_ci
2766141cc406Sopenharmony_ci        /* turn off the lamp of the flatbed during a scan */
2767141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].name = M_NAME_LIGHTLID35;
2768141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].title = M_TITLE_LIGHTLID35;
2769141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].desc = M_DESC_LIGHTLID35;
2770141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].type = SANE_TYPE_BOOL;
2771141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].size = sizeof(SANE_Bool);
2772141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].cap |= SANE_CAP_ADVANCED;
2773141cc406Sopenharmony_ci        sod[OPT_LIGHTLID35].constraint_type = SANE_CONSTRAINT_NONE;
2774141cc406Sopenharmony_ci        if ( strncmp(md->opts.lightlid35, "off", 3) == 0 )
2775141cc406Sopenharmony_ci            sod[OPT_LIGHTLID35].cap |= SANE_CAP_INACTIVE;
2776141cc406Sopenharmony_ci
2777141cc406Sopenharmony_ci        /* toggle the lamp of the flatbed */
2778141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].name = M_NAME_TOGGLELAMP;
2779141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].title = M_TITLE_TOGGLELAMP;
2780141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].desc = M_DESC_TOGGLELAMP;
2781141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].type = SANE_TYPE_BUTTON;
2782141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].size = 0;
2783141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].cap |= SANE_CAP_ADVANCED;
2784141cc406Sopenharmony_ci        sod[OPT_TOGGLELAMP].constraint_type = SANE_CONSTRAINT_NONE;
2785141cc406Sopenharmony_ci        if ( strncmp(md->opts.toggle_lamp, "off", 3) == 0 )
2786141cc406Sopenharmony_ci            sod[OPT_TOGGLELAMP].cap |= SANE_CAP_INACTIVE;
2787141cc406Sopenharmony_ci
2788141cc406Sopenharmony_ci        /* color balance */
2789141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].title = M_TITLE_COLBALANCEGRP;
2790141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].type = SANE_TYPE_GROUP;
2791141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].size = 0;
2792141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].desc = "";
2793141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].cap = SANE_CAP_ADVANCED;
2794141cc406Sopenharmony_ci        sod[OPT_COLORBALANCE].constraint_type = SANE_CONSTRAINT_NONE;
2795141cc406Sopenharmony_ci
2796141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].name = M_NAME_BALANCE_R;
2797141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].title = M_TITLE_BALANCE_R;
2798141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].desc = M_DESC_BALANCE_R;
2799141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].unit = SANE_UNIT_PERCENT;
2800141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].cap |= SANE_CAP_ADVANCED;
2801141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].constraint.range = &md->balance_range;
2802141cc406Sopenharmony_ci        if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2803141cc406Sopenharmony_ci             sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2804141cc406Sopenharmony_ci
2805141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].name = M_NAME_BALANCE_G;
2806141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].title = M_TITLE_BALANCE_G;
2807141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].desc = M_DESC_BALANCE_G;
2808141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].unit = SANE_UNIT_PERCENT;
2809141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].cap |= SANE_CAP_ADVANCED;
2810141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].constraint.range = &md->balance_range;
2811141cc406Sopenharmony_ci        if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2812141cc406Sopenharmony_ci             sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2813141cc406Sopenharmony_ci
2814141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].name = M_NAME_BALANCE_B;
2815141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].title = M_TITLE_BALANCE_B;
2816141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].desc = M_DESC_BALANCE_B;
2817141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].unit = SANE_UNIT_PERCENT;
2818141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].cap |= SANE_CAP_ADVANCED;
2819141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].constraint.range = &md->balance_range;
2820141cc406Sopenharmony_ci        if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2821141cc406Sopenharmony_ci             sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2822141cc406Sopenharmony_ci
2823141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].name = M_NAME_BALANCE_FW;
2824141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].title = M_TITLE_BALANCE_FW;
2825141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].desc = M_DESC_BALANCE_FW;
2826141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].type = SANE_TYPE_BUTTON;
2827141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].size = 0;
2828141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].cap |= SANE_CAP_ADVANCED;
2829141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].constraint_type = SANE_CONSTRAINT_NONE;
2830141cc406Sopenharmony_ci        if ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 )
2831141cc406Sopenharmony_ci             sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2832141cc406Sopenharmony_ci      }
2833141cc406Sopenharmony_ci
2834141cc406Sopenharmony_ci    status = set_option_dependencies(ms, sod, val);
2835141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
2836141cc406Sopenharmony_ci        return status;
2837141cc406Sopenharmony_ci
2838141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
2839141cc406Sopenharmony_ci}
2840141cc406Sopenharmony_ci
2841141cc406Sopenharmony_ci/*---------- set_option_dependencies() ---------------------------------------*/
2842141cc406Sopenharmony_ci
2843141cc406Sopenharmony_cistatic SANE_Status
2844141cc406Sopenharmony_ciset_option_dependencies(Microtek2_Scanner *ms, SANE_Option_Descriptor *sod,
2845141cc406Sopenharmony_ci                        Option_Value *val)
2846141cc406Sopenharmony_ci{
2847141cc406Sopenharmony_ci
2848141cc406Sopenharmony_ci    Microtek2_Device *md;
2849141cc406Sopenharmony_ci    md = ms->dev;
2850141cc406Sopenharmony_ci
2851141cc406Sopenharmony_ci    DBG(40, "set_option_dependencies: val=%p, sod=%p, mode=%s\n",
2852141cc406Sopenharmony_ci             (void *) val, (void *) sod, val[OPT_MODE].s);
2853141cc406Sopenharmony_ci
2854141cc406Sopenharmony_ci    if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
2855141cc406Sopenharmony_ci      {
2856141cc406Sopenharmony_ci        /* activate brightness,..., deactivate halftone pattern */
2857141cc406Sopenharmony_ci        /* and threshold */
2858141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
2859141cc406Sopenharmony_ci        sod[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
2860141cc406Sopenharmony_ci        sod[OPT_CHANNEL].cap &= ~SANE_CAP_INACTIVE;
2861141cc406Sopenharmony_ci        sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
2862141cc406Sopenharmony_ci        sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
2863141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
2864141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
2865141cc406Sopenharmony_ci        sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2866141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2867141cc406Sopenharmony_ci        if ( md->bitdepth_list[0] != 1 )
2868141cc406Sopenharmony_ci            sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE;
2869141cc406Sopenharmony_ci        else
2870141cc406Sopenharmony_ci            sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2871141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2872141cc406Sopenharmony_ci        if ( ! ( strncmp(md->opts.colorbalance_adjust, "off", 3) == 0 ) )
2873141cc406Sopenharmony_ci          {
2874141cc406Sopenharmony_ci            sod[OPT_BALANCE_R].cap &= ~SANE_CAP_INACTIVE;
2875141cc406Sopenharmony_ci            sod[OPT_BALANCE_G].cap &= ~SANE_CAP_INACTIVE;
2876141cc406Sopenharmony_ci            sod[OPT_BALANCE_B].cap &= ~SANE_CAP_INACTIVE;
2877141cc406Sopenharmony_ci            sod[OPT_BALANCE_FW].cap &= ~SANE_CAP_INACTIVE;
2878141cc406Sopenharmony_ci          }
2879141cc406Sopenharmony_ci        /* reset options values that are inactive to their default */
2880141cc406Sopenharmony_ci        val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2881141cc406Sopenharmony_ci      }
2882141cc406Sopenharmony_ci
2883141cc406Sopenharmony_ci    else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
2884141cc406Sopenharmony_ci      {
2885141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
2886141cc406Sopenharmony_ci        sod[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE;
2887141cc406Sopenharmony_ci        sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2888141cc406Sopenharmony_ci        sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
2889141cc406Sopenharmony_ci        sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
2890141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
2891141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
2892141cc406Sopenharmony_ci        sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2893141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2894141cc406Sopenharmony_ci        if ( md->bitdepth_list[0] != 1 )
2895141cc406Sopenharmony_ci            sod[OPT_BITDEPTH].cap &= ~SANE_CAP_INACTIVE;
2896141cc406Sopenharmony_ci        else
2897141cc406Sopenharmony_ci            sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2898141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2899141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2900141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2901141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2902141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2903141cc406Sopenharmony_ci
2904141cc406Sopenharmony_ci        /* reset options values that are inactive to their default */
2905141cc406Sopenharmony_ci        if ( val[OPT_CHANNEL].s )
2906141cc406Sopenharmony_ci            free((void *) val[OPT_CHANNEL].s);
2907141cc406Sopenharmony_ci        val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2908141cc406Sopenharmony_ci      }
2909141cc406Sopenharmony_ci
2910141cc406Sopenharmony_ci    else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0 )
2911141cc406Sopenharmony_ci      {
2912141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2913141cc406Sopenharmony_ci        sod[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2914141cc406Sopenharmony_ci        sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2915141cc406Sopenharmony_ci        sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
2916141cc406Sopenharmony_ci        sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
2917141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
2918141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
2919141cc406Sopenharmony_ci        sod[OPT_HALFTONE].cap &= ~SANE_CAP_INACTIVE;
2920141cc406Sopenharmony_ci        sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2921141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2922141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
2923141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2924141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2925141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2926141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2927141cc406Sopenharmony_ci
2928141cc406Sopenharmony_ci        /* reset options values that are inactive to their default */
2929141cc406Sopenharmony_ci        val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2930141cc406Sopenharmony_ci        val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2931141cc406Sopenharmony_ci        if ( val[OPT_CHANNEL].s )
2932141cc406Sopenharmony_ci            free((void *) val[OPT_CHANNEL].s);
2933141cc406Sopenharmony_ci        val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2934141cc406Sopenharmony_ci        val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2935141cc406Sopenharmony_ci        val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2936141cc406Sopenharmony_ci        val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2937141cc406Sopenharmony_ci        val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2938141cc406Sopenharmony_ci        val[OPT_THRESHOLD].w = MD_THRESHOLD_DEFAULT;
2939141cc406Sopenharmony_ci      }
2940141cc406Sopenharmony_ci
2941141cc406Sopenharmony_ci    else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
2942141cc406Sopenharmony_ci      {
2943141cc406Sopenharmony_ci        sod[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
2944141cc406Sopenharmony_ci        sod[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
2945141cc406Sopenharmony_ci        sod[OPT_CHANNEL].cap |= SANE_CAP_INACTIVE;
2946141cc406Sopenharmony_ci        sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
2947141cc406Sopenharmony_ci        sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
2948141cc406Sopenharmony_ci        sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
2949141cc406Sopenharmony_ci        sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
2950141cc406Sopenharmony_ci        sod[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE;
2951141cc406Sopenharmony_ci        if ( val[OPT_AUTOADJUST].w == SANE_FALSE )
2952141cc406Sopenharmony_ci            sod[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
2953141cc406Sopenharmony_ci        else
2954141cc406Sopenharmony_ci            sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
2955141cc406Sopenharmony_ci        sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
2956141cc406Sopenharmony_ci        sod[OPT_AUTOADJUST].cap &= ~SANE_CAP_INACTIVE;
2957141cc406Sopenharmony_ci        sod[OPT_BALANCE_R].cap |= SANE_CAP_INACTIVE;
2958141cc406Sopenharmony_ci        sod[OPT_BALANCE_G].cap |= SANE_CAP_INACTIVE;
2959141cc406Sopenharmony_ci        sod[OPT_BALANCE_B].cap |= SANE_CAP_INACTIVE;
2960141cc406Sopenharmony_ci        sod[OPT_BALANCE_FW].cap |= SANE_CAP_INACTIVE;
2961141cc406Sopenharmony_ci
2962141cc406Sopenharmony_ci        /* reset options values that are inactive to their default */
2963141cc406Sopenharmony_ci        val[OPT_BRIGHTNESS].w = MD_BRIGHTNESS_DEFAULT;
2964141cc406Sopenharmony_ci        val[OPT_CONTRAST].w = MD_CONTRAST_DEFAULT;
2965141cc406Sopenharmony_ci        if ( val[OPT_CHANNEL].s )
2966141cc406Sopenharmony_ci            free((void *) val[OPT_CHANNEL].s);
2967141cc406Sopenharmony_ci        val[OPT_CHANNEL].s = strdup((SANE_String) MD_CHANNEL_MASTER);
2968141cc406Sopenharmony_ci        val[OPT_SHADOW].w = MD_SHADOW_DEFAULT;
2969141cc406Sopenharmony_ci        val[OPT_MIDTONE].w = MD_MIDTONE_DEFAULT;
2970141cc406Sopenharmony_ci        val[OPT_HIGHLIGHT].w = MD_HIGHLIGHT_DEFAULT;
2971141cc406Sopenharmony_ci        val[OPT_EXPOSURE].w = MD_EXPOSURE_DEFAULT;
2972141cc406Sopenharmony_ci      }
2973141cc406Sopenharmony_ci
2974141cc406Sopenharmony_ci    else
2975141cc406Sopenharmony_ci      {
2976141cc406Sopenharmony_ci        DBG(1, "set_option_dependencies: unknown mode '%s'\n",
2977141cc406Sopenharmony_ci                val[OPT_MODE].s );
2978141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
2979141cc406Sopenharmony_ci      }
2980141cc406Sopenharmony_ci
2981141cc406Sopenharmony_ci    /* these ones are always inactive if the mode changes */
2982141cc406Sopenharmony_ci    sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
2983141cc406Sopenharmony_ci    sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
2984141cc406Sopenharmony_ci    sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
2985141cc406Sopenharmony_ci    sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
2986141cc406Sopenharmony_ci    sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
2987141cc406Sopenharmony_ci    sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
2988141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
2989141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
2990141cc406Sopenharmony_ci    sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
2991141cc406Sopenharmony_ci    sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
2992141cc406Sopenharmony_ci    sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
2993141cc406Sopenharmony_ci    sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
2994141cc406Sopenharmony_ci
2995141cc406Sopenharmony_ci    /* reset options values that are inactive to their default */
2996141cc406Sopenharmony_ci    val[OPT_SHADOW_R].w = val[OPT_SHADOW_G].w = val[OPT_SHADOW_B].w
2997141cc406Sopenharmony_ci            = MD_SHADOW_DEFAULT;
2998141cc406Sopenharmony_ci    val[OPT_MIDTONE_R].w = val[OPT_MIDTONE_G].w = val[OPT_MIDTONE_B].w
2999141cc406Sopenharmony_ci            = MD_MIDTONE_DEFAULT;
3000141cc406Sopenharmony_ci    val[OPT_HIGHLIGHT_R].w = val[OPT_HIGHLIGHT_G].w = val[OPT_HIGHLIGHT_B].w
3001141cc406Sopenharmony_ci            = MD_HIGHLIGHT_DEFAULT;
3002141cc406Sopenharmony_ci    val[OPT_EXPOSURE_R].w = val[OPT_EXPOSURE_G].w = val[OPT_EXPOSURE_B].w
3003141cc406Sopenharmony_ci            = MD_EXPOSURE_DEFAULT;
3004141cc406Sopenharmony_ci
3005141cc406Sopenharmony_ci    if ( SANE_OPTION_IS_SETTABLE(sod[OPT_GAMMA_MODE].cap) )
3006141cc406Sopenharmony_ci      {
3007141cc406Sopenharmony_ci        restore_gamma_options(sod, val);
3008141cc406Sopenharmony_ci      }
3009141cc406Sopenharmony_ci
3010141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3011141cc406Sopenharmony_ci}
3012141cc406Sopenharmony_ci
3013141cc406Sopenharmony_ci/*---------- sane_control_option() -------------------------------------------*/
3014141cc406Sopenharmony_ci
3015141cc406Sopenharmony_ciSANE_Status
3016141cc406Sopenharmony_cisane_control_option(SANE_Handle handle, SANE_Int option,
3017141cc406Sopenharmony_ci                    SANE_Action action, void *value, SANE_Int *info)
3018141cc406Sopenharmony_ci{
3019141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
3020141cc406Sopenharmony_ci    Microtek2_Device *md;
3021141cc406Sopenharmony_ci    Microtek2_Info *mi;
3022141cc406Sopenharmony_ci    Option_Value *val;
3023141cc406Sopenharmony_ci    SANE_Option_Descriptor *sod;
3024141cc406Sopenharmony_ci    SANE_Status status;
3025141cc406Sopenharmony_ci
3026141cc406Sopenharmony_ci    md = ms->dev;
3027141cc406Sopenharmony_ci    val = &ms->val[0];
3028141cc406Sopenharmony_ci    sod = &ms->sod[0];
3029141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
3030141cc406Sopenharmony_ci
3031141cc406Sopenharmony_ci    if ( ms->scanning )
3032141cc406Sopenharmony_ci        return SANE_STATUS_DEVICE_BUSY;
3033141cc406Sopenharmony_ci
3034141cc406Sopenharmony_ci    if ( option < 0 || option >= NUM_OPTIONS )
3035141cc406Sopenharmony_ci      {
3036141cc406Sopenharmony_ci        DBG(100, "sane_control_option: option %d; action %d \n", option, action);
3037141cc406Sopenharmony_ci        DBG(10, "sane_control_option: option %d invalid\n", option);
3038141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
3039141cc406Sopenharmony_ci      }
3040141cc406Sopenharmony_ci
3041141cc406Sopenharmony_ci    if ( ! SANE_OPTION_IS_ACTIVE(ms->sod[option].cap) )
3042141cc406Sopenharmony_ci      {
3043141cc406Sopenharmony_ci        DBG(100, "sane_control_option: option %d; action %d \n", option, action);
3044141cc406Sopenharmony_ci        DBG(10, "sane_control_option: option %d not active\n", option);
3045141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
3046141cc406Sopenharmony_ci      }
3047141cc406Sopenharmony_ci
3048141cc406Sopenharmony_ci    if ( info )
3049141cc406Sopenharmony_ci        *info = 0;
3050141cc406Sopenharmony_ci
3051141cc406Sopenharmony_ci    switch ( action )
3052141cc406Sopenharmony_ci      {
3053141cc406Sopenharmony_ci        case SANE_ACTION_GET_VALUE:   /* read out option values */
3054141cc406Sopenharmony_ci          switch ( option )
3055141cc406Sopenharmony_ci            {
3056141cc406Sopenharmony_ci              /* word options */
3057141cc406Sopenharmony_ci              case OPT_BITDEPTH:
3058141cc406Sopenharmony_ci              case OPT_RESOLUTION:
3059141cc406Sopenharmony_ci              case OPT_Y_RESOLUTION:
3060141cc406Sopenharmony_ci              case OPT_THRESHOLD:
3061141cc406Sopenharmony_ci              case OPT_TL_X:
3062141cc406Sopenharmony_ci              case OPT_TL_Y:
3063141cc406Sopenharmony_ci              case OPT_BR_X:
3064141cc406Sopenharmony_ci              case OPT_BR_Y:
3065141cc406Sopenharmony_ci              case OPT_PREVIEW:
3066141cc406Sopenharmony_ci              case OPT_BRIGHTNESS:
3067141cc406Sopenharmony_ci              case OPT_CONTRAST:
3068141cc406Sopenharmony_ci              case OPT_SHADOW:
3069141cc406Sopenharmony_ci              case OPT_SHADOW_R:
3070141cc406Sopenharmony_ci              case OPT_SHADOW_G:
3071141cc406Sopenharmony_ci              case OPT_SHADOW_B:
3072141cc406Sopenharmony_ci              case OPT_MIDTONE:
3073141cc406Sopenharmony_ci              case OPT_MIDTONE_R:
3074141cc406Sopenharmony_ci              case OPT_MIDTONE_G:
3075141cc406Sopenharmony_ci              case OPT_MIDTONE_B:
3076141cc406Sopenharmony_ci              case OPT_HIGHLIGHT:
3077141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_R:
3078141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_G:
3079141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_B:
3080141cc406Sopenharmony_ci              case OPT_EXPOSURE:
3081141cc406Sopenharmony_ci              case OPT_EXPOSURE_R:
3082141cc406Sopenharmony_ci              case OPT_EXPOSURE_G:
3083141cc406Sopenharmony_ci              case OPT_EXPOSURE_B:
3084141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR:
3085141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_R:
3086141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_G:
3087141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_B:
3088141cc406Sopenharmony_ci              case OPT_BALANCE_R:
3089141cc406Sopenharmony_ci              case OPT_BALANCE_G:
3090141cc406Sopenharmony_ci              case OPT_BALANCE_B:
3091141cc406Sopenharmony_ci
3092141cc406Sopenharmony_ci                *(SANE_Word *) value = val[option].w;
3093141cc406Sopenharmony_ci
3094141cc406Sopenharmony_ci                if (sod[option].type == SANE_TYPE_FIXED )
3095141cc406Sopenharmony_ci                    DBG(50, "sane_control_option: opt=%d, act=%d, val=%f\n",
3096141cc406Sopenharmony_ci                             option, action, SANE_UNFIX(val[option].w));
3097141cc406Sopenharmony_ci                else
3098141cc406Sopenharmony_ci                    DBG(50, "sane_control_option: opt=%d, act=%d, val=%d\n",
3099141cc406Sopenharmony_ci                             option, action, val[option].w);
3100141cc406Sopenharmony_ci
3101141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3102141cc406Sopenharmony_ci
3103141cc406Sopenharmony_ci              /* boolean options */
3104141cc406Sopenharmony_ci              case OPT_RESOLUTION_BIND:
3105141cc406Sopenharmony_ci              case OPT_DISABLE_BACKTRACK:
3106141cc406Sopenharmony_ci              case OPT_CALIB_BACKEND:
3107141cc406Sopenharmony_ci              case OPT_LIGHTLID35:
3108141cc406Sopenharmony_ci              case OPT_GAMMA_BIND:
3109141cc406Sopenharmony_ci              case OPT_AUTOADJUST:
3110141cc406Sopenharmony_ci                *(SANE_Bool *) value = val[option].w;
3111141cc406Sopenharmony_ci                DBG(50, "sane_control_option: opt=%d, act=%d, val=%d\n",
3112141cc406Sopenharmony_ci                         option, action, val[option].w);
3113141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3114141cc406Sopenharmony_ci
3115141cc406Sopenharmony_ci              /* string options */
3116141cc406Sopenharmony_ci              case OPT_SOURCE:
3117141cc406Sopenharmony_ci              case OPT_MODE:
3118141cc406Sopenharmony_ci              case OPT_HALFTONE:
3119141cc406Sopenharmony_ci              case OPT_CHANNEL:
3120141cc406Sopenharmony_ci              case OPT_GAMMA_MODE:
3121141cc406Sopenharmony_ci                strcpy(value, val[option].s);
3122141cc406Sopenharmony_ci                DBG(50, "sane_control_option: opt=%d, act=%d, val=%s\n",
3123141cc406Sopenharmony_ci                         option, action, val[option].s);
3124141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3125141cc406Sopenharmony_ci
3126141cc406Sopenharmony_ci              /* word array options */
3127141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM:
3128141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_R:
3129141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_G:
3130141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_B:
3131141cc406Sopenharmony_ci                memcpy(value, val[option].wa, sod[option].size);
3132141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3133141cc406Sopenharmony_ci
3134141cc406Sopenharmony_ci              /* button options */
3135141cc406Sopenharmony_ci              case OPT_TOGGLELAMP:
3136141cc406Sopenharmony_ci              case OPT_BALANCE_FW:
3137141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3138141cc406Sopenharmony_ci
3139141cc406Sopenharmony_ci              /* others */
3140141cc406Sopenharmony_ci              case OPT_NUM_OPTS:
3141141cc406Sopenharmony_ci                *(SANE_Word *) value = NUM_OPTIONS;
3142141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3143141cc406Sopenharmony_ci
3144141cc406Sopenharmony_ci              default:
3145141cc406Sopenharmony_ci                return SANE_STATUS_UNSUPPORTED;
3146141cc406Sopenharmony_ci            }
3147141cc406Sopenharmony_ci          /* NOTREACHED */
3148141cc406Sopenharmony_ci          /* break; */
3149141cc406Sopenharmony_ci
3150141cc406Sopenharmony_ci        case SANE_ACTION_SET_VALUE:     /* set option values */
3151141cc406Sopenharmony_ci          if ( ! SANE_OPTION_IS_SETTABLE(sod[option].cap) )
3152141cc406Sopenharmony_ci            {
3153141cc406Sopenharmony_ci              DBG(100, "sane_control_option: option %d; action %d \n",
3154141cc406Sopenharmony_ci                        option, action);
3155141cc406Sopenharmony_ci              DBG(10, "sane_control_option: trying to set unsettable option\n");
3156141cc406Sopenharmony_ci              return SANE_STATUS_INVAL;
3157141cc406Sopenharmony_ci            }
3158141cc406Sopenharmony_ci
3159141cc406Sopenharmony_ci          /* do not check OPT_BR_Y, xscanimage sometimes tries to set */
3160141cc406Sopenharmony_ci          /* it to a too large value; bug in xscanimage ? */
3161141cc406Sopenharmony_ci          /* if ( option != OPT_BR_Y )
3162141cc406Sopenharmony_ci            { */
3163141cc406Sopenharmony_ci              status = sanei_constrain_value(ms->sod + option, value, info);
3164141cc406Sopenharmony_ci              if (status != SANE_STATUS_GOOD)
3165141cc406Sopenharmony_ci                {
3166141cc406Sopenharmony_ci                  DBG(10, "sane_control_option: invalid option value\n");
3167141cc406Sopenharmony_ci                  return status;
3168141cc406Sopenharmony_ci                }
3169141cc406Sopenharmony_ci          /*  } */
3170141cc406Sopenharmony_ci
3171141cc406Sopenharmony_ci          switch ( sod[option].type )
3172141cc406Sopenharmony_ci            {
3173141cc406Sopenharmony_ci              case SANE_TYPE_BOOL:
3174141cc406Sopenharmony_ci                DBG(50, "sane_control_option: option=%d, action=%d, value=%d\n",
3175141cc406Sopenharmony_ci                         option, action, *(SANE_Int *) value);
3176141cc406Sopenharmony_ci                if ( ! ( ( *(SANE_Bool *) value == SANE_TRUE )
3177141cc406Sopenharmony_ci                         || ( *(SANE_Bool *) value == SANE_FALSE ) ) )
3178141cc406Sopenharmony_ci                    {
3179141cc406Sopenharmony_ci                      DBG(10, "sane_control_option: invalid BOOL option value\n");
3180141cc406Sopenharmony_ci                      return SANE_STATUS_INVAL;
3181141cc406Sopenharmony_ci                    }
3182141cc406Sopenharmony_ci                if ( val[option].w == *(SANE_Bool *) value ) /* no change */
3183141cc406Sopenharmony_ci                    return SANE_STATUS_GOOD;
3184141cc406Sopenharmony_ci                val[option].w = *(SANE_Bool *) value;
3185141cc406Sopenharmony_ci                break;
3186141cc406Sopenharmony_ci
3187141cc406Sopenharmony_ci              case SANE_TYPE_INT:
3188141cc406Sopenharmony_ci                if ( sod[option].size == sizeof(SANE_Int) )
3189141cc406Sopenharmony_ci                  {
3190141cc406Sopenharmony_ci                    /* word option */
3191141cc406Sopenharmony_ci                    DBG(50, "sane_control_option: option=%d, action=%d, "
3192141cc406Sopenharmony_ci                            "value=%d\n", option, action, *(SANE_Int *) value);
3193141cc406Sopenharmony_ci                    if ( val[option].w == *(SANE_Int *) value ) /* no change */
3194141cc406Sopenharmony_ci                        return SANE_STATUS_GOOD;
3195141cc406Sopenharmony_ci                    val[option].w = *(SANE_Int *) value;
3196141cc406Sopenharmony_ci                  }
3197141cc406Sopenharmony_ci                else
3198141cc406Sopenharmony_ci                  {
3199141cc406Sopenharmony_ci                    /* word array option */
3200141cc406Sopenharmony_ci                    memcpy(val[option].wa, value, sod[option].size);
3201141cc406Sopenharmony_ci                  }
3202141cc406Sopenharmony_ci                break;
3203141cc406Sopenharmony_ci
3204141cc406Sopenharmony_ci              case SANE_TYPE_FIXED:
3205141cc406Sopenharmony_ci                DBG(50, "sane_control_option: option=%d, action=%d, value=%f\n",
3206141cc406Sopenharmony_ci                         option, action, SANE_UNFIX( *(SANE_Fixed *) value));
3207141cc406Sopenharmony_ci                if ( val[option].w == *(SANE_Fixed *) value ) /* no change */
3208141cc406Sopenharmony_ci                    return SANE_STATUS_GOOD;
3209141cc406Sopenharmony_ci                val[option].w = *(SANE_Fixed *) value;
3210141cc406Sopenharmony_ci                break;
3211141cc406Sopenharmony_ci
3212141cc406Sopenharmony_ci              case SANE_TYPE_STRING:
3213141cc406Sopenharmony_ci                DBG(50, "sane_control_option: option=%d, action=%d, value=%s\n",
3214141cc406Sopenharmony_ci                         option, action, (SANE_String) value);
3215141cc406Sopenharmony_ci                if ( strcmp(val[option].s, (SANE_String) value) == 0 )
3216141cc406Sopenharmony_ci                    return SANE_STATUS_GOOD;         /* no change */
3217141cc406Sopenharmony_ci                if ( val[option].s )
3218141cc406Sopenharmony_ci                    free((void *) val[option].s);
3219141cc406Sopenharmony_ci                val[option].s = strdup(value);
3220141cc406Sopenharmony_ci                if ( val[option].s == NULL )
3221141cc406Sopenharmony_ci                  {
3222141cc406Sopenharmony_ci                    DBG(1, "sane_control_option: strdup failed\n");
3223141cc406Sopenharmony_ci                    return SANE_STATUS_NO_MEM;
3224141cc406Sopenharmony_ci                  }
3225141cc406Sopenharmony_ci                break;
3226141cc406Sopenharmony_ci
3227141cc406Sopenharmony_ci              case SANE_TYPE_BUTTON:
3228141cc406Sopenharmony_ci                break;
3229141cc406Sopenharmony_ci
3230141cc406Sopenharmony_ci              default:
3231141cc406Sopenharmony_ci                DBG(1, "sane_control_option: unknown type %d\n",
3232141cc406Sopenharmony_ci                        sod[option].type);
3233141cc406Sopenharmony_ci                break;
3234141cc406Sopenharmony_ci            }
3235141cc406Sopenharmony_ci
3236141cc406Sopenharmony_ci          switch ( option )
3237141cc406Sopenharmony_ci            {
3238141cc406Sopenharmony_ci              case OPT_RESOLUTION:
3239141cc406Sopenharmony_ci              case OPT_Y_RESOLUTION:
3240141cc406Sopenharmony_ci              case OPT_TL_X:
3241141cc406Sopenharmony_ci              case OPT_TL_Y:
3242141cc406Sopenharmony_ci              case OPT_BR_X:
3243141cc406Sopenharmony_ci              case OPT_BR_Y:
3244141cc406Sopenharmony_ci                if ( info )
3245141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_PARAMS;
3246141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3247141cc406Sopenharmony_ci              case OPT_DISABLE_BACKTRACK:
3248141cc406Sopenharmony_ci              case OPT_CALIB_BACKEND:
3249141cc406Sopenharmony_ci              case OPT_LIGHTLID35:
3250141cc406Sopenharmony_ci              case OPT_PREVIEW:
3251141cc406Sopenharmony_ci              case OPT_BRIGHTNESS:
3252141cc406Sopenharmony_ci              case OPT_THRESHOLD:
3253141cc406Sopenharmony_ci              case OPT_CONTRAST:
3254141cc406Sopenharmony_ci              case OPT_EXPOSURE:
3255141cc406Sopenharmony_ci              case OPT_EXPOSURE_R:
3256141cc406Sopenharmony_ci              case OPT_EXPOSURE_G:
3257141cc406Sopenharmony_ci              case OPT_EXPOSURE_B:
3258141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR:
3259141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_R:
3260141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_G:
3261141cc406Sopenharmony_ci              case OPT_GAMMA_SCALAR_B:
3262141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM:
3263141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_R:
3264141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_G:
3265141cc406Sopenharmony_ci              case OPT_GAMMA_CUSTOM_B:
3266141cc406Sopenharmony_ci              case OPT_HALFTONE:
3267141cc406Sopenharmony_ci              case OPT_BALANCE_R:
3268141cc406Sopenharmony_ci              case OPT_BALANCE_G:
3269141cc406Sopenharmony_ci              case OPT_BALANCE_B:
3270141cc406Sopenharmony_ci               return SANE_STATUS_GOOD;
3271141cc406Sopenharmony_ci
3272141cc406Sopenharmony_ci              case OPT_BITDEPTH:
3273141cc406Sopenharmony_ci                /* If the bitdepth has changed we must change the size of */
3274141cc406Sopenharmony_ci                /* the gamma table if the device does not support gamma */
3275141cc406Sopenharmony_ci                /* tables. This will hopefully cause no trouble if the */
3276141cc406Sopenharmony_ci                /* mode is one bit */
3277141cc406Sopenharmony_ci
3278141cc406Sopenharmony_ci                if ( md->model_flags & MD_NO_GAMMA )
3279141cc406Sopenharmony_ci                  {
3280141cc406Sopenharmony_ci                    int max_gamma_value;
3281141cc406Sopenharmony_ci                    int size;
3282141cc406Sopenharmony_ci                    int color;
3283141cc406Sopenharmony_ci                    int i;
3284141cc406Sopenharmony_ci
3285141cc406Sopenharmony_ci                    size = (int) pow(2.0, (double) val[OPT_BITDEPTH].w) - 1;
3286141cc406Sopenharmony_ci                    max_gamma_value = size - 1;
3287141cc406Sopenharmony_ci                    for ( color = 0; color < 4; color++ )
3288141cc406Sopenharmony_ci                      {
3289141cc406Sopenharmony_ci                        for ( i = 0; i < max_gamma_value; i++ )
3290141cc406Sopenharmony_ci                            md->custom_gamma_table[color][i] = (SANE_Int) i;
3291141cc406Sopenharmony_ci                      }
3292141cc406Sopenharmony_ci                    md->custom_gamma_range.max = (SANE_Int) max_gamma_value;
3293141cc406Sopenharmony_ci                    sod[OPT_GAMMA_CUSTOM].size = size * sizeof (SANE_Int);
3294141cc406Sopenharmony_ci                    sod[OPT_GAMMA_CUSTOM_R].size = size * sizeof (SANE_Int);
3295141cc406Sopenharmony_ci                    sod[OPT_GAMMA_CUSTOM_G].size = size * sizeof (SANE_Int);
3296141cc406Sopenharmony_ci                    sod[OPT_GAMMA_CUSTOM_B].size = size * sizeof (SANE_Int);
3297141cc406Sopenharmony_ci
3298141cc406Sopenharmony_ci                    if ( info )
3299141cc406Sopenharmony_ci                        *info |= SANE_INFO_RELOAD_OPTIONS;
3300141cc406Sopenharmony_ci
3301141cc406Sopenharmony_ci                  }
3302141cc406Sopenharmony_ci
3303141cc406Sopenharmony_ci                if ( info )
3304141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_PARAMS;
3305141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3306141cc406Sopenharmony_ci
3307141cc406Sopenharmony_ci              case OPT_SOURCE:
3308141cc406Sopenharmony_ci                if ( info )
3309141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
3310141cc406Sopenharmony_ci                if ( strcmp(val[option].s, MD_SOURCESTRING_FLATBED) == 0 )
3311141cc406Sopenharmony_ci                    md->scan_source = MD_SOURCE_FLATBED;
3312141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_SOURCESTRING_TMA) == 0 )
3313141cc406Sopenharmony_ci                    md->scan_source = MD_SOURCE_TMA;
3314141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_SOURCESTRING_ADF) == 0 )
3315141cc406Sopenharmony_ci                    md->scan_source = MD_SOURCE_ADF;
3316141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_SOURCESTRING_STRIPE) == 0 )
3317141cc406Sopenharmony_ci                    md->scan_source = MD_SOURCE_STRIPE;
3318141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_SOURCESTRING_SLIDE) == 0 )
3319141cc406Sopenharmony_ci                    md->scan_source = MD_SOURCE_SLIDE;
3320141cc406Sopenharmony_ci                else
3321141cc406Sopenharmony_ci                  {
3322141cc406Sopenharmony_ci                    DBG(1, "sane_control_option: unsupported option %s\n",
3323141cc406Sopenharmony_ci                            val[option].s);
3324141cc406Sopenharmony_ci                    return SANE_STATUS_UNSUPPORTED;
3325141cc406Sopenharmony_ci                  }
3326141cc406Sopenharmony_ci
3327141cc406Sopenharmony_ci                init_options(ms, md->scan_source);
3328141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3329141cc406Sopenharmony_ci
3330141cc406Sopenharmony_ci              case OPT_MODE:
3331141cc406Sopenharmony_ci                if ( info )
3332141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
3333141cc406Sopenharmony_ci
3334141cc406Sopenharmony_ci                status = set_option_dependencies(ms, sod, val);
3335141cc406Sopenharmony_ci
3336141cc406Sopenharmony_ci                /* Options with side effects need special treatment. They are */
3337141cc406Sopenharmony_ci                /* reset, even if they were set by set_option_dependencies(): */
3338141cc406Sopenharmony_ci                /* if we have more than one color depth activate this option */
3339141cc406Sopenharmony_ci
3340141cc406Sopenharmony_ci                if ( md->bitdepth_list[0] == 1 )
3341141cc406Sopenharmony_ci                    sod[OPT_BITDEPTH].cap |= SANE_CAP_INACTIVE;
3342141cc406Sopenharmony_ci                if ( strncmp(md->opts.auto_adjust, "off", 3) == 0 )
3343141cc406Sopenharmony_ci                    sod[OPT_AUTOADJUST].cap |= SANE_CAP_INACTIVE;
3344141cc406Sopenharmony_ci
3345141cc406Sopenharmony_ci                if ( status != SANE_STATUS_GOOD )
3346141cc406Sopenharmony_ci                    return status;
3347141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3348141cc406Sopenharmony_ci
3349141cc406Sopenharmony_ci              case OPT_CHANNEL:
3350141cc406Sopenharmony_ci                if ( info )
3351141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_OPTIONS;
3352141cc406Sopenharmony_ci                if ( strcmp(val[option].s, MD_CHANNEL_MASTER) == 0 )
3353141cc406Sopenharmony_ci                  {
3354141cc406Sopenharmony_ci                    sod[OPT_SHADOW].cap &= ~SANE_CAP_INACTIVE;
3355141cc406Sopenharmony_ci                    sod[OPT_MIDTONE].cap &= ~SANE_CAP_INACTIVE;
3356141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT].cap &= ~SANE_CAP_INACTIVE;
3357141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE].cap &= ~SANE_CAP_INACTIVE;
3358141cc406Sopenharmony_ci                    sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3359141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3360141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3361141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3362141cc406Sopenharmony_ci                    sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3363141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3364141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3365141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3366141cc406Sopenharmony_ci                    sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3367141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3368141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3369141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3370141cc406Sopenharmony_ci                  }
3371141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_CHANNEL_RED) == 0 )
3372141cc406Sopenharmony_ci                  {
3373141cc406Sopenharmony_ci                    sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3374141cc406Sopenharmony_ci                    sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3375141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3376141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3377141cc406Sopenharmony_ci                    sod[OPT_SHADOW_R].cap &= ~SANE_CAP_INACTIVE;
3378141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_R].cap &= ~SANE_CAP_INACTIVE;
3379141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_R].cap &= ~SANE_CAP_INACTIVE;
3380141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_R].cap &= ~SANE_CAP_INACTIVE;
3381141cc406Sopenharmony_ci                    sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3382141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3383141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3384141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3385141cc406Sopenharmony_ci                    sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3386141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3387141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3388141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3389141cc406Sopenharmony_ci                  }
3390141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_CHANNEL_GREEN) == 0 )
3391141cc406Sopenharmony_ci                  {
3392141cc406Sopenharmony_ci                    sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3393141cc406Sopenharmony_ci                    sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3394141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3395141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3396141cc406Sopenharmony_ci                    sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3397141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3398141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3399141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3400141cc406Sopenharmony_ci                    sod[OPT_SHADOW_G].cap &= ~SANE_CAP_INACTIVE;
3401141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_G].cap &= ~SANE_CAP_INACTIVE;
3402141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_G].cap &= ~SANE_CAP_INACTIVE;
3403141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_G].cap &= ~SANE_CAP_INACTIVE;
3404141cc406Sopenharmony_ci                    sod[OPT_SHADOW_B].cap |= SANE_CAP_INACTIVE;
3405141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_B].cap |= SANE_CAP_INACTIVE;
3406141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_B].cap |= SANE_CAP_INACTIVE;
3407141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_B].cap |= SANE_CAP_INACTIVE;
3408141cc406Sopenharmony_ci                  }
3409141cc406Sopenharmony_ci                else if ( strcmp(val[option].s, MD_CHANNEL_BLUE) == 0 )
3410141cc406Sopenharmony_ci                  {
3411141cc406Sopenharmony_ci                    sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE;
3412141cc406Sopenharmony_ci                    sod[OPT_MIDTONE].cap |= SANE_CAP_INACTIVE;
3413141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE;
3414141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE;
3415141cc406Sopenharmony_ci                    sod[OPT_SHADOW_R].cap |= SANE_CAP_INACTIVE;
3416141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_R].cap |= SANE_CAP_INACTIVE;
3417141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_R].cap |= SANE_CAP_INACTIVE;
3418141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_R].cap |= SANE_CAP_INACTIVE;
3419141cc406Sopenharmony_ci                    sod[OPT_SHADOW_G].cap |= SANE_CAP_INACTIVE;
3420141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_G].cap |= SANE_CAP_INACTIVE;
3421141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_G].cap |= SANE_CAP_INACTIVE;
3422141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_G].cap |= SANE_CAP_INACTIVE;
3423141cc406Sopenharmony_ci                    sod[OPT_SHADOW_B].cap &= ~SANE_CAP_INACTIVE;
3424141cc406Sopenharmony_ci                    sod[OPT_MIDTONE_B].cap &= ~SANE_CAP_INACTIVE;
3425141cc406Sopenharmony_ci                    sod[OPT_HIGHLIGHT_B].cap &= ~SANE_CAP_INACTIVE;
3426141cc406Sopenharmony_ci                    sod[OPT_EXPOSURE_B].cap &= ~SANE_CAP_INACTIVE;
3427141cc406Sopenharmony_ci                  }
3428141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3429141cc406Sopenharmony_ci
3430141cc406Sopenharmony_ci              case OPT_GAMMA_MODE:
3431141cc406Sopenharmony_ci                restore_gamma_options(sod, val);
3432141cc406Sopenharmony_ci                if ( info )
3433141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_OPTIONS;
3434141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3435141cc406Sopenharmony_ci
3436141cc406Sopenharmony_ci              case OPT_GAMMA_BIND:
3437141cc406Sopenharmony_ci                restore_gamma_options(sod, val);
3438141cc406Sopenharmony_ci                if ( info )
3439141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_OPTIONS;
3440141cc406Sopenharmony_ci
3441141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3442141cc406Sopenharmony_ci
3443141cc406Sopenharmony_ci              case OPT_SHADOW:
3444141cc406Sopenharmony_ci              case OPT_SHADOW_R:
3445141cc406Sopenharmony_ci              case OPT_SHADOW_G:
3446141cc406Sopenharmony_ci              case OPT_SHADOW_B:
3447141cc406Sopenharmony_ci                if ( val[option].w >= val[option + 1].w )
3448141cc406Sopenharmony_ci                  {
3449141cc406Sopenharmony_ci                    val[option + 1].w = val[option].w + 1;
3450141cc406Sopenharmony_ci                    if ( info )
3451141cc406Sopenharmony_ci                        *info |= SANE_INFO_RELOAD_OPTIONS;
3452141cc406Sopenharmony_ci                  }
3453141cc406Sopenharmony_ci                if ( val[option + 1].w >= val[option + 2].w )
3454141cc406Sopenharmony_ci                    val[option + 2].w = val[option + 1].w + 1;
3455141cc406Sopenharmony_ci
3456141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3457141cc406Sopenharmony_ci
3458141cc406Sopenharmony_ci              case OPT_MIDTONE:
3459141cc406Sopenharmony_ci              case OPT_MIDTONE_R:
3460141cc406Sopenharmony_ci              case OPT_MIDTONE_G:
3461141cc406Sopenharmony_ci              case OPT_MIDTONE_B:
3462141cc406Sopenharmony_ci                if ( val[option].w <= val[option - 1].w )
3463141cc406Sopenharmony_ci                  {
3464141cc406Sopenharmony_ci                    val[option - 1].w = val[option].w - 1;
3465141cc406Sopenharmony_ci                    if ( info )
3466141cc406Sopenharmony_ci                        *info |= SANE_INFO_RELOAD_OPTIONS;
3467141cc406Sopenharmony_ci                  }
3468141cc406Sopenharmony_ci                if ( val[option].w >= val[option + 1].w )
3469141cc406Sopenharmony_ci                  {
3470141cc406Sopenharmony_ci                    val[option + 1].w = val[option].w + 1;
3471141cc406Sopenharmony_ci                    if ( info )
3472141cc406Sopenharmony_ci                        *info |= SANE_INFO_RELOAD_OPTIONS;
3473141cc406Sopenharmony_ci                  }
3474141cc406Sopenharmony_ci
3475141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3476141cc406Sopenharmony_ci
3477141cc406Sopenharmony_ci              case OPT_HIGHLIGHT:
3478141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_R:
3479141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_G:
3480141cc406Sopenharmony_ci              case OPT_HIGHLIGHT_B:
3481141cc406Sopenharmony_ci                if ( val[option].w <= val[option - 1].w )
3482141cc406Sopenharmony_ci                  {
3483141cc406Sopenharmony_ci                    val[option - 1].w = val[option].w - 1;
3484141cc406Sopenharmony_ci                    if ( info )
3485141cc406Sopenharmony_ci                        *info |= SANE_INFO_RELOAD_OPTIONS;
3486141cc406Sopenharmony_ci                  }
3487141cc406Sopenharmony_ci                if ( val[option - 1].w <= val[option - 2].w )
3488141cc406Sopenharmony_ci                    val[option - 2].w = val[option - 1].w - 1;
3489141cc406Sopenharmony_ci
3490141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3491141cc406Sopenharmony_ci
3492141cc406Sopenharmony_ci              case OPT_RESOLUTION_BIND:
3493141cc406Sopenharmony_ci                if ( ms->val[option].w == SANE_FALSE )
3494141cc406Sopenharmony_ci                  {
3495141cc406Sopenharmony_ci                    ms->sod[OPT_Y_RESOLUTION].cap &= ~SANE_CAP_INACTIVE;
3496141cc406Sopenharmony_ci                  }
3497141cc406Sopenharmony_ci                else
3498141cc406Sopenharmony_ci                  {
3499141cc406Sopenharmony_ci                    ms->sod[OPT_Y_RESOLUTION].cap |= SANE_CAP_INACTIVE;
3500141cc406Sopenharmony_ci                  }
3501141cc406Sopenharmony_ci                if ( info )
3502141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_OPTIONS;
3503141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3504141cc406Sopenharmony_ci
3505141cc406Sopenharmony_ci              case OPT_TOGGLELAMP:
3506141cc406Sopenharmony_ci                status = scsi_read_system_status(md, -1);
3507141cc406Sopenharmony_ci                if ( status != SANE_STATUS_GOOD )
3508141cc406Sopenharmony_ci                    return SANE_STATUS_IO_ERROR;
3509141cc406Sopenharmony_ci
3510141cc406Sopenharmony_ci                md->status.flamp ^= 1;
3511141cc406Sopenharmony_ci                status = scsi_send_system_status(md, -1);
3512141cc406Sopenharmony_ci                if ( status != SANE_STATUS_GOOD )
3513141cc406Sopenharmony_ci                    return SANE_STATUS_IO_ERROR;
3514141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3515141cc406Sopenharmony_ci
3516141cc406Sopenharmony_ci              case OPT_AUTOADJUST:
3517141cc406Sopenharmony_ci                if ( info )
3518141cc406Sopenharmony_ci                    *info |= SANE_INFO_RELOAD_OPTIONS;
3519141cc406Sopenharmony_ci
3520141cc406Sopenharmony_ci                if ( ms->val[option].w == SANE_FALSE )
3521141cc406Sopenharmony_ci                    ms->sod[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE;
3522141cc406Sopenharmony_ci                else
3523141cc406Sopenharmony_ci                    ms->sod[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
3524141cc406Sopenharmony_ci
3525141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3526141cc406Sopenharmony_ci
3527141cc406Sopenharmony_ci              case OPT_BALANCE_FW:
3528141cc406Sopenharmony_ci                   val[OPT_BALANCE_R].w =
3529141cc406Sopenharmony_ci                        SANE_FIX((uint8_t)( (float)mi->balance[0] / 2.55 ) );
3530141cc406Sopenharmony_ci                   val[OPT_BALANCE_G].w =
3531141cc406Sopenharmony_ci                        SANE_FIX((uint8_t)( (float)mi->balance[1] / 2.55 ) );
3532141cc406Sopenharmony_ci                   val[OPT_BALANCE_B].w =
3533141cc406Sopenharmony_ci                        SANE_FIX((uint8_t)( (float)mi->balance[2] / 2.55 ) );
3534141cc406Sopenharmony_ci                   if ( info )
3535141cc406Sopenharmony_ci                       *info |= SANE_INFO_RELOAD_OPTIONS;
3536141cc406Sopenharmony_ci
3537141cc406Sopenharmony_ci                return SANE_STATUS_GOOD;
3538141cc406Sopenharmony_ci
3539141cc406Sopenharmony_ci
3540141cc406Sopenharmony_ci              default:
3541141cc406Sopenharmony_ci                return SANE_STATUS_UNSUPPORTED;
3542141cc406Sopenharmony_ci            }
3543141cc406Sopenharmony_ci#if 0
3544141cc406Sopenharmony_ci          break;
3545141cc406Sopenharmony_ci#endif
3546141cc406Sopenharmony_ci        default:
3547141cc406Sopenharmony_ci          DBG(1, "sane_control_option: Unsupported action %d\n", action);
3548141cc406Sopenharmony_ci          return SANE_STATUS_UNSUPPORTED;
3549141cc406Sopenharmony_ci      }
3550141cc406Sopenharmony_ci}
3551141cc406Sopenharmony_ci
3552141cc406Sopenharmony_ci/*---------- sane_get_option_descriptor() ------------------------------------*/
3553141cc406Sopenharmony_ci
3554141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
3555141cc406Sopenharmony_cisane_get_option_descriptor(SANE_Handle handle, SANE_Int n)
3556141cc406Sopenharmony_ci{
3557141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
3558141cc406Sopenharmony_ci
3559141cc406Sopenharmony_ci    DBG(255, "sane_get_option_descriptor: handle=%p, sod=%p, opt=%d\n",
3560141cc406Sopenharmony_ci              (void *) handle, (void *) ms->sod, n);
3561141cc406Sopenharmony_ci
3562141cc406Sopenharmony_ci    if ( n < 0 || n >= NUM_OPTIONS )
3563141cc406Sopenharmony_ci      {
3564141cc406Sopenharmony_ci        DBG(30, "sane_get_option_descriptor: invalid option %d\n", n);
3565141cc406Sopenharmony_ci        return NULL;
3566141cc406Sopenharmony_ci      }
3567141cc406Sopenharmony_ci
3568141cc406Sopenharmony_ci    return &ms->sod[n];
3569141cc406Sopenharmony_ci}
3570141cc406Sopenharmony_ci
3571141cc406Sopenharmony_ci/*---------- restore_gamma_options() -----------------------------------------*/
3572141cc406Sopenharmony_ci
3573141cc406Sopenharmony_cistatic SANE_Status
3574141cc406Sopenharmony_cirestore_gamma_options(SANE_Option_Descriptor *sod, Option_Value *val)
3575141cc406Sopenharmony_ci{
3576141cc406Sopenharmony_ci
3577141cc406Sopenharmony_ci    DBG(40, "restore_gamma_options: val=%p, sod=%p\n", (void *) val, (void *) sod);
3578141cc406Sopenharmony_ci    /* if we don't have a gamma table return immediately */
3579141cc406Sopenharmony_ci    if ( ! val[OPT_GAMMA_MODE].s )
3580141cc406Sopenharmony_ci       return SANE_STATUS_GOOD;
3581141cc406Sopenharmony_ci
3582141cc406Sopenharmony_ci    if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
3583141cc406Sopenharmony_ci      {
3584141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].cap &= ~SANE_CAP_INACTIVE;
3585141cc406Sopenharmony_ci        if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_LINEAR) == 0 )
3586141cc406Sopenharmony_ci          {
3587141cc406Sopenharmony_ci            sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3588141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3589141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3590141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3591141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3592141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3593141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3594141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3595141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3596141cc406Sopenharmony_ci          }
3597141cc406Sopenharmony_ci        else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_SCALAR) == 0 )
3598141cc406Sopenharmony_ci          {
3599141cc406Sopenharmony_ci            sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3600141cc406Sopenharmony_ci            if ( val[OPT_GAMMA_BIND].w == SANE_TRUE )
3601141cc406Sopenharmony_ci              {
3602141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR].cap &= ~SANE_CAP_INACTIVE;
3603141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3604141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3605141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3606141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3607141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3608141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3609141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3610141cc406Sopenharmony_ci              }
3611141cc406Sopenharmony_ci            else
3612141cc406Sopenharmony_ci              {
3613141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3614141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_R].cap &= ~SANE_CAP_INACTIVE;
3615141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_G].cap &= ~SANE_CAP_INACTIVE;
3616141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_B].cap &= ~SANE_CAP_INACTIVE;
3617141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3618141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3619141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3620141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3621141cc406Sopenharmony_ci              }
3622141cc406Sopenharmony_ci          }
3623141cc406Sopenharmony_ci        else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_CUSTOM) == 0 )
3624141cc406Sopenharmony_ci          {
3625141cc406Sopenharmony_ci            sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE;
3626141cc406Sopenharmony_ci            if ( val[OPT_GAMMA_BIND].w == SANE_TRUE )
3627141cc406Sopenharmony_ci              {
3628141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM].cap &= ~SANE_CAP_INACTIVE;
3629141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3630141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3631141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3632141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3633141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3634141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3635141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3636141cc406Sopenharmony_ci              }
3637141cc406Sopenharmony_ci            else
3638141cc406Sopenharmony_ci              {
3639141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3640141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_R].cap &= ~SANE_CAP_INACTIVE;
3641141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_G].cap &= ~SANE_CAP_INACTIVE;
3642141cc406Sopenharmony_ci                sod[OPT_GAMMA_CUSTOM_B].cap &= ~SANE_CAP_INACTIVE;
3643141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3644141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3645141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3646141cc406Sopenharmony_ci                sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3647141cc406Sopenharmony_ci              }
3648141cc406Sopenharmony_ci          }
3649141cc406Sopenharmony_ci      }
3650141cc406Sopenharmony_ci    else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
3651141cc406Sopenharmony_ci      {
3652141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].cap &= ~SANE_CAP_INACTIVE;
3653141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3654141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3655141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3656141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3657141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3658141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3659141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3660141cc406Sopenharmony_ci        if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_LINEAR) == 0 )
3661141cc406Sopenharmony_ci          {
3662141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3663141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3664141cc406Sopenharmony_ci          }
3665141cc406Sopenharmony_ci        else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_SCALAR) == 0 )
3666141cc406Sopenharmony_ci          {
3667141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR].cap &= ~SANE_CAP_INACTIVE;
3668141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3669141cc406Sopenharmony_ci          }
3670141cc406Sopenharmony_ci        else if ( strcmp(val[OPT_GAMMA_MODE].s, MD_GAMMAMODE_CUSTOM) == 0 )
3671141cc406Sopenharmony_ci          {
3672141cc406Sopenharmony_ci            sod[OPT_GAMMA_CUSTOM].cap &= ~SANE_CAP_INACTIVE;
3673141cc406Sopenharmony_ci            sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3674141cc406Sopenharmony_ci          }
3675141cc406Sopenharmony_ci      }
3676141cc406Sopenharmony_ci    else if ( strcmp(val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0
3677141cc406Sopenharmony_ci              || strcmp(val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
3678141cc406Sopenharmony_ci      {
3679141cc406Sopenharmony_ci        /* reset gamma to default */
3680141cc406Sopenharmony_ci        if ( val[OPT_GAMMA_MODE].s )
3681141cc406Sopenharmony_ci            free((void *) val[OPT_GAMMA_MODE].s);
3682141cc406Sopenharmony_ci        val[OPT_GAMMA_MODE].s = strdup(MD_GAMMAMODE_LINEAR);
3683141cc406Sopenharmony_ci        sod[OPT_GAMMA_MODE].cap |= SANE_CAP_INACTIVE;
3684141cc406Sopenharmony_ci        sod[OPT_GAMMA_BIND].cap |= SANE_CAP_INACTIVE;
3685141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR].cap |= SANE_CAP_INACTIVE;
3686141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_R].cap |= SANE_CAP_INACTIVE;
3687141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_G].cap |= SANE_CAP_INACTIVE;
3688141cc406Sopenharmony_ci        sod[OPT_GAMMA_SCALAR_B].cap |= SANE_CAP_INACTIVE;
3689141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM].cap |= SANE_CAP_INACTIVE;
3690141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_R].cap |= SANE_CAP_INACTIVE;
3691141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_G].cap |= SANE_CAP_INACTIVE;
3692141cc406Sopenharmony_ci        sod[OPT_GAMMA_CUSTOM_B].cap |= SANE_CAP_INACTIVE;
3693141cc406Sopenharmony_ci      }
3694141cc406Sopenharmony_ci    else
3695141cc406Sopenharmony_ci        DBG(1, "restore_gamma_options: unknown mode %s\n", val[OPT_MODE].s);
3696141cc406Sopenharmony_ci
3697141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3698141cc406Sopenharmony_ci}
3699141cc406Sopenharmony_ci
3700141cc406Sopenharmony_ci
3701141cc406Sopenharmony_ci/*---------- calculate_sane_params() -----------------------------------------*/
3702141cc406Sopenharmony_ci
3703141cc406Sopenharmony_cistatic SANE_Status
3704141cc406Sopenharmony_cicalculate_sane_params(Microtek2_Scanner *ms)
3705141cc406Sopenharmony_ci{
3706141cc406Sopenharmony_ci    Microtek2_Device *md;
3707141cc406Sopenharmony_ci    Microtek2_Info *mi;
3708141cc406Sopenharmony_ci
3709141cc406Sopenharmony_ci
3710141cc406Sopenharmony_ci    DBG(30, "calculate_sane_params: ms=%p\n", (void *) ms);
3711141cc406Sopenharmony_ci
3712141cc406Sopenharmony_ci    md = ms->dev;
3713141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
3714141cc406Sopenharmony_ci
3715141cc406Sopenharmony_ci    if ( ! mi->onepass && ms->mode == MS_MODE_COLOR )
3716141cc406Sopenharmony_ci      {
3717141cc406Sopenharmony_ci        if ( ms->current_pass == 1 )
3718141cc406Sopenharmony_ci            ms->params.format = SANE_FRAME_RED;
3719141cc406Sopenharmony_ci        else if ( ms->current_pass == 2 )
3720141cc406Sopenharmony_ci            ms->params.format = SANE_FRAME_GREEN;
3721141cc406Sopenharmony_ci        else if ( ms->current_pass == 3 )
3722141cc406Sopenharmony_ci            ms->params.format = SANE_FRAME_BLUE;
3723141cc406Sopenharmony_ci        else
3724141cc406Sopenharmony_ci          {
3725141cc406Sopenharmony_ci            DBG(1, "calculate_sane_params: invalid pass number %d\n",
3726141cc406Sopenharmony_ci                    ms->current_pass);
3727141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
3728141cc406Sopenharmony_ci          }
3729141cc406Sopenharmony_ci      }
3730141cc406Sopenharmony_ci    else if ( mi->onepass && ms->mode == MS_MODE_COLOR )
3731141cc406Sopenharmony_ci        ms->params.format = SANE_FRAME_RGB;
3732141cc406Sopenharmony_ci    else
3733141cc406Sopenharmony_ci        ms->params.format = SANE_FRAME_GRAY;
3734141cc406Sopenharmony_ci
3735141cc406Sopenharmony_ci    if ( ! mi->onepass && ms->mode == MS_MODE_COLOR && ms->current_pass < 3 )
3736141cc406Sopenharmony_ci        ms->params.last_frame = SANE_FALSE;
3737141cc406Sopenharmony_ci    else
3738141cc406Sopenharmony_ci        ms->params.last_frame = SANE_TRUE;
3739141cc406Sopenharmony_ci    ms->params.lines = ms->src_remaining_lines;
3740141cc406Sopenharmony_ci    ms->params.pixels_per_line = ms->ppl;
3741141cc406Sopenharmony_ci    ms->params.bytes_per_line = ms->real_bpl;
3742141cc406Sopenharmony_ci    ms->params.depth = ms->bits_per_pixel_out;
3743141cc406Sopenharmony_ci
3744141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3745141cc406Sopenharmony_ci
3746141cc406Sopenharmony_ci}
3747141cc406Sopenharmony_ci
3748141cc406Sopenharmony_ci/*---------- get_calib_params() ----------------------------------------------*/
3749141cc406Sopenharmony_ci
3750141cc406Sopenharmony_cistatic void
3751141cc406Sopenharmony_ciget_calib_params(Microtek2_Scanner *ms)
3752141cc406Sopenharmony_ci{
3753141cc406Sopenharmony_ci    Microtek2_Device *md;
3754141cc406Sopenharmony_ci    Microtek2_Info *mi;
3755141cc406Sopenharmony_ci
3756141cc406Sopenharmony_ci
3757141cc406Sopenharmony_ci    DBG(30, "get_calib_params: handle=%p\n", (void *) ms);
3758141cc406Sopenharmony_ci
3759141cc406Sopenharmony_ci    md = ms->dev;
3760141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
3761141cc406Sopenharmony_ci
3762141cc406Sopenharmony_ci    if ( md->model_flags & MD_CALIB_DIVISOR_600 )
3763141cc406Sopenharmony_ci      {
3764141cc406Sopenharmony_ci        if ( ms->x_resolution_dpi <= 600 )
3765141cc406Sopenharmony_ci            mi->calib_divisor = 2;
3766141cc406Sopenharmony_ci        else
3767141cc406Sopenharmony_ci            mi->calib_divisor = 1;
3768141cc406Sopenharmony_ci      }
3769141cc406Sopenharmony_ci    DBG(30, "Calib Divisor: %d\n", mi->calib_divisor);
3770141cc406Sopenharmony_ci
3771141cc406Sopenharmony_ci
3772141cc406Sopenharmony_ci    ms->x_resolution_dpi = mi->opt_resolution / mi->calib_divisor;
3773141cc406Sopenharmony_ci    ms->y_resolution_dpi = mi->opt_resolution / 5; /* ignore dust particles */
3774141cc406Sopenharmony_ci    ms->x1_dots = 0;
3775141cc406Sopenharmony_ci    ms->y1_dots = mi->calib_white;
3776141cc406Sopenharmony_ci    ms->width_dots = mi->geo_width;
3777141cc406Sopenharmony_ci    if ( md->shading_length != 0 )
3778141cc406Sopenharmony_ci       ms->height_dots = md->shading_length;
3779141cc406Sopenharmony_ci    else
3780141cc406Sopenharmony_ci       ms->height_dots = mi->calib_space;
3781141cc406Sopenharmony_ci
3782141cc406Sopenharmony_ci    ms->mode = MS_MODE_COLOR;
3783141cc406Sopenharmony_ci
3784141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_16 )
3785141cc406Sopenharmony_ci        ms->depth = 16;
3786141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_14 )
3787141cc406Sopenharmony_ci        ms->depth = 14;
3788141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_12 )
3789141cc406Sopenharmony_ci        ms->depth = 12;
3790141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_10 )
3791141cc406Sopenharmony_ci        ms->depth = 10;
3792141cc406Sopenharmony_ci    else
3793141cc406Sopenharmony_ci        ms->depth = 8;
3794141cc406Sopenharmony_ci
3795141cc406Sopenharmony_ci    ms->stay = 0;
3796141cc406Sopenharmony_ci    if ( mi->calib_space < 10 )
3797141cc406Sopenharmony_ci        ms->stay = 1;
3798141cc406Sopenharmony_ci    ms->rawdat = 1;
3799141cc406Sopenharmony_ci    ms->quality = 1;
3800141cc406Sopenharmony_ci    ms->fastscan = 0;
3801141cc406Sopenharmony_ci/*    ms->scan_source = md->scan_source; */
3802141cc406Sopenharmony_ci    ms->scan_source = 0;
3803141cc406Sopenharmony_ci    ms->brightness_m = ms->brightness_r = ms->brightness_g =
3804141cc406Sopenharmony_ci                       ms->brightness_b = 128;
3805141cc406Sopenharmony_ci    ms->exposure_m = ms->exposure_r = ms->exposure_g = ms->exposure_b = 0;
3806141cc406Sopenharmony_ci    ms->contrast_m = ms->contrast_r = ms->contrast_g = ms->contrast_b = 128;
3807141cc406Sopenharmony_ci    ms->shadow_m = ms->shadow_r = ms->shadow_g = ms->shadow_b = 0;
3808141cc406Sopenharmony_ci    ms->midtone_m = ms->midtone_r = ms->midtone_g = ms->midtone_b = 128;
3809141cc406Sopenharmony_ci    ms->highlight_m = ms->highlight_r = ms->highlight_g = ms->highlight_b = 255;
3810141cc406Sopenharmony_ci
3811141cc406Sopenharmony_ci    return;
3812141cc406Sopenharmony_ci}
3813141cc406Sopenharmony_ci
3814141cc406Sopenharmony_ci
3815141cc406Sopenharmony_ci/*---------- get_scan_parameters () ------------------------------------------*/
3816141cc406Sopenharmony_ci
3817141cc406Sopenharmony_cistatic SANE_Status
3818141cc406Sopenharmony_ciget_scan_parameters(Microtek2_Scanner *ms)
3819141cc406Sopenharmony_ci{
3820141cc406Sopenharmony_ci    Microtek2_Device *md;
3821141cc406Sopenharmony_ci    Microtek2_Info *mi;
3822141cc406Sopenharmony_ci    double dpm;                   /* dots per millimeter */
3823141cc406Sopenharmony_ci    int x2_dots;
3824141cc406Sopenharmony_ci    int y2_dots;
3825141cc406Sopenharmony_ci    int i;
3826141cc406Sopenharmony_ci
3827141cc406Sopenharmony_ci
3828141cc406Sopenharmony_ci    DBG(30, "get_scan_parameters: handle=%p\n", (void *) ms);
3829141cc406Sopenharmony_ci
3830141cc406Sopenharmony_ci    md = ms->dev;
3831141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
3832141cc406Sopenharmony_ci
3833141cc406Sopenharmony_ci    get_scan_mode_and_depth(ms, &ms->mode, &ms->depth,
3834141cc406Sopenharmony_ci                            &ms->bits_per_pixel_in, &ms->bits_per_pixel_out);
3835141cc406Sopenharmony_ci
3836141cc406Sopenharmony_ci    /* get the scan_source */
3837141cc406Sopenharmony_ci    if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_FLATBED) == 0 )
3838141cc406Sopenharmony_ci        ms->scan_source = MS_SOURCE_FLATBED;
3839141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_ADF) == 0 )
3840141cc406Sopenharmony_ci        ms->scan_source = MS_SOURCE_ADF;
3841141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_TMA) == 0 )
3842141cc406Sopenharmony_ci        ms->scan_source = MS_SOURCE_TMA;
3843141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_STRIPE) == 0 )
3844141cc406Sopenharmony_ci        ms->scan_source = MS_SOURCE_STRIPE;
3845141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_SLIDE) == 0 )
3846141cc406Sopenharmony_ci        ms->scan_source = MS_SOURCE_SLIDE;
3847141cc406Sopenharmony_ci
3848141cc406Sopenharmony_ci    /* enable/disable backtracking */
3849141cc406Sopenharmony_ci    if ( ms->val[OPT_DISABLE_BACKTRACK].w == SANE_TRUE )
3850141cc406Sopenharmony_ci        ms->no_backtracking = 1;
3851141cc406Sopenharmony_ci    else
3852141cc406Sopenharmony_ci        ms->no_backtracking = 0;
3853141cc406Sopenharmony_ci
3854141cc406Sopenharmony_ci    /* turn off the lamp during a scan */
3855141cc406Sopenharmony_ci    if ( ms->val[OPT_LIGHTLID35].w == SANE_TRUE )
3856141cc406Sopenharmony_ci        ms->lightlid35 = 1;
3857141cc406Sopenharmony_ci    else
3858141cc406Sopenharmony_ci        ms->lightlid35 = 0;
3859141cc406Sopenharmony_ci
3860141cc406Sopenharmony_ci    /* automatic adjustment of threshold */
3861141cc406Sopenharmony_ci    if ( ms->val[OPT_AUTOADJUST].w == SANE_TRUE)
3862141cc406Sopenharmony_ci        ms->auto_adjust = 1;
3863141cc406Sopenharmony_ci    else
3864141cc406Sopenharmony_ci        ms->auto_adjust = 0;
3865141cc406Sopenharmony_ci
3866141cc406Sopenharmony_ci    /* color calibration by backend */
3867141cc406Sopenharmony_ci    if ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
3868141cc406Sopenharmony_ci        ms->calib_backend = 1;
3869141cc406Sopenharmony_ci    else
3870141cc406Sopenharmony_ci        ms->calib_backend = 0;
3871141cc406Sopenharmony_ci
3872141cc406Sopenharmony_ci    /* if halftone mode select halftone pattern */
3873141cc406Sopenharmony_ci    if ( ms->mode == MS_MODE_HALFTONE )
3874141cc406Sopenharmony_ci      {
3875141cc406Sopenharmony_ci        i = 0;
3876141cc406Sopenharmony_ci        while ( strcmp(md->halftone_mode_list[i], ms->val[OPT_HALFTONE].s) )
3877141cc406Sopenharmony_ci            ++i;
3878141cc406Sopenharmony_ci        ms->internal_ht_index = i;
3879141cc406Sopenharmony_ci      }
3880141cc406Sopenharmony_ci
3881141cc406Sopenharmony_ci    /* if lineart get the value for threshold */
3882141cc406Sopenharmony_ci    if ( ms->mode == MS_MODE_LINEART || ms->mode == MS_MODE_LINEARTFAKE)
3883141cc406Sopenharmony_ci        ms->threshold = (uint8_t) ms->val[OPT_THRESHOLD].w;
3884141cc406Sopenharmony_ci    else
3885141cc406Sopenharmony_ci        ms->threshold = (uint8_t) M_THRESHOLD_DEFAULT;
3886141cc406Sopenharmony_ci
3887141cc406Sopenharmony_ci    DBG(30, "get_scan_parameters: mode=%d, depth=%d, bpp_in=%d, bpp_out=%d\n",
3888141cc406Sopenharmony_ci             ms->mode, ms->depth, ms->bits_per_pixel_in,
3889141cc406Sopenharmony_ci             ms->bits_per_pixel_out);
3890141cc406Sopenharmony_ci
3891141cc406Sopenharmony_ci    /* calculate positions, width and height in dots */
3892141cc406Sopenharmony_ci    /* check for impossible values */
3893141cc406Sopenharmony_ci    /* ensure a minimum scan area of 10 x 10 pixels */
3894141cc406Sopenharmony_ci    dpm = (double) mi->opt_resolution / MM_PER_INCH;
3895141cc406Sopenharmony_ci    ms->x1_dots = (SANE_Int) ( SANE_UNFIX(ms->val[OPT_TL_X].w) * dpm + 0.5 );
3896141cc406Sopenharmony_ci    if ( ms->x1_dots > ( mi->geo_width - 10 ) )
3897141cc406Sopenharmony_ci        ms->x1_dots = ( mi->geo_width - 10 );
3898141cc406Sopenharmony_ci    ms->y1_dots = (SANE_Int) ( SANE_UNFIX(ms->val[OPT_TL_Y].w) * dpm + 0.5 );
3899141cc406Sopenharmony_ci    if ( ms->y1_dots > ( mi->geo_height - 10 ) )
3900141cc406Sopenharmony_ci        ms->y1_dots = ( mi->geo_height - 10 );
3901141cc406Sopenharmony_ci    x2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_X].w) * dpm + 0.5 );
3902141cc406Sopenharmony_ci    if ( x2_dots >= mi->geo_width )
3903141cc406Sopenharmony_ci        x2_dots = mi->geo_width - 1;
3904141cc406Sopenharmony_ci    y2_dots = (int) ( SANE_UNFIX(ms->val[OPT_BR_Y].w) * dpm + 0.5 );
3905141cc406Sopenharmony_ci    if ( y2_dots >= mi->geo_height )
3906141cc406Sopenharmony_ci        y2_dots = mi->geo_height - 1;
3907141cc406Sopenharmony_ci    ms->width_dots = x2_dots - ms->x1_dots;
3908141cc406Sopenharmony_ci    if ( md->model_flags & MD_OFFSET_2 ) /* this firmware has problems with */
3909141cc406Sopenharmony_ci      if ( ( ms->width_dots % 2 ) == 1 ) /* odd pixel numbers */
3910141cc406Sopenharmony_ci        ms->width_dots -= 1;
3911141cc406Sopenharmony_ci    if ( ms->width_dots < 10 )
3912141cc406Sopenharmony_ci        ms->width_dots = 10;
3913141cc406Sopenharmony_ci    ms->height_dots = y2_dots - ms->y1_dots;
3914141cc406Sopenharmony_ci    if ( ms->height_dots < 10 )
3915141cc406Sopenharmony_ci        ms->height_dots = 10;
3916141cc406Sopenharmony_ci
3917141cc406Sopenharmony_ci/*test!!!*/
3918141cc406Sopenharmony_ci/*    ms->y1_dots -= 50;*/
3919141cc406Sopenharmony_ci
3920141cc406Sopenharmony_ci    /* take scanning direction into account */
3921141cc406Sopenharmony_ci    if ((mi->direction & MI_DATSEQ_RTOL) == 1)
3922141cc406Sopenharmony_ci        ms->x1_dots = mi->geo_width - ms->x1_dots - ms->width_dots;
3923141cc406Sopenharmony_ci
3924141cc406Sopenharmony_ci    if ( ms->val[OPT_RESOLUTION_BIND].w == SANE_TRUE )
3925141cc406Sopenharmony_ci      {
3926141cc406Sopenharmony_ci        ms->x_resolution_dpi =
3927141cc406Sopenharmony_ci                    (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3928141cc406Sopenharmony_ci        ms->y_resolution_dpi =
3929141cc406Sopenharmony_ci                    (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3930141cc406Sopenharmony_ci      }
3931141cc406Sopenharmony_ci    else
3932141cc406Sopenharmony_ci      {
3933141cc406Sopenharmony_ci        ms->x_resolution_dpi =
3934141cc406Sopenharmony_ci                    (SANE_Int) (SANE_UNFIX(ms->val[OPT_RESOLUTION].w) + 0.5);
3935141cc406Sopenharmony_ci        ms->y_resolution_dpi =
3936141cc406Sopenharmony_ci                    (SANE_Int) (SANE_UNFIX(ms->val[OPT_Y_RESOLUTION].w) + 0.5);
3937141cc406Sopenharmony_ci      }
3938141cc406Sopenharmony_ci
3939141cc406Sopenharmony_ci    if ( ms->x_resolution_dpi < 10 )
3940141cc406Sopenharmony_ci        ms->x_resolution_dpi = 10;
3941141cc406Sopenharmony_ci    if ( ms->y_resolution_dpi < 10 )
3942141cc406Sopenharmony_ci        ms->y_resolution_dpi = 10;
3943141cc406Sopenharmony_ci
3944141cc406Sopenharmony_ci    DBG(30, "get_scan_parameters: yres=%d, x1=%d, width=%d, y1=%d, height=%d\n",
3945141cc406Sopenharmony_ci             ms->y_resolution_dpi, ms->x1_dots, ms->width_dots,
3946141cc406Sopenharmony_ci             ms->y1_dots, ms->height_dots);
3947141cc406Sopenharmony_ci
3948141cc406Sopenharmony_ci    /* Preview mode */
3949141cc406Sopenharmony_ci    if ( ms->val[OPT_PREVIEW].w == SANE_TRUE )
3950141cc406Sopenharmony_ci      {
3951141cc406Sopenharmony_ci        ms->fastscan = SANE_TRUE;
3952141cc406Sopenharmony_ci        ms->quality = SANE_FALSE;
3953141cc406Sopenharmony_ci      }
3954141cc406Sopenharmony_ci    else
3955141cc406Sopenharmony_ci      {
3956141cc406Sopenharmony_ci        ms->fastscan = SANE_FALSE;
3957141cc406Sopenharmony_ci        ms->quality = SANE_TRUE;
3958141cc406Sopenharmony_ci      }
3959141cc406Sopenharmony_ci
3960141cc406Sopenharmony_ci    ms->rawdat = 0;
3961141cc406Sopenharmony_ci
3962141cc406Sopenharmony_ci    /* brightness, contrast, values 1,..,255 */
3963141cc406Sopenharmony_ci    ms->brightness_m = (uint8_t) (SANE_UNFIX(ms->val[OPT_BRIGHTNESS].w)
3964141cc406Sopenharmony_ci                      / SANE_UNFIX(md->percentage_range.max) * 254.0) + 1;
3965141cc406Sopenharmony_ci    ms->brightness_r = ms->brightness_g = ms->brightness_b = ms->brightness_m;
3966141cc406Sopenharmony_ci
3967141cc406Sopenharmony_ci    ms->contrast_m = (uint8_t) (SANE_UNFIX(ms->val[OPT_CONTRAST].w)
3968141cc406Sopenharmony_ci                    / SANE_UNFIX(md->percentage_range.max) * 254.0) + 1;
3969141cc406Sopenharmony_ci    ms->contrast_r = ms->contrast_g = ms->contrast_b = ms->contrast_m;
3970141cc406Sopenharmony_ci
3971141cc406Sopenharmony_ci    /* shadow, midtone, highlight, exposure */
3972141cc406Sopenharmony_ci    ms->shadow_m = (uint8_t) ms->val[OPT_SHADOW].w;
3973141cc406Sopenharmony_ci    ms->shadow_r = (uint8_t) ms->val[OPT_SHADOW_R].w;
3974141cc406Sopenharmony_ci    ms->shadow_g = (uint8_t) ms->val[OPT_SHADOW_G].w;
3975141cc406Sopenharmony_ci    ms->shadow_b = (uint8_t) ms->val[OPT_SHADOW_B].w;
3976141cc406Sopenharmony_ci    ms->midtone_m = (uint8_t) ms->val[OPT_MIDTONE].w;
3977141cc406Sopenharmony_ci    ms->midtone_r = (uint8_t) ms->val[OPT_MIDTONE_R].w;
3978141cc406Sopenharmony_ci    ms->midtone_g = (uint8_t) ms->val[OPT_MIDTONE_G].w;
3979141cc406Sopenharmony_ci    ms->midtone_b = (uint8_t) ms->val[OPT_MIDTONE_B].w;
3980141cc406Sopenharmony_ci    ms->highlight_m = (uint8_t) ms->val[OPT_HIGHLIGHT].w;
3981141cc406Sopenharmony_ci    ms->highlight_r = (uint8_t) ms->val[OPT_HIGHLIGHT_R].w;
3982141cc406Sopenharmony_ci    ms->highlight_g = (uint8_t) ms->val[OPT_HIGHLIGHT_G].w;
3983141cc406Sopenharmony_ci    ms->highlight_b = (uint8_t) ms->val[OPT_HIGHLIGHT_B].w;
3984141cc406Sopenharmony_ci    ms->exposure_m = (uint8_t) (ms->val[OPT_EXPOSURE].w / 2);
3985141cc406Sopenharmony_ci    ms->exposure_r = (uint8_t) (ms->val[OPT_EXPOSURE_R].w / 2);
3986141cc406Sopenharmony_ci    ms->exposure_g = (uint8_t) (ms->val[OPT_EXPOSURE_G].w / 2);
3987141cc406Sopenharmony_ci    ms->exposure_b = (uint8_t) (ms->val[OPT_EXPOSURE_B].w / 2);
3988141cc406Sopenharmony_ci
3989141cc406Sopenharmony_ci    ms->gamma_mode = strdup( (char *) ms->val[OPT_GAMMA_MODE].s);
3990141cc406Sopenharmony_ci
3991141cc406Sopenharmony_ci    ms->balance[0] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_R].w));
3992141cc406Sopenharmony_ci    ms->balance[1] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_G].w));
3993141cc406Sopenharmony_ci    ms->balance[2] = (uint8_t) (SANE_UNFIX(ms->val[OPT_BALANCE_B].w));
3994141cc406Sopenharmony_ci    DBG(255, "get_scan_parameters:ms->balance[0]=%d,[1]=%d,[2]=%d\n",
3995141cc406Sopenharmony_ci               ms->balance[0], ms->balance[1], ms->balance[2]);
3996141cc406Sopenharmony_ci
3997141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
3998141cc406Sopenharmony_ci}
3999141cc406Sopenharmony_ci
4000141cc406Sopenharmony_ci/*---------- get_scan_mode_and_depth() ---------------------------------------*/
4001141cc406Sopenharmony_ci
4002141cc406Sopenharmony_cistatic SANE_Status
4003141cc406Sopenharmony_ciget_scan_mode_and_depth(Microtek2_Scanner *ms,
4004141cc406Sopenharmony_ci                        int *mode,
4005141cc406Sopenharmony_ci                        int *depth,
4006141cc406Sopenharmony_ci                        int *bits_per_pixel_in,
4007141cc406Sopenharmony_ci                        int *bits_per_pixel_out)
4008141cc406Sopenharmony_ci{
4009141cc406Sopenharmony_ci    /* This function translates the strings for the possible modes and */
4010141cc406Sopenharmony_ci    /* bitdepth into a more conveniant format as needed for SET WINDOW. */
4011141cc406Sopenharmony_ci    /* bits_per_pixel is the number of bits per color one pixel needs */
4012141cc406Sopenharmony_ci    /* when transferred from the scanner, bits_perpixel_out is the */
4013141cc406Sopenharmony_ci    /* number of bits per color one pixel uses when transferred to the */
4014141cc406Sopenharmony_ci    /* frontend. These may be different. For example, with a depth of 4 */
4015141cc406Sopenharmony_ci    /* two pixels per byte are transferred from the scanner, but only one */
4016141cc406Sopenharmony_ci    /* pixel per byte is transferred to the frontend. */
4017141cc406Sopenharmony_ci    /* If lineart_fake is set to !=0, we need the parameters for a */
4018141cc406Sopenharmony_ci    /* grayscale scan, because the scanner has no lineart mode */
4019141cc406Sopenharmony_ci
4020141cc406Sopenharmony_ci    Microtek2_Device *md;
4021141cc406Sopenharmony_ci    Microtek2_Info *mi;
4022141cc406Sopenharmony_ci
4023141cc406Sopenharmony_ci    DBG(30, "get_scan_mode_and_depth: handle=%p\n", (void *) ms);
4024141cc406Sopenharmony_ci
4025141cc406Sopenharmony_ci    md = ms->dev;
4026141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
4027141cc406Sopenharmony_ci
4028141cc406Sopenharmony_ci    if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0 )
4029141cc406Sopenharmony_ci	*mode = MS_MODE_COLOR;
4030141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
4031141cc406Sopenharmony_ci	*mode = MS_MODE_GRAY;
4032141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0)
4033141cc406Sopenharmony_ci	*mode = MS_MODE_HALFTONE;
4034141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_LINEART) == 0 )
4035141cc406Sopenharmony_ci      {
4036141cc406Sopenharmony_ci        if ( MI_LINEART_NONE(mi->scanmode)
4037141cc406Sopenharmony_ci             || ms->val[OPT_AUTOADJUST].w == SANE_TRUE
4038141cc406Sopenharmony_ci             || md->model_flags & MD_READ_CONTROL_BIT)
4039141cc406Sopenharmony_ci            *mode = MS_MODE_LINEARTFAKE;
4040141cc406Sopenharmony_ci        else
4041141cc406Sopenharmony_ci	    *mode = MS_MODE_LINEART;
4042141cc406Sopenharmony_ci      }
4043141cc406Sopenharmony_ci    else
4044141cc406Sopenharmony_ci      {
4045141cc406Sopenharmony_ci        DBG(1, "get_scan_mode_and_depth: Unknown mode %s\n",
4046141cc406Sopenharmony_ci                ms->val[OPT_MODE].s);
4047141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
4048141cc406Sopenharmony_ci      }
4049141cc406Sopenharmony_ci
4050141cc406Sopenharmony_ci    if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_COLOR) == 0
4051141cc406Sopenharmony_ci         || strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_GRAY) == 0 )
4052141cc406Sopenharmony_ci      {
4053141cc406Sopenharmony_ci        if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_16 )
4054141cc406Sopenharmony_ci          {
4055141cc406Sopenharmony_ci            *depth = 16;
4056141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 16;
4057141cc406Sopenharmony_ci          }
4058141cc406Sopenharmony_ci        else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_14 )
4059141cc406Sopenharmony_ci          {
4060141cc406Sopenharmony_ci            *depth = 14;
4061141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 16;
4062141cc406Sopenharmony_ci          }
4063141cc406Sopenharmony_ci        else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_12 )
4064141cc406Sopenharmony_ci          {
4065141cc406Sopenharmony_ci            *depth = 12;
4066141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 16;
4067141cc406Sopenharmony_ci          }
4068141cc406Sopenharmony_ci        else if ( ms->val[OPT_BITDEPTH].w == MD_DEPTHVAL_10 )
4069141cc406Sopenharmony_ci          {
4070141cc406Sopenharmony_ci            *depth = 10;
4071141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 16;
4072141cc406Sopenharmony_ci          }
4073141cc406Sopenharmony_ci        else if ( ms->val[OPT_BITDEPTH].w ==  MD_DEPTHVAL_8 )
4074141cc406Sopenharmony_ci          {
4075141cc406Sopenharmony_ci            *depth = 8;
4076141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 8;
4077141cc406Sopenharmony_ci          }
4078141cc406Sopenharmony_ci        else if ( ms->val[OPT_MODE].w == MD_DEPTHVAL_4 )
4079141cc406Sopenharmony_ci          {
4080141cc406Sopenharmony_ci            *depth = 4;
4081141cc406Sopenharmony_ci            *bits_per_pixel_in = 4;
4082141cc406Sopenharmony_ci            *bits_per_pixel_out = 8;
4083141cc406Sopenharmony_ci          }
4084141cc406Sopenharmony_ci      }
4085141cc406Sopenharmony_ci    else if ( strcmp(ms->val[OPT_MODE].s, MD_MODESTRING_HALFTONE) == 0  )
4086141cc406Sopenharmony_ci      {
4087141cc406Sopenharmony_ci        *depth = 1;
4088141cc406Sopenharmony_ci        *bits_per_pixel_in = *bits_per_pixel_out = 1;
4089141cc406Sopenharmony_ci      }
4090141cc406Sopenharmony_ci    else                   /* lineart */
4091141cc406Sopenharmony_ci      {
4092141cc406Sopenharmony_ci        *bits_per_pixel_out = 1;
4093141cc406Sopenharmony_ci        if ( *mode == MS_MODE_LINEARTFAKE )
4094141cc406Sopenharmony_ci          {
4095141cc406Sopenharmony_ci            *depth = 8;
4096141cc406Sopenharmony_ci            *bits_per_pixel_in = 8;
4097141cc406Sopenharmony_ci          }
4098141cc406Sopenharmony_ci        else
4099141cc406Sopenharmony_ci          {
4100141cc406Sopenharmony_ci            *depth = 1;
4101141cc406Sopenharmony_ci            *bits_per_pixel_in = 1;
4102141cc406Sopenharmony_ci          }
4103141cc406Sopenharmony_ci      }
4104141cc406Sopenharmony_ci
4105141cc406Sopenharmony_ci#if 0
4106141cc406Sopenharmony_ci    if ( ms->val[OPT_PREVIEW].w == SANE_TRUE )
4107141cc406Sopenharmony_ci      {
4108141cc406Sopenharmony_ci        if ( *depth > 8 )
4109141cc406Sopenharmony_ci          {
4110141cc406Sopenharmony_ci            *depth = 8;
4111141cc406Sopenharmony_ci            *bits_per_pixel_in = *bits_per_pixel_out = 8;
4112141cc406Sopenharmony_ci          }
4113141cc406Sopenharmony_ci      }
4114141cc406Sopenharmony_ci#endif
4115141cc406Sopenharmony_ci
4116141cc406Sopenharmony_ci    DBG(30, "get_scan_mode_and_depth: mode=%d, depth=%d,"
4117141cc406Sopenharmony_ci            " bits_pp_in=%d, bits_pp_out=%d, preview=%d\n",
4118141cc406Sopenharmony_ci             *mode, *depth, *bits_per_pixel_in, *bits_per_pixel_out,
4119141cc406Sopenharmony_ci             ms->val[OPT_PREVIEW].w);
4120141cc406Sopenharmony_ci
4121141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4122141cc406Sopenharmony_ci}
4123141cc406Sopenharmony_ci
4124141cc406Sopenharmony_ci
4125141cc406Sopenharmony_ci/*---------- scsi_wait_for_image() -------------------------------------------*/
4126141cc406Sopenharmony_ci
4127141cc406Sopenharmony_cistatic SANE_Status
4128141cc406Sopenharmony_ciscsi_wait_for_image(Microtek2_Scanner *ms)
4129141cc406Sopenharmony_ci{
4130141cc406Sopenharmony_ci    int retry = 60;
4131141cc406Sopenharmony_ci    SANE_Status status;
4132141cc406Sopenharmony_ci
4133141cc406Sopenharmony_ci
4134141cc406Sopenharmony_ci    DBG(30, "scsi_wait_for_image: ms=%p\n", (void *) ms);
4135141cc406Sopenharmony_ci
4136141cc406Sopenharmony_ci    while ( retry-- > 0 )
4137141cc406Sopenharmony_ci      {
4138141cc406Sopenharmony_ci        status = scsi_read_image_status(ms);
4139141cc406Sopenharmony_ci        if  (status == SANE_STATUS_DEVICE_BUSY )
4140141cc406Sopenharmony_ci          {
4141141cc406Sopenharmony_ci            sleep(1);
4142141cc406Sopenharmony_ci            continue;
4143141cc406Sopenharmony_ci          }
4144141cc406Sopenharmony_ci        if ( status == SANE_STATUS_GOOD )
4145141cc406Sopenharmony_ci            return status;
4146141cc406Sopenharmony_ci
4147141cc406Sopenharmony_ci        /* status != GOOD && != BUSY */
4148141cc406Sopenharmony_ci        DBG(1, "scsi_wait_for_image: '%s'\n", sane_strstatus(status));
4149141cc406Sopenharmony_ci        return status;
4150141cc406Sopenharmony_ci      }
4151141cc406Sopenharmony_ci
4152141cc406Sopenharmony_ci    /* BUSY after n retries */
4153141cc406Sopenharmony_ci    DBG(1, "scsi_wait_for_image: '%s'\n", sane_strstatus(status));
4154141cc406Sopenharmony_ci    return status;
4155141cc406Sopenharmony_ci}
4156141cc406Sopenharmony_ci
4157141cc406Sopenharmony_ci
4158141cc406Sopenharmony_ci/*---------- scsi_read_gamma() -----------------------------------------------*/
4159141cc406Sopenharmony_ci
4160141cc406Sopenharmony_ci/* currently not used */
4161141cc406Sopenharmony_ci/*
4162141cc406Sopenharmony_cistatic SANE_Status
4163141cc406Sopenharmony_ciscsi_read_gamma(Microtek2_Scanner *ms, int color)
4164141cc406Sopenharmony_ci{
4165141cc406Sopenharmony_ci    uint8_t readgamma[RG_CMD_L];
4166141cc406Sopenharmony_ci    uint8_t result[3072];
4167141cc406Sopenharmony_ci    size_t size;
4168141cc406Sopenharmony_ci    SANE_Bool endiantype;
4169141cc406Sopenharmony_ci    SANE_Status status;
4170141cc406Sopenharmony_ci
4171141cc406Sopenharmony_ci    RG_CMD(readgamma);
4172141cc406Sopenharmony_ci    ENDIAN_TYPE(endiantype);
4173141cc406Sopenharmony_ci    RG_PCORMAC(readgamma, endiantype);
4174141cc406Sopenharmony_ci    RG_COLOR(readgamma, color);
4175141cc406Sopenharmony_ci    RG_WORD(readgamma, ( ms->dev->lut_entry_size == 1 ) ? 0 : 1);
4176141cc406Sopenharmony_ci    RG_TRANSFERLENGTH(readgamma, (color == 3 ) ? 3072 : 1024);
4177141cc406Sopenharmony_ci
4178141cc406Sopenharmony_ci    dump_area(readgamma, 10, "ReadGamma");
4179141cc406Sopenharmony_ci
4180141cc406Sopenharmony_ci    size = sizeof(result);
4181141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, readgamma, sizeof(readgamma),
4182141cc406Sopenharmony_ci                            result, &size);
4183141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD ) {
4184141cc406Sopenharmony_ci        DBG(1, "scsi_read_gamma: (L,R) read_gamma failed: status '%s'\n",
4185141cc406Sopenharmony_ci                sane_strstatus(status));
4186141cc406Sopenharmony_ci        return status;
4187141cc406Sopenharmony_ci    }
4188141cc406Sopenharmony_ci
4189141cc406Sopenharmony_ci    dump_area(result, 3072, "Result");
4190141cc406Sopenharmony_ci
4191141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4192141cc406Sopenharmony_ci}
4193141cc406Sopenharmony_ci*/
4194141cc406Sopenharmony_ci
4195141cc406Sopenharmony_ci
4196141cc406Sopenharmony_ci/*---------- scsi_send_gamma() -----------------------------------------------*/
4197141cc406Sopenharmony_ci
4198141cc406Sopenharmony_cistatic SANE_Status
4199141cc406Sopenharmony_ciscsi_send_gamma(Microtek2_Scanner *ms)
4200141cc406Sopenharmony_ci{
4201141cc406Sopenharmony_ci    SANE_Bool endiantype;
4202141cc406Sopenharmony_ci    SANE_Status status;
4203141cc406Sopenharmony_ci    size_t size;
4204141cc406Sopenharmony_ci    uint8_t *cmd, color;
4205141cc406Sopenharmony_ci
4206141cc406Sopenharmony_ci
4207141cc406Sopenharmony_ci    DBG(30, "scsi_send_gamma: pos=%p, size=%d, word=%d, color=%d\n",
4208141cc406Sopenharmony_ci             (void *) ms->gamma_table, ms->lut_size_bytes, ms->word,
4209141cc406Sopenharmony_ci             ms->current_color);
4210141cc406Sopenharmony_ci
4211141cc406Sopenharmony_ci    if ( ( 3 * ms->lut_size_bytes ) <= 0xffff ) /*send Gamma with one command*/
4212141cc406Sopenharmony_ci      {
4213141cc406Sopenharmony_ci        cmd = (uint8_t *) alloca(SG_CMD_L + 3 * ms->lut_size_bytes);
4214141cc406Sopenharmony_ci        if ( cmd == NULL )
4215141cc406Sopenharmony_ci          {
4216141cc406Sopenharmony_ci            DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n");
4217141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
4218141cc406Sopenharmony_ci          }
4219141cc406Sopenharmony_ci
4220141cc406Sopenharmony_ci        SG_SET_CMD(cmd);
4221141cc406Sopenharmony_ci        ENDIAN_TYPE(endiantype)
4222141cc406Sopenharmony_ci        SG_SET_PCORMAC(cmd, endiantype);
4223141cc406Sopenharmony_ci        SG_SET_COLOR(cmd, ms->current_color);
4224141cc406Sopenharmony_ci        SG_SET_WORD(cmd, ms->word);
4225141cc406Sopenharmony_ci        SG_SET_TRANSFERLENGTH(cmd, 3 * ms->lut_size_bytes);
4226141cc406Sopenharmony_ci        memcpy(cmd + SG_CMD_L, ms->gamma_table, 3 * ms->lut_size_bytes);
4227141cc406Sopenharmony_ci        size = 3 * ms->lut_size_bytes;
4228141cc406Sopenharmony_ci        if ( md_dump >= 2 )
4229141cc406Sopenharmony_ci                dump_area2(cmd, SG_CMD_L, "sendgammacmd");
4230141cc406Sopenharmony_ci        if ( md_dump >= 3 )
4231141cc406Sopenharmony_ci                dump_area2(cmd + SG_CMD_L, size, "sendgammadata");
4232141cc406Sopenharmony_ci
4233141cc406Sopenharmony_ci        status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0);
4234141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
4235141cc406Sopenharmony_ci                DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status));
4236141cc406Sopenharmony_ci      }
4237141cc406Sopenharmony_ci
4238141cc406Sopenharmony_ci    else  /* send gamma with 3 commands, one for each color */
4239141cc406Sopenharmony_ci      {
4240141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
4241141cc406Sopenharmony_ci          {
4242141cc406Sopenharmony_ci            cmd = (uint8_t *) alloca(SG_CMD_L + ms->lut_size_bytes);
4243141cc406Sopenharmony_ci            if ( cmd == NULL )
4244141cc406Sopenharmony_ci              {
4245141cc406Sopenharmony_ci                DBG(1, "scsi_send_gamma: Couldn't get buffer for gamma table\n");
4246141cc406Sopenharmony_ci                return SANE_STATUS_IO_ERROR;
4247141cc406Sopenharmony_ci              }
4248141cc406Sopenharmony_ci            SG_SET_CMD(cmd);
4249141cc406Sopenharmony_ci            ENDIAN_TYPE(endiantype)
4250141cc406Sopenharmony_ci            SG_SET_PCORMAC(cmd, endiantype);
4251141cc406Sopenharmony_ci            SG_SET_COLOR(cmd, color);
4252141cc406Sopenharmony_ci            SG_SET_WORD(cmd, ms->word);
4253141cc406Sopenharmony_ci            SG_SET_TRANSFERLENGTH(cmd, ms->lut_size_bytes);
4254141cc406Sopenharmony_ci            memcpy(cmd + SG_CMD_L,
4255141cc406Sopenharmony_ci                   ms->gamma_table + color * ms->lut_size_bytes,
4256141cc406Sopenharmony_ci                   ms->lut_size_bytes);
4257141cc406Sopenharmony_ci            size = ms->lut_size_bytes;
4258141cc406Sopenharmony_ci            if ( md_dump >= 2 )
4259141cc406Sopenharmony_ci                    dump_area2(cmd, SG_CMD_L, "sendgammacmd");
4260141cc406Sopenharmony_ci            if ( md_dump >= 3 )
4261141cc406Sopenharmony_ci                    dump_area2(cmd + SG_CMD_L, size, "sendgammadata");
4262141cc406Sopenharmony_ci
4263141cc406Sopenharmony_ci            status = sanei_scsi_cmd(ms->sfd, cmd, size + SG_CMD_L, NULL, 0);
4264141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
4265141cc406Sopenharmony_ci                    DBG(1, "scsi_send_gamma: '%s'\n", sane_strstatus(status));
4266141cc406Sopenharmony_ci          }
4267141cc406Sopenharmony_ci
4268141cc406Sopenharmony_ci      }
4269141cc406Sopenharmony_ci
4270141cc406Sopenharmony_ci    return status;
4271141cc406Sopenharmony_ci}
4272141cc406Sopenharmony_ci
4273141cc406Sopenharmony_ci
4274141cc406Sopenharmony_ci/*---------- scsi_inquiry() --------------------------------------------------*/
4275141cc406Sopenharmony_ci
4276141cc406Sopenharmony_cistatic SANE_Status
4277141cc406Sopenharmony_ciscsi_inquiry(Microtek2_Info *mi, char *device)
4278141cc406Sopenharmony_ci{
4279141cc406Sopenharmony_ci    SANE_Status status;
4280141cc406Sopenharmony_ci    uint8_t cmd[INQ_CMD_L];
4281141cc406Sopenharmony_ci    uint8_t *result;
4282141cc406Sopenharmony_ci    uint8_t inqlen;
4283141cc406Sopenharmony_ci    size_t size;
4284141cc406Sopenharmony_ci    int sfd;
4285141cc406Sopenharmony_ci
4286141cc406Sopenharmony_ci
4287141cc406Sopenharmony_ci    DBG(30, "scsi_inquiry: mi=%p, device='%s'\n", (void *) mi, device);
4288141cc406Sopenharmony_ci
4289141cc406Sopenharmony_ci    status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0);
4290141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4291141cc406Sopenharmony_ci      {
4292141cc406Sopenharmony_ci        DBG(1, "scsi_inquiry: '%s'\n", sane_strstatus(status));
4293141cc406Sopenharmony_ci        return status;
4294141cc406Sopenharmony_ci      }
4295141cc406Sopenharmony_ci
4296141cc406Sopenharmony_ci    INQ_CMD(cmd);
4297141cc406Sopenharmony_ci    INQ_SET_ALLOC(cmd, INQ_ALLOC_L);
4298141cc406Sopenharmony_ci    result = (uint8_t *) alloca(INQ_ALLOC_L);
4299141cc406Sopenharmony_ci    if ( result == NULL )
4300141cc406Sopenharmony_ci      {
4301141cc406Sopenharmony_ci        DBG(1, "scsi_inquiry: malloc failed\n");
4302141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4303141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
4304141cc406Sopenharmony_ci      }
4305141cc406Sopenharmony_ci
4306141cc406Sopenharmony_ci    size = INQ_ALLOC_L;
4307141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4308141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4309141cc406Sopenharmony_ci      {
4310141cc406Sopenharmony_ci        DBG(1, "scsi_inquiry: '%s'\n", sane_strstatus(status));
4311141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4312141cc406Sopenharmony_ci        return status;
4313141cc406Sopenharmony_ci      }
4314141cc406Sopenharmony_ci
4315141cc406Sopenharmony_ci    INQ_GET_INQLEN(inqlen, result);
4316141cc406Sopenharmony_ci    INQ_SET_ALLOC(cmd, inqlen + INQ_ALLOC_L);
4317141cc406Sopenharmony_ci    result = alloca(inqlen + INQ_ALLOC_L);
4318141cc406Sopenharmony_ci    if ( result == NULL )
4319141cc406Sopenharmony_ci      {
4320141cc406Sopenharmony_ci        DBG(1, "scsi_inquiry: malloc failed\n");
4321141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4322141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
4323141cc406Sopenharmony_ci      }
4324141cc406Sopenharmony_ci    size = inqlen + INQ_ALLOC_L;
4325141cc406Sopenharmony_ci    if (md_dump >= 2 )
4326141cc406Sopenharmony_ci        dump_area2(cmd, sizeof(cmd), "inquiry");
4327141cc406Sopenharmony_ci
4328141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4329141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4330141cc406Sopenharmony_ci      {
4331141cc406Sopenharmony_ci        DBG(1, "scsi_inquiry: cmd '%s'\n", sane_strstatus(status));
4332141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4333141cc406Sopenharmony_ci        return status;
4334141cc406Sopenharmony_ci      }
4335141cc406Sopenharmony_ci    sanei_scsi_close(sfd);
4336141cc406Sopenharmony_ci
4337141cc406Sopenharmony_ci    if (md_dump >= 2 )
4338141cc406Sopenharmony_ci      {
4339141cc406Sopenharmony_ci        dump_area2((uint8_t *) result, size, "inquiryresult");
4340141cc406Sopenharmony_ci        dump_area((uint8_t *) result, size, "inquiryresult");
4341141cc406Sopenharmony_ci      }
4342141cc406Sopenharmony_ci
4343141cc406Sopenharmony_ci    /* copy results */
4344141cc406Sopenharmony_ci    INQ_GET_QUAL(mi->device_qualifier, result);
4345141cc406Sopenharmony_ci    INQ_GET_DEVT(mi->device_type, result);
4346141cc406Sopenharmony_ci    INQ_GET_VERSION(mi->scsi_version, result);
4347141cc406Sopenharmony_ci    INQ_GET_VENDOR(mi->vendor, (char *)result);
4348141cc406Sopenharmony_ci    INQ_GET_MODEL(mi->model, (char *)result);
4349141cc406Sopenharmony_ci    INQ_GET_REV(mi->revision, (char *)result);
4350141cc406Sopenharmony_ci    INQ_GET_MODELCODE(mi->model_code, result);
4351141cc406Sopenharmony_ci
4352141cc406Sopenharmony_ci
4353141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4354141cc406Sopenharmony_ci}
4355141cc406Sopenharmony_ci
4356141cc406Sopenharmony_ci
4357141cc406Sopenharmony_ci/*---------- scsi_read_attributes() ------------------------------------------*/
4358141cc406Sopenharmony_ci
4359141cc406Sopenharmony_cistatic SANE_Status
4360141cc406Sopenharmony_ciscsi_read_attributes(Microtek2_Info *pmi, char *device, uint8_t scan_source)
4361141cc406Sopenharmony_ci{
4362141cc406Sopenharmony_ci    SANE_Status status;
4363141cc406Sopenharmony_ci    Microtek2_Info *mi;
4364141cc406Sopenharmony_ci    uint8_t readattributes[RSA_CMD_L];
4365141cc406Sopenharmony_ci    uint8_t result[RSA_TRANSFERLENGTH];
4366141cc406Sopenharmony_ci    size_t size;
4367141cc406Sopenharmony_ci    int sfd;
4368141cc406Sopenharmony_ci
4369141cc406Sopenharmony_ci
4370141cc406Sopenharmony_ci    mi = &pmi[scan_source];
4371141cc406Sopenharmony_ci
4372141cc406Sopenharmony_ci    DBG(30, "scsi_read_attributes: mi=%p, device='%s', source=%d\n",
4373141cc406Sopenharmony_ci             (void *) mi, device, scan_source);
4374141cc406Sopenharmony_ci
4375141cc406Sopenharmony_ci    RSA_CMD(readattributes);
4376141cc406Sopenharmony_ci    RSA_SETMEDIA(readattributes, scan_source);
4377141cc406Sopenharmony_ci    status = sanei_scsi_open(device, &sfd, scsi_sense_handler, 0);
4378141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4379141cc406Sopenharmony_ci      {
4380141cc406Sopenharmony_ci        DBG(1, "scsi_read_attributes: open '%s'\n", sane_strstatus(status));
4381141cc406Sopenharmony_ci        return status;
4382141cc406Sopenharmony_ci      }
4383141cc406Sopenharmony_ci
4384141cc406Sopenharmony_ci    if (md_dump >= 2 )
4385141cc406Sopenharmony_ci        dump_area2(readattributes, sizeof(readattributes), "scannerattributes");
4386141cc406Sopenharmony_ci
4387141cc406Sopenharmony_ci    size = sizeof(result);
4388141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, readattributes,
4389141cc406Sopenharmony_ci                            sizeof(readattributes), result, &size);
4390141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4391141cc406Sopenharmony_ci      {
4392141cc406Sopenharmony_ci        DBG(1, "scsi_read_attributes: cmd '%s'\n", sane_strstatus(status));
4393141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4394141cc406Sopenharmony_ci        return status;
4395141cc406Sopenharmony_ci      }
4396141cc406Sopenharmony_ci
4397141cc406Sopenharmony_ci    sanei_scsi_close(sfd);
4398141cc406Sopenharmony_ci
4399141cc406Sopenharmony_ci    /* The X6 appears to lie about the data format for a TMA */
4400141cc406Sopenharmony_ci    if ( (&pmi[0])->model_code == 0x91 )
4401141cc406Sopenharmony_ci        result[0] &= 0xfd;
4402141cc406Sopenharmony_ci    /* default value for calib_divisor ... bit49?? */
4403141cc406Sopenharmony_ci    mi->calib_divisor = 1;
4404141cc406Sopenharmony_ci    /* 9600XL */
4405141cc406Sopenharmony_ci    if ( (&pmi[0])->model_code == 0xde )
4406141cc406Sopenharmony_ci        mi->calib_divisor = 2;
4407141cc406Sopenharmony_ci    /* 6400XL has problems in lineart mode*/
4408141cc406Sopenharmony_ci    if ( (&pmi[0])->model_code == 0x89 )
4409141cc406Sopenharmony_ci        result[13] &= 0xfe; /* simulate no lineart */
4410141cc406Sopenharmony_ci#if 0
4411141cc406Sopenharmony_ci    result[13] &= 0xfe; /* simulate no lineart */
4412141cc406Sopenharmony_ci#endif
4413141cc406Sopenharmony_ci
4414141cc406Sopenharmony_ci    /* copy all the stuff into the info structure */
4415141cc406Sopenharmony_ci    RSA_COLOR(mi->color, result);
4416141cc406Sopenharmony_ci    RSA_ONEPASS(mi->onepass, result);
4417141cc406Sopenharmony_ci    RSA_SCANNERTYPE(mi->scanner_type, result);
4418141cc406Sopenharmony_ci    RSA_FEPROM(mi->feprom, result);
4419141cc406Sopenharmony_ci    RSA_DATAFORMAT(mi->data_format, result);
4420141cc406Sopenharmony_ci    RSA_COLORSEQUENCE(mi->color_sequence, result);
4421141cc406Sopenharmony_ci    RSA_NIS(mi->new_image_status, result);
4422141cc406Sopenharmony_ci    RSA_DATSEQ(mi->direction, result);
4423141cc406Sopenharmony_ci    RSA_CCDGAP(mi->ccd_gap, result);
4424141cc406Sopenharmony_ci    RSA_MAX_XRESOLUTION(mi->max_xresolution, result);
4425141cc406Sopenharmony_ci    RSA_MAX_YRESOLUTION(mi->max_yresolution, result);
4426141cc406Sopenharmony_ci    RSA_GEOWIDTH(mi->geo_width, result);
4427141cc406Sopenharmony_ci    RSA_GEOHEIGHT(mi->geo_height, result);
4428141cc406Sopenharmony_ci    RSA_OPTRESOLUTION(mi->opt_resolution, result);
4429141cc406Sopenharmony_ci    RSA_DEPTH(mi->depth, result);
4430141cc406Sopenharmony_ci    /* The X12USL doesn't say that it has 14bit */
4431141cc406Sopenharmony_ci    if ( (&pmi[0])->model_code == 0xb0 )
4432141cc406Sopenharmony_ci        mi->depth |= MI_HASDEPTH_14;
4433141cc406Sopenharmony_ci    RSA_SCANMODE(mi->scanmode, result);
4434141cc406Sopenharmony_ci    RSA_CCDPIXELS(mi->ccd_pixels, result);
4435141cc406Sopenharmony_ci    RSA_LUTCAP(mi->lut_cap, result);
4436141cc406Sopenharmony_ci    RSA_DNLDPTRN(mi->has_dnldptrn, result);
4437141cc406Sopenharmony_ci    RSA_GRAINSLCT(mi->grain_slct, result);
4438141cc406Sopenharmony_ci    RSA_SUPPOPT(mi->option_device, result);
4439141cc406Sopenharmony_ci    RSA_CALIBWHITE(mi->calib_white, result);
4440141cc406Sopenharmony_ci    RSA_CALIBSPACE(mi->calib_space, result);
4441141cc406Sopenharmony_ci    RSA_NLENS(mi->nlens, result);
4442141cc406Sopenharmony_ci    RSA_NWINDOWS(mi->nwindows, result);
4443141cc406Sopenharmony_ci    RSA_SHTRNSFEREQU(mi->shtrnsferequ, result);
4444141cc406Sopenharmony_ci    RSA_SCNBTTN(mi->scnbuttn, result);
4445141cc406Sopenharmony_ci    RSA_BUFTYPE(mi->buftype, result);
4446141cc406Sopenharmony_ci    RSA_REDBALANCE(mi->balance[0], result);
4447141cc406Sopenharmony_ci    RSA_GREENBALANCE(mi->balance[1], result);
4448141cc406Sopenharmony_ci    RSA_BLUEBALANCE(mi->balance[2], result);
4449141cc406Sopenharmony_ci    RSA_APSMAXFRAMES(mi->aps_maxframes, result);
4450141cc406Sopenharmony_ci
4451141cc406Sopenharmony_ci    if (md_dump >= 2 )
4452141cc406Sopenharmony_ci        dump_area2((uint8_t *) result, sizeof(result),
4453141cc406Sopenharmony_ci                   "scannerattributesresults");
4454141cc406Sopenharmony_ci    if ( md_dump >= 1 && md_dump_clear )
4455141cc406Sopenharmony_ci        dump_attributes(mi);
4456141cc406Sopenharmony_ci
4457141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4458141cc406Sopenharmony_ci}
4459141cc406Sopenharmony_ci
4460141cc406Sopenharmony_ci
4461141cc406Sopenharmony_ci/*---------- scsi_read_control_bits() ----------------------------------------*/
4462141cc406Sopenharmony_ci
4463141cc406Sopenharmony_cistatic SANE_Status
4464141cc406Sopenharmony_ciscsi_read_control_bits(Microtek2_Scanner *ms)
4465141cc406Sopenharmony_ci{
4466141cc406Sopenharmony_ci    SANE_Status status;
4467141cc406Sopenharmony_ci    uint8_t cmd[RCB_CMD_L];
4468141cc406Sopenharmony_ci    uint32_t byte;
4469141cc406Sopenharmony_ci    int bit;
4470141cc406Sopenharmony_ci    int count_1s;
4471141cc406Sopenharmony_ci
4472141cc406Sopenharmony_ci    DBG(30, "scsi_read_control_bits: ms=%p, fd=%d\n", (void *) ms, ms->sfd);
4473141cc406Sopenharmony_ci    DBG(30, "ms->control_bytes = %p\n", (void *) ms->control_bytes);
4474141cc406Sopenharmony_ci
4475141cc406Sopenharmony_ci    RCB_SET_CMD(cmd);
4476141cc406Sopenharmony_ci    RCB_SET_LENGTH(cmd, ms->n_control_bytes);
4477141cc406Sopenharmony_ci
4478141cc406Sopenharmony_ci    if ( md_dump >= 2)
4479141cc406Sopenharmony_ci        dump_area2(cmd, RCB_CMD_L, "readcontrolbits");
4480141cc406Sopenharmony_ci
4481141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd,
4482141cc406Sopenharmony_ci                            cmd,
4483141cc406Sopenharmony_ci                            sizeof(cmd),
4484141cc406Sopenharmony_ci                            ms->control_bytes,
4485141cc406Sopenharmony_ci                            &ms->n_control_bytes);
4486141cc406Sopenharmony_ci
4487141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4488141cc406Sopenharmony_ci      {
4489141cc406Sopenharmony_ci        DBG(1, "scsi_read_control_bits: cmd '%s'\n", sane_strstatus(status));
4490141cc406Sopenharmony_ci        return status;
4491141cc406Sopenharmony_ci      }
4492141cc406Sopenharmony_ci
4493141cc406Sopenharmony_ci    if ( md_dump >= 2)
4494141cc406Sopenharmony_ci        dump_area2(ms->control_bytes,
4495141cc406Sopenharmony_ci                   ms->n_control_bytes,
4496141cc406Sopenharmony_ci                   "readcontrolbitsresult");
4497141cc406Sopenharmony_ci
4498141cc406Sopenharmony_ci    count_1s = 0;
4499141cc406Sopenharmony_ci    for ( byte = 0; byte < ms->n_control_bytes; byte++ )
4500141cc406Sopenharmony_ci      {
4501141cc406Sopenharmony_ci        for ( bit = 0; bit < 8; bit++ )
4502141cc406Sopenharmony_ci          {
4503141cc406Sopenharmony_ci            if ( (ms->control_bytes[byte] >> bit) & 0x01 )
4504141cc406Sopenharmony_ci                ++count_1s;
4505141cc406Sopenharmony_ci          }
4506141cc406Sopenharmony_ci      }
4507141cc406Sopenharmony_ci    DBG(20, "read_control_bits: number of 1's in controlbytes: %d\n", count_1s);
4508141cc406Sopenharmony_ci
4509141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4510141cc406Sopenharmony_ci}
4511141cc406Sopenharmony_ci
4512141cc406Sopenharmony_ci
4513141cc406Sopenharmony_ci/*---------- scsi_set_window() -----------------------------------------------*/
4514141cc406Sopenharmony_ci
4515141cc406Sopenharmony_cistatic SANE_Status
4516141cc406Sopenharmony_ciscsi_set_window(Microtek2_Scanner *ms, int n) {   /* n windows, not yet */
4517141cc406Sopenharmony_ci                                                  /* implemented */
4518141cc406Sopenharmony_ci    SANE_Status status;
4519141cc406Sopenharmony_ci    uint8_t *setwindow;
4520141cc406Sopenharmony_ci    int size;
4521141cc406Sopenharmony_ci
4522141cc406Sopenharmony_ci
4523141cc406Sopenharmony_ci    DBG(30, "scsi_set_window: ms=%p, wnd=%d\n", (void *) ms, n);
4524141cc406Sopenharmony_ci
4525141cc406Sopenharmony_ci    size = SW_CMD_L + SW_HEADER_L + n * SW_BODY_L;
4526141cc406Sopenharmony_ci    setwindow = (uint8_t *) malloc(size);
4527141cc406Sopenharmony_ci    DBG(100, "scsi_set_window: setwindow= %p, malloc'd %d Bytes\n",
4528141cc406Sopenharmony_ci              (void *) setwindow, size);
4529141cc406Sopenharmony_ci    if ( setwindow == NULL )
4530141cc406Sopenharmony_ci      {
4531141cc406Sopenharmony_ci        DBG(1, "scsi_set_window: malloc for setwindow failed\n");
4532141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
4533141cc406Sopenharmony_ci      }
4534141cc406Sopenharmony_ci    memset(setwindow, 0, size);
4535141cc406Sopenharmony_ci
4536141cc406Sopenharmony_ci    SW_CMD(setwindow);
4537141cc406Sopenharmony_ci    SW_PARAM_LENGTH(setwindow, SW_HEADER_L + n * SW_BODY_L);
4538141cc406Sopenharmony_ci    SW_WNDDESCLEN(setwindow + SW_HEADER_P, SW_WNDDESCVAL);
4539141cc406Sopenharmony_ci
4540141cc406Sopenharmony_ci#define POS  (setwindow + SW_BODY_P(n-1))
4541141cc406Sopenharmony_ci
4542141cc406Sopenharmony_ci    SW_WNDID(POS, n-1);
4543141cc406Sopenharmony_ci    SW_XRESDPI(POS, ms->x_resolution_dpi);
4544141cc406Sopenharmony_ci    SW_YRESDPI(POS, ms->y_resolution_dpi);
4545141cc406Sopenharmony_ci    SW_XPOSTL(POS, ms->x1_dots);
4546141cc406Sopenharmony_ci    SW_YPOSTL(POS, ms->y1_dots);
4547141cc406Sopenharmony_ci    SW_WNDWIDTH(POS, ms->width_dots);
4548141cc406Sopenharmony_ci    SW_WNDHEIGHT(POS, ms->height_dots);
4549141cc406Sopenharmony_ci    SW_THRESHOLD(POS, ms->threshold);
4550141cc406Sopenharmony_ci    SW_IMGCOMP(POS, ms->mode);
4551141cc406Sopenharmony_ci    SW_BITSPERPIXEL(POS, ms->depth);
4552141cc406Sopenharmony_ci    SW_EXTHT(POS, ms->use_external_ht);
4553141cc406Sopenharmony_ci    SW_INTHTINDEX(POS, ms->internal_ht_index);
4554141cc406Sopenharmony_ci    SW_RIF(POS, 1);
4555141cc406Sopenharmony_ci    SW_LENS(POS, 0);                                  /* ???? */
4556141cc406Sopenharmony_ci    SW_INFINITE(POS, 0);
4557141cc406Sopenharmony_ci    SW_STAY(POS, ms->stay);
4558141cc406Sopenharmony_ci    SW_RAWDAT(POS, ms->rawdat);
4559141cc406Sopenharmony_ci    SW_QUALITY(POS, ms->quality);
4560141cc406Sopenharmony_ci    SW_FASTSCAN(POS, ms->fastscan);
4561141cc406Sopenharmony_ci    SW_MEDIA(POS, ms->scan_source);
4562141cc406Sopenharmony_ci    SW_BRIGHTNESS_M(POS, ms->brightness_m);
4563141cc406Sopenharmony_ci    SW_CONTRAST_M(POS, ms->contrast_m);
4564141cc406Sopenharmony_ci    SW_EXPOSURE_M(POS, ms->exposure_m);
4565141cc406Sopenharmony_ci    SW_SHADOW_M(POS, ms->shadow_m);
4566141cc406Sopenharmony_ci    SW_MIDTONE_M(POS, ms->midtone_m);
4567141cc406Sopenharmony_ci    SW_HIGHLIGHT_M(POS, ms->highlight_m);
4568141cc406Sopenharmony_ci    /* the following properties are only referenced if it's a color scan */
4569141cc406Sopenharmony_ci    /* but I guess they don't matter at a gray scan */
4570141cc406Sopenharmony_ci    SW_BRIGHTNESS_R(POS, ms->brightness_r);
4571141cc406Sopenharmony_ci    SW_CONTRAST_R(POS, ms->contrast_r);
4572141cc406Sopenharmony_ci    SW_EXPOSURE_R(POS, ms->exposure_r);
4573141cc406Sopenharmony_ci    SW_SHADOW_R(POS, ms->shadow_r);
4574141cc406Sopenharmony_ci    SW_MIDTONE_R(POS, ms->midtone_r);
4575141cc406Sopenharmony_ci    SW_HIGHLIGHT_R(POS, ms->highlight_r);
4576141cc406Sopenharmony_ci    SW_BRIGHTNESS_G(POS, ms->brightness_g);
4577141cc406Sopenharmony_ci    SW_CONTRAST_G(POS, ms->contrast_g);
4578141cc406Sopenharmony_ci    SW_EXPOSURE_G(POS, ms->exposure_g);
4579141cc406Sopenharmony_ci    SW_SHADOW_G(POS, ms->shadow_g);
4580141cc406Sopenharmony_ci    SW_MIDTONE_G(POS, ms->midtone_g);
4581141cc406Sopenharmony_ci    SW_HIGHLIGHT_G(POS, ms->highlight_g);
4582141cc406Sopenharmony_ci    SW_BRIGHTNESS_B(POS, ms->brightness_b);
4583141cc406Sopenharmony_ci    SW_CONTRAST_B(POS, ms->contrast_b);
4584141cc406Sopenharmony_ci    SW_EXPOSURE_B(POS, ms->exposure_b);
4585141cc406Sopenharmony_ci    SW_SHADOW_B(POS, ms->shadow_b);
4586141cc406Sopenharmony_ci    SW_MIDTONE_B(POS, ms->midtone_b);
4587141cc406Sopenharmony_ci    SW_HIGHLIGHT_B(POS, ms->highlight_b);
4588141cc406Sopenharmony_ci
4589141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4590141cc406Sopenharmony_ci      {
4591141cc406Sopenharmony_ci        dump_area2(setwindow, 10, "setwindowcmd");
4592141cc406Sopenharmony_ci        dump_area2(setwindow + 10 ,8 , "setwindowheader");
4593141cc406Sopenharmony_ci        dump_area2(setwindow + 18 ,61 , "setwindowbody");
4594141cc406Sopenharmony_ci      }
4595141cc406Sopenharmony_ci
4596141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, setwindow, size, NULL, 0);
4597141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4598141cc406Sopenharmony_ci        DBG(1, "scsi_set_window: '%s'\n", sane_strstatus(status));
4599141cc406Sopenharmony_ci
4600141cc406Sopenharmony_ci    DBG(100, "scsi_set_window: free setwindow at %p\n", (void *) setwindow);
4601141cc406Sopenharmony_ci    free((void *) setwindow);
4602141cc406Sopenharmony_ci    return status;
4603141cc406Sopenharmony_ci}
4604141cc406Sopenharmony_ci
4605141cc406Sopenharmony_ci
4606141cc406Sopenharmony_ci/*---------- scsi_read_image_info() ------------------------------------------*/
4607141cc406Sopenharmony_ci
4608141cc406Sopenharmony_cistatic SANE_Status
4609141cc406Sopenharmony_ciscsi_read_image_info(Microtek2_Scanner *ms)
4610141cc406Sopenharmony_ci{
4611141cc406Sopenharmony_ci    uint8_t cmd[RII_CMD_L];
4612141cc406Sopenharmony_ci    uint8_t result[RII_RESULT_L];
4613141cc406Sopenharmony_ci    size_t size;
4614141cc406Sopenharmony_ci    SANE_Status status;
4615141cc406Sopenharmony_ci    Microtek2_Device *md;
4616141cc406Sopenharmony_ci
4617141cc406Sopenharmony_ci    md = ms->dev;
4618141cc406Sopenharmony_ci
4619141cc406Sopenharmony_ci    DBG(30, "scsi_read_image_info: ms=%p\n", (void *) ms);
4620141cc406Sopenharmony_ci
4621141cc406Sopenharmony_ci    RII_SET_CMD(cmd);
4622141cc406Sopenharmony_ci
4623141cc406Sopenharmony_ci    if ( md_dump >= 2)
4624141cc406Sopenharmony_ci        dump_area2(cmd, RII_CMD_L, "readimageinfo");
4625141cc406Sopenharmony_ci
4626141cc406Sopenharmony_ci    size = sizeof(result);
4627141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), result, &size);
4628141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4629141cc406Sopenharmony_ci      {
4630141cc406Sopenharmony_ci        DBG(1, "scsi_read_image_info: '%s'\n", sane_strstatus(status));
4631141cc406Sopenharmony_ci        return status;
4632141cc406Sopenharmony_ci      }
4633141cc406Sopenharmony_ci
4634141cc406Sopenharmony_ci    if ( md_dump >= 2)
4635141cc406Sopenharmony_ci        dump_area2(result, size, "readimageinforesult");
4636141cc406Sopenharmony_ci
4637141cc406Sopenharmony_ci    /* The V300 returns some values in only two bytes */
4638141cc406Sopenharmony_ci    if ( !(md->revision==2.70) && (md->model_flags & MD_RII_TWO_BYTES) )
4639141cc406Sopenharmony_ci      {
4640141cc406Sopenharmony_ci        RII_GET_V300_WIDTHPIXEL(ms->ppl, result);
4641141cc406Sopenharmony_ci        RII_GET_V300_WIDTHBYTES(ms->bpl, result);
4642141cc406Sopenharmony_ci        RII_GET_V300_HEIGHTLINES(ms->src_remaining_lines, result);
4643141cc406Sopenharmony_ci        RII_GET_V300_REMAINBYTES(ms->remaining_bytes, result);
4644141cc406Sopenharmony_ci      }
4645141cc406Sopenharmony_ci    else
4646141cc406Sopenharmony_ci      {
4647141cc406Sopenharmony_ci        RII_GET_WIDTHPIXEL(ms->ppl, result);
4648141cc406Sopenharmony_ci        RII_GET_WIDTHBYTES(ms->bpl, result);
4649141cc406Sopenharmony_ci        RII_GET_HEIGHTLINES(ms->src_remaining_lines, result);
4650141cc406Sopenharmony_ci        RII_GET_REMAINBYTES(ms->remaining_bytes, result);
4651141cc406Sopenharmony_ci      }
4652141cc406Sopenharmony_ci
4653141cc406Sopenharmony_ci    DBG(30, "scsi_read_image_info: ppl=%d, bpl=%d, lines=%d, remain=%d\n",
4654141cc406Sopenharmony_ci             ms->ppl, ms->bpl, ms->src_remaining_lines, ms->remaining_bytes);
4655141cc406Sopenharmony_ci
4656141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4657141cc406Sopenharmony_ci}
4658141cc406Sopenharmony_ci
4659141cc406Sopenharmony_ci
4660141cc406Sopenharmony_ci/*---------- scsi_read_image() -----------------------------------------------*/
4661141cc406Sopenharmony_ci
4662141cc406Sopenharmony_cistatic SANE_Status
4663141cc406Sopenharmony_ciscsi_read_image(Microtek2_Scanner *ms, uint8_t *buffer, int bytes_per_pixel)
4664141cc406Sopenharmony_ci{
4665141cc406Sopenharmony_ci    uint8_t cmd[RI_CMD_L];
4666141cc406Sopenharmony_ci    SANE_Bool endiantype;
4667141cc406Sopenharmony_ci    SANE_Status status;
4668141cc406Sopenharmony_ci    size_t size;
4669141cc406Sopenharmony_ci    size_t i;
4670141cc406Sopenharmony_ci    uint8_t tmp;
4671141cc406Sopenharmony_ci
4672141cc406Sopenharmony_ci
4673141cc406Sopenharmony_ci    DBG(30, "scsi_read_image:  ms=%p, buffer=%p\n",
4674141cc406Sopenharmony_ci             (void *) ms, (void *) buffer);
4675141cc406Sopenharmony_ci
4676141cc406Sopenharmony_ci    ENDIAN_TYPE(endiantype)
4677141cc406Sopenharmony_ci    RI_SET_CMD(cmd);
4678141cc406Sopenharmony_ci    RI_SET_PCORMAC(cmd, endiantype);
4679141cc406Sopenharmony_ci    RI_SET_COLOR(cmd, ms->current_read_color);
4680141cc406Sopenharmony_ci    RI_SET_TRANSFERLENGTH(cmd, ms->transfer_length);
4681141cc406Sopenharmony_ci
4682141cc406Sopenharmony_ci    DBG(30, "scsi_read_image: transferlength=%d\n", ms->transfer_length);
4683141cc406Sopenharmony_ci
4684141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4685141cc406Sopenharmony_ci        dump_area2(cmd, RI_CMD_L, "readimagecmd");
4686141cc406Sopenharmony_ci
4687141cc406Sopenharmony_ci    size = ms->transfer_length;
4688141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), buffer, &size);
4689141cc406Sopenharmony_ci
4690141cc406Sopenharmony_ci    if ( buffer && ( ms->dev->model_flags & MD_PHANTOM_C6 ) && endiantype )
4691141cc406Sopenharmony_ci      {
4692141cc406Sopenharmony_ci	switch(bytes_per_pixel)
4693141cc406Sopenharmony_ci	  {
4694141cc406Sopenharmony_ci	    case 1: break;
4695141cc406Sopenharmony_ci	    case 2:
4696141cc406Sopenharmony_ci		    for ( i = 1; i < size; i += 2 )
4697141cc406Sopenharmony_ci		      {
4698141cc406Sopenharmony_ci			tmp = buffer[i-1];
4699141cc406Sopenharmony_ci			buffer[i-1] = buffer[i];
4700141cc406Sopenharmony_ci			buffer[i] = tmp;
4701141cc406Sopenharmony_ci		      }
4702141cc406Sopenharmony_ci		    break;
4703141cc406Sopenharmony_ci	    default:
4704141cc406Sopenharmony_ci		    DBG(1, "scsi_read_image: Unexpected bytes_per_pixel=%d\n", bytes_per_pixel);
4705141cc406Sopenharmony_ci	  }
4706141cc406Sopenharmony_ci      }
4707141cc406Sopenharmony_ci
4708141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4709141cc406Sopenharmony_ci        DBG(1, "scsi_read_image: '%s'\n", sane_strstatus(status));
4710141cc406Sopenharmony_ci
4711141cc406Sopenharmony_ci    if ( md_dump > 3 )
4712141cc406Sopenharmony_ci        dump_area2(buffer, ms->transfer_length, "readimageresult");
4713141cc406Sopenharmony_ci
4714141cc406Sopenharmony_ci    return status;
4715141cc406Sopenharmony_ci}
4716141cc406Sopenharmony_ci
4717141cc406Sopenharmony_ci
4718141cc406Sopenharmony_ci/*---------- scsi_read_image_status() ----------------------------------------*/
4719141cc406Sopenharmony_ci
4720141cc406Sopenharmony_cistatic SANE_Status
4721141cc406Sopenharmony_ciscsi_read_image_status(Microtek2_Scanner *ms)
4722141cc406Sopenharmony_ci{
4723141cc406Sopenharmony_ci    Microtek2_Device *md;
4724141cc406Sopenharmony_ci    Microtek2_Info *mi;
4725141cc406Sopenharmony_ci    uint8_t cmd[RIS_CMD_L];
4726141cc406Sopenharmony_ci    uint8_t dummy;
4727141cc406Sopenharmony_ci    size_t dummy_length;
4728141cc406Sopenharmony_ci    SANE_Status status;
4729141cc406Sopenharmony_ci    SANE_Bool endian_type;
4730141cc406Sopenharmony_ci
4731141cc406Sopenharmony_ci    md = ms->dev;
4732141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
4733141cc406Sopenharmony_ci
4734141cc406Sopenharmony_ci    DBG(30, "scsi_read_image_status: ms=%p\n", (void *) ms);
4735141cc406Sopenharmony_ci
4736141cc406Sopenharmony_ci    ENDIAN_TYPE(endian_type)
4737141cc406Sopenharmony_ci    RIS_SET_CMD(cmd);
4738141cc406Sopenharmony_ci    RIS_SET_PCORMAC(cmd, endian_type);
4739141cc406Sopenharmony_ci    RIS_SET_COLOR(cmd, ms->current_read_color);
4740141cc406Sopenharmony_ci
4741141cc406Sopenharmony_ci/*    mi->new_image_status = SANE_TRUE;  */  /* for testing*/
4742141cc406Sopenharmony_ci
4743141cc406Sopenharmony_ci    if ( mi->new_image_status == SANE_TRUE )
4744141cc406Sopenharmony_ci      {
4745141cc406Sopenharmony_ci        DBG(30, "scsi_read_image_status: use new image status \n");
4746141cc406Sopenharmony_ci        dummy_length = 1;
4747141cc406Sopenharmony_ci        cmd[8] = 1;
4748141cc406Sopenharmony_ci      }
4749141cc406Sopenharmony_ci    else
4750141cc406Sopenharmony_ci      {
4751141cc406Sopenharmony_ci        DBG(30, "scsi_read_image_status: use old image status \n");
4752141cc406Sopenharmony_ci        dummy_length = 0;
4753141cc406Sopenharmony_ci        cmd[8] = 0;
4754141cc406Sopenharmony_ci      }
4755141cc406Sopenharmony_ci
4756141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4757141cc406Sopenharmony_ci        dump_area2(cmd, sizeof(cmd), "readimagestatus");
4758141cc406Sopenharmony_ci
4759141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), &dummy, &dummy_length);
4760141cc406Sopenharmony_ci
4761141cc406Sopenharmony_ci    if ( mi->new_image_status == SANE_TRUE )
4762141cc406Sopenharmony_ci      {
4763141cc406Sopenharmony_ci        if ( dummy == 0 )
4764141cc406Sopenharmony_ci            status = SANE_STATUS_GOOD;
4765141cc406Sopenharmony_ci        else
4766141cc406Sopenharmony_ci            status = SANE_STATUS_DEVICE_BUSY;
4767141cc406Sopenharmony_ci      }
4768141cc406Sopenharmony_ci
4769141cc406Sopenharmony_ci        /* For some (X6USB) scanner
4770141cc406Sopenharmony_ci        We say we are going to try to read 1 byte of data (as recommended
4771141cc406Sopenharmony_ci        in the Microtek SCSI command documentation under "New Image Status")
4772141cc406Sopenharmony_ci        so that dubious SCSI host adapters (like the one in at least some
4773141cc406Sopenharmony_ci        Microtek X6 USB scanners) don't get wedged trying to do a zero
4774141cc406Sopenharmony_ci        length read. However, we do not actually try to read this byte of
4775141cc406Sopenharmony_ci        data, as that wedges the USB scanner as well.
4776141cc406Sopenharmony_ci        IOW the SCSI command says we are going to read 1 byte, but in fact
4777141cc406Sopenharmony_ci        we don't: */
4778141cc406Sopenharmony_ci        /*cmd[8] = 1;
4779141cc406Sopenharmony_ci        status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), &dummy, 0); */
4780141cc406Sopenharmony_ci
4781141cc406Sopenharmony_ci
4782141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4783141cc406Sopenharmony_ci        DBG(1, "scsi_read_image_status: '%s'\n", sane_strstatus(status));
4784141cc406Sopenharmony_ci
4785141cc406Sopenharmony_ci    return status;
4786141cc406Sopenharmony_ci}
4787141cc406Sopenharmony_ci
4788141cc406Sopenharmony_ci/*---------- scsi_read_shading () --------------------------------------------*/
4789141cc406Sopenharmony_ci
4790141cc406Sopenharmony_cistatic SANE_Status
4791141cc406Sopenharmony_ciscsi_read_shading(Microtek2_Scanner *ms, uint8_t *buffer, uint32_t length)
4792141cc406Sopenharmony_ci{
4793141cc406Sopenharmony_ci    uint8_t cmd[RSI_CMD_L];
4794141cc406Sopenharmony_ci    SANE_Bool endiantype;
4795141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
4796141cc406Sopenharmony_ci    size_t size;
4797141cc406Sopenharmony_ci
4798141cc406Sopenharmony_ci    DBG(30, "scsi_read_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n",
4799141cc406Sopenharmony_ci             (void *) buffer, length, ms->word, ms->current_color, ms->dark);
4800141cc406Sopenharmony_ci
4801141cc406Sopenharmony_ci    size = length;
4802141cc406Sopenharmony_ci
4803141cc406Sopenharmony_ci    RSI_SET_CMD(cmd);
4804141cc406Sopenharmony_ci    ENDIAN_TYPE(endiantype)
4805141cc406Sopenharmony_ci    RSI_SET_PCORMAC(cmd, endiantype);
4806141cc406Sopenharmony_ci    RSI_SET_COLOR(cmd, ms->current_color);
4807141cc406Sopenharmony_ci    RSI_SET_DARK(cmd, ms->dark);
4808141cc406Sopenharmony_ci    RSI_SET_WORD(cmd, ms->word);
4809141cc406Sopenharmony_ci    RSI_SET_TRANSFERLENGTH(cmd, size);
4810141cc406Sopenharmony_ci
4811141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4812141cc406Sopenharmony_ci        dump_area2(cmd, RSI_CMD_L, "readshading");
4813141cc406Sopenharmony_ci
4814141cc406Sopenharmony_ci    DBG(100, "scsi_read_shading: sfd=%d, cmd=%p, sizeofcmd=%lu,"
4815141cc406Sopenharmony_ci             "dest=%p, destsize=%lu\n",
4816141cc406Sopenharmony_ci              ms->sfd, (void *) cmd, (u_long) sizeof(cmd), (void *) buffer,
4817141cc406Sopenharmony_ci              (u_long) size);
4818141cc406Sopenharmony_ci
4819141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, cmd, sizeof(cmd), buffer, &size);
4820141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4821141cc406Sopenharmony_ci        DBG(1, "scsi_read_shading: '%s'\n", sane_strstatus(status));
4822141cc406Sopenharmony_ci
4823141cc406Sopenharmony_ci    if ( md_dump > 3)
4824141cc406Sopenharmony_ci        dump_area2(buffer,
4825141cc406Sopenharmony_ci                   size,
4826141cc406Sopenharmony_ci                   "readshadingresult");
4827141cc406Sopenharmony_ci
4828141cc406Sopenharmony_ci    return status;
4829141cc406Sopenharmony_ci}
4830141cc406Sopenharmony_ci
4831141cc406Sopenharmony_ci
4832141cc406Sopenharmony_ci/*---------- scsi_send_shading () --------------------------------------------*/
4833141cc406Sopenharmony_ci
4834141cc406Sopenharmony_cistatic SANE_Status
4835141cc406Sopenharmony_ciscsi_send_shading(Microtek2_Scanner *ms,
4836141cc406Sopenharmony_ci                  uint8_t *shading_data,
4837141cc406Sopenharmony_ci                  uint32_t length,
4838141cc406Sopenharmony_ci                  uint8_t dark)
4839141cc406Sopenharmony_ci{
4840141cc406Sopenharmony_ci    SANE_Bool endiantype;
4841141cc406Sopenharmony_ci    SANE_Status status;
4842141cc406Sopenharmony_ci    size_t size;
4843141cc406Sopenharmony_ci    uint8_t *cmd;
4844141cc406Sopenharmony_ci
4845141cc406Sopenharmony_ci
4846141cc406Sopenharmony_ci    DBG(30, "scsi_send_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n",
4847141cc406Sopenharmony_ci             (void *) shading_data, length, ms->word, ms->current_color, dark);
4848141cc406Sopenharmony_ci
4849141cc406Sopenharmony_ci    cmd = (uint8_t *) malloc(SSI_CMD_L + length);
4850141cc406Sopenharmony_ci    DBG(100, "scsi_send_shading: cmd=%p, malloc'd %d bytes\n",
4851141cc406Sopenharmony_ci              (void *) cmd, SSI_CMD_L + length);
4852141cc406Sopenharmony_ci    if ( cmd == NULL )
4853141cc406Sopenharmony_ci      {
4854141cc406Sopenharmony_ci        DBG(1, "scsi_send_shading: Couldn't get buffer for shading table\n");
4855141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
4856141cc406Sopenharmony_ci      }
4857141cc406Sopenharmony_ci
4858141cc406Sopenharmony_ci    SSI_SET_CMD(cmd);
4859141cc406Sopenharmony_ci    ENDIAN_TYPE(endiantype)
4860141cc406Sopenharmony_ci    SSI_SET_PCORMAC(cmd, endiantype);
4861141cc406Sopenharmony_ci    SSI_SET_COLOR(cmd, ms->current_color);
4862141cc406Sopenharmony_ci    SSI_SET_DARK(cmd, dark);
4863141cc406Sopenharmony_ci    SSI_SET_WORD(cmd, ms->word);
4864141cc406Sopenharmony_ci    SSI_SET_TRANSFERLENGTH(cmd, length);
4865141cc406Sopenharmony_ci    memcpy(cmd + SSI_CMD_L, shading_data, length);
4866141cc406Sopenharmony_ci    size = length;
4867141cc406Sopenharmony_ci
4868141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4869141cc406Sopenharmony_ci        dump_area2(cmd, SSI_CMD_L, "sendshading");
4870141cc406Sopenharmony_ci    if ( md_dump >= 3 )
4871141cc406Sopenharmony_ci        dump_area2(cmd + SSI_CMD_L, size, "sendshadingdata");
4872141cc406Sopenharmony_ci
4873141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd, cmd, size + SSI_CMD_L, NULL, 0);
4874141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4875141cc406Sopenharmony_ci        DBG(1, "scsi_send_shading: '%s'\n", sane_strstatus(status));
4876141cc406Sopenharmony_ci
4877141cc406Sopenharmony_ci    DBG(100, "free cmd at %p\n", (void *) cmd);
4878141cc406Sopenharmony_ci    free((void *) cmd);
4879141cc406Sopenharmony_ci
4880141cc406Sopenharmony_ci    return status;
4881141cc406Sopenharmony_ci
4882141cc406Sopenharmony_ci}
4883141cc406Sopenharmony_ci
4884141cc406Sopenharmony_ci
4885141cc406Sopenharmony_ci/*---------- scsi_read_system_status() ---------------------------------------*/
4886141cc406Sopenharmony_ci
4887141cc406Sopenharmony_cistatic SANE_Status
4888141cc406Sopenharmony_ciscsi_read_system_status(Microtek2_Device *md, int fd)
4889141cc406Sopenharmony_ci{
4890141cc406Sopenharmony_ci    uint8_t cmd[RSS_CMD_L];
4891141cc406Sopenharmony_ci    uint8_t result[RSS_RESULT_L];
4892141cc406Sopenharmony_ci    int sfd;
4893141cc406Sopenharmony_ci    size_t size;
4894141cc406Sopenharmony_ci    SANE_Status status;
4895141cc406Sopenharmony_ci
4896141cc406Sopenharmony_ci    DBG(30, "scsi_read_system_status: md=%p, fd=%d\n", (void *) md, fd);
4897141cc406Sopenharmony_ci
4898141cc406Sopenharmony_ci    if ( fd == -1 )
4899141cc406Sopenharmony_ci      {
4900141cc406Sopenharmony_ci        status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
4901141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
4902141cc406Sopenharmony_ci          {
4903141cc406Sopenharmony_ci            DBG(1, "scsi_read_system_status: open '%s'\n",
4904141cc406Sopenharmony_ci                    sane_strstatus(status));
4905141cc406Sopenharmony_ci            return status;
4906141cc406Sopenharmony_ci          }
4907141cc406Sopenharmony_ci      }
4908141cc406Sopenharmony_ci    else
4909141cc406Sopenharmony_ci      sfd = fd;
4910141cc406Sopenharmony_ci
4911141cc406Sopenharmony_ci    RSS_CMD(cmd);
4912141cc406Sopenharmony_ci
4913141cc406Sopenharmony_ci    if ( md_dump >= 2)
4914141cc406Sopenharmony_ci        dump_area2(cmd, RSS_CMD_L, "readsystemstatus");
4915141cc406Sopenharmony_ci
4916141cc406Sopenharmony_ci    size = sizeof(result);
4917141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), result, &size);
4918141cc406Sopenharmony_ci
4919141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4920141cc406Sopenharmony_ci      {
4921141cc406Sopenharmony_ci        DBG(1, "scsi_read_system_status: cmd '%s'\n", sane_strstatus(status));
4922141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4923141cc406Sopenharmony_ci        return status;
4924141cc406Sopenharmony_ci      }
4925141cc406Sopenharmony_ci
4926141cc406Sopenharmony_ci    if ( fd == -1 )
4927141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
4928141cc406Sopenharmony_ci
4929141cc406Sopenharmony_ci    if ( md_dump >= 2)
4930141cc406Sopenharmony_ci        dump_area2(result, size, "readsystemstatusresult");
4931141cc406Sopenharmony_ci
4932141cc406Sopenharmony_ci    md->status.sskip = RSS_SSKIP(result);
4933141cc406Sopenharmony_ci    md->status.ntrack = RSS_NTRACK(result);
4934141cc406Sopenharmony_ci    md->status.ncalib = RSS_NCALIB(result);
4935141cc406Sopenharmony_ci    md->status.tlamp = RSS_TLAMP(result);
4936141cc406Sopenharmony_ci    md->status.flamp = RSS_FLAMP(result);
4937141cc406Sopenharmony_ci    md->status.rdyman= RSS_RDYMAN(result);
4938141cc406Sopenharmony_ci    md->status.trdy = RSS_TRDY(result);
4939141cc406Sopenharmony_ci    md->status.frdy = RSS_FRDY(result);
4940141cc406Sopenharmony_ci    md->status.adp = RSS_RDYMAN(result);
4941141cc406Sopenharmony_ci    md->status.detect = RSS_DETECT(result);
4942141cc406Sopenharmony_ci    md->status.adptime = RSS_ADPTIME(result);
4943141cc406Sopenharmony_ci    md->status.lensstatus = RSS_LENSSTATUS(result);
4944141cc406Sopenharmony_ci    md->status.aloff = RSS_ALOFF(result);
4945141cc406Sopenharmony_ci    md->status.timeremain = RSS_TIMEREMAIN(result);
4946141cc406Sopenharmony_ci    md->status.tmacnt = RSS_TMACNT(result);
4947141cc406Sopenharmony_ci    md->status.paper = RSS_PAPER(result);
4948141cc406Sopenharmony_ci    md->status.adfcnt = RSS_ADFCNT(result);
4949141cc406Sopenharmony_ci    md->status.currentmode = RSS_CURRENTMODE(result);
4950141cc406Sopenharmony_ci    md->status.buttoncount = RSS_BUTTONCOUNT(result);
4951141cc406Sopenharmony_ci
4952141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4953141cc406Sopenharmony_ci}
4954141cc406Sopenharmony_ci
4955141cc406Sopenharmony_ci
4956141cc406Sopenharmony_ci/*---------- scsi_request_sense() --------------------------------------------*/
4957141cc406Sopenharmony_ci
4958141cc406Sopenharmony_ci/* currently not used */
4959141cc406Sopenharmony_ci
4960141cc406Sopenharmony_ci#if 0
4961141cc406Sopenharmony_ci
4962141cc406Sopenharmony_cistatic SANE_Status
4963141cc406Sopenharmony_ciscsi_request_sense(Microtek2_Scanner *ms)
4964141cc406Sopenharmony_ci{
4965141cc406Sopenharmony_ci    uint8_t requestsense[RQS_CMD_L];
4966141cc406Sopenharmony_ci    uint8_t buffer[100];
4967141cc406Sopenharmony_ci    SANE_Status status;
4968141cc406Sopenharmony_ci    int size;
4969141cc406Sopenharmony_ci    int asl;
4970141cc406Sopenharmony_ci    int as_info_length;
4971141cc406Sopenharmony_ci
4972141cc406Sopenharmony_ci    DBG(30, "scsi_request_sense: ms=%p\n", (void *) ms);
4973141cc406Sopenharmony_ci
4974141cc406Sopenharmony_ci    RQS_CMD(requestsense);
4975141cc406Sopenharmony_ci    RQS_ALLOCLENGTH(requestsense, 100);
4976141cc406Sopenharmony_ci
4977141cc406Sopenharmony_ci    size = sizeof(buffer);
4978141cc406Sopenharmony_ci    status = sanei_scsi_cmd(ms->sfd,  requestsense, sizeof(requestsense),
4979141cc406Sopenharmony_ci                            buffer, &size);
4980141cc406Sopenharmony_ci
4981141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
4982141cc406Sopenharmony_ci      {
4983141cc406Sopenharmony_ci        DBG(1, "scsi_request_sense: '%s'\n", sane_strstatus(status));
4984141cc406Sopenharmony_ci        return status;
4985141cc406Sopenharmony_ci      }
4986141cc406Sopenharmony_ci
4987141cc406Sopenharmony_ci    if ( md_dump >= 2 )
4988141cc406Sopenharmony_ci        dump_area2(buffer, size, "requestsenseresult");
4989141cc406Sopenharmony_ci
4990141cc406Sopenharmony_ci    dump_area(buffer, RQS_LENGTH(buffer), "RequestSense");
4991141cc406Sopenharmony_ci    asl = RQS_ASL(buffer);
4992141cc406Sopenharmony_ci    if ( (as_info_length = RQS_ASINFOLENGTH(buffer)) > 0 )
4993141cc406Sopenharmony_ci        DBG(25, "scsi_request_sense: info '%.*s'\n",
4994141cc406Sopenharmony_ci                as_info_length, RQS_ASINFO(buffer));
4995141cc406Sopenharmony_ci
4996141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
4997141cc406Sopenharmony_ci}
4998141cc406Sopenharmony_ci#endif
4999141cc406Sopenharmony_ci
5000141cc406Sopenharmony_ci
5001141cc406Sopenharmony_ci/*---------- scsi_send_system_status() ---------------------------------------*/
5002141cc406Sopenharmony_ci
5003141cc406Sopenharmony_cistatic SANE_Status
5004141cc406Sopenharmony_ciscsi_send_system_status(Microtek2_Device *md, int fd)
5005141cc406Sopenharmony_ci{
5006141cc406Sopenharmony_ci    uint8_t cmd[SSS_CMD_L + SSS_DATA_L];
5007141cc406Sopenharmony_ci    uint8_t *pos;
5008141cc406Sopenharmony_ci    int sfd;
5009141cc406Sopenharmony_ci    SANE_Status status;
5010141cc406Sopenharmony_ci
5011141cc406Sopenharmony_ci
5012141cc406Sopenharmony_ci    DBG(30, "scsi_send_system_status: md=%p, fd=%d\n", (void *) md, fd);
5013141cc406Sopenharmony_ci
5014141cc406Sopenharmony_ci    memset(cmd, 0, SSS_CMD_L + SSS_DATA_L);
5015141cc406Sopenharmony_ci    if ( fd == -1 )
5016141cc406Sopenharmony_ci      {
5017141cc406Sopenharmony_ci        status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
5018141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5019141cc406Sopenharmony_ci          {
5020141cc406Sopenharmony_ci            DBG(1, "scsi_send_system_status: open '%s'\n",
5021141cc406Sopenharmony_ci                    sane_strstatus(status));
5022141cc406Sopenharmony_ci            return status;
5023141cc406Sopenharmony_ci          }
5024141cc406Sopenharmony_ci      }
5025141cc406Sopenharmony_ci    else
5026141cc406Sopenharmony_ci      sfd = fd;
5027141cc406Sopenharmony_ci
5028141cc406Sopenharmony_ci    SSS_CMD(cmd);
5029141cc406Sopenharmony_ci    pos = cmd + SSS_CMD_L;
5030141cc406Sopenharmony_ci    SSS_STICK(pos, md->status.stick);
5031141cc406Sopenharmony_ci    SSS_NTRACK(pos, md->status.ntrack);
5032141cc406Sopenharmony_ci    SSS_NCALIB(pos, md->status.ncalib);
5033141cc406Sopenharmony_ci    SSS_TLAMP(pos, md->status.tlamp);
5034141cc406Sopenharmony_ci    SSS_FLAMP(pos, md->status.flamp);
5035141cc406Sopenharmony_ci    SSS_RESERVED17(pos, md->status.reserved17);
5036141cc406Sopenharmony_ci    SSS_RDYMAN(pos, md->status.rdyman);
5037141cc406Sopenharmony_ci    SSS_TRDY(pos, md->status.trdy);
5038141cc406Sopenharmony_ci    SSS_FRDY(pos, md->status.frdy);
5039141cc406Sopenharmony_ci    SSS_ADP(pos, md->status.adp);
5040141cc406Sopenharmony_ci    SSS_DETECT(pos, md->status.detect);
5041141cc406Sopenharmony_ci    SSS_ADPTIME(pos, md->status.adptime);
5042141cc406Sopenharmony_ci    SSS_LENSSTATUS(pos, md->status.lensstatus);
5043141cc406Sopenharmony_ci    SSS_ALOFF(pos, md->status.aloff);
5044141cc406Sopenharmony_ci    SSS_TIMEREMAIN(pos, md->status.timeremain);
5045141cc406Sopenharmony_ci    SSS_TMACNT(pos, md->status.tmacnt);
5046141cc406Sopenharmony_ci    SSS_PAPER(pos, md->status.paper);
5047141cc406Sopenharmony_ci    SSS_ADFCNT(pos, md->status.adfcnt);
5048141cc406Sopenharmony_ci    SSS_CURRENTMODE(pos, md->status.currentmode);
5049141cc406Sopenharmony_ci    SSS_BUTTONCOUNT(pos, md->status.buttoncount);
5050141cc406Sopenharmony_ci
5051141cc406Sopenharmony_ci    if ( md_dump >= 2)
5052141cc406Sopenharmony_ci      {
5053141cc406Sopenharmony_ci        dump_area2(cmd, SSS_CMD_L, "sendsystemstatus");
5054141cc406Sopenharmony_ci        dump_area2(cmd + SSS_CMD_L, SSS_DATA_L, "sendsystemstatusdata");
5055141cc406Sopenharmony_ci      }
5056141cc406Sopenharmony_ci
5057141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, cmd, sizeof(cmd), NULL, 0);
5058141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5059141cc406Sopenharmony_ci        DBG(1, "scsi_send_system_status: '%s'\n", sane_strstatus(status));
5060141cc406Sopenharmony_ci
5061141cc406Sopenharmony_ci    if ( fd == -1 )
5062141cc406Sopenharmony_ci        sanei_scsi_close(sfd);
5063141cc406Sopenharmony_ci    return status;
5064141cc406Sopenharmony_ci}
5065141cc406Sopenharmony_ci
5066141cc406Sopenharmony_ci
5067141cc406Sopenharmony_ci/*---------- scsi_sense_handler() --------------------------------------------*/
5068141cc406Sopenharmony_ci/* rewritten 19.12.2001 for better SANE_STATUS return codes */
5069141cc406Sopenharmony_ci
5070141cc406Sopenharmony_cistatic SANE_Status
5071141cc406Sopenharmony_ciscsi_sense_handler (int fd, u_char *sense, void *arg)
5072141cc406Sopenharmony_ci{
5073141cc406Sopenharmony_ci    int as_info_length;
5074141cc406Sopenharmony_ci    uint8_t sense_key;
5075141cc406Sopenharmony_ci    uint8_t asc;
5076141cc406Sopenharmony_ci    uint8_t ascq;
5077141cc406Sopenharmony_ci
5078141cc406Sopenharmony_ci
5079141cc406Sopenharmony_ci    DBG(30, "scsi_sense_handler: fd=%d, sense=%p arg=%p\n",
5080141cc406Sopenharmony_ci             fd, (void *) sense, arg);
5081141cc406Sopenharmony_ci
5082141cc406Sopenharmony_ci    dump_area(sense, RQS_LENGTH(sense), "SenseBuffer");
5083141cc406Sopenharmony_ci
5084141cc406Sopenharmony_ci    sense_key = RQS_SENSEKEY(sense);
5085141cc406Sopenharmony_ci    asc = RQS_ASC(sense);
5086141cc406Sopenharmony_ci    ascq = RQS_ASCQ(sense);
5087141cc406Sopenharmony_ci
5088141cc406Sopenharmony_ci    DBG(5, "scsi_sense_handler: SENSE KEY (0x%02x), "
5089141cc406Sopenharmony_ci           "ASC (0x%02x), ASCQ (0x%02x)\n", sense_key, asc, ascq);
5090141cc406Sopenharmony_ci
5091141cc406Sopenharmony_ci    if ( (as_info_length = RQS_ASINFOLENGTH(sense)) > 0 )
5092141cc406Sopenharmony_ci        DBG(5,"scsi_sense_handler: info: '%*s'\n",
5093141cc406Sopenharmony_ci                as_info_length, RQS_ASINFO(sense));
5094141cc406Sopenharmony_ci
5095141cc406Sopenharmony_ci    switch ( sense_key )
5096141cc406Sopenharmony_ci      {
5097141cc406Sopenharmony_ci        case RQS_SENSEKEY_NOSENSE:
5098141cc406Sopenharmony_ci          return SANE_STATUS_GOOD;
5099141cc406Sopenharmony_ci
5100141cc406Sopenharmony_ci        case RQS_SENSEKEY_HWERR:
5101141cc406Sopenharmony_ci        case RQS_SENSEKEY_ILLEGAL:
5102141cc406Sopenharmony_ci        case RQS_SENSEKEY_VENDOR:
5103141cc406Sopenharmony_ci          if ( asc == 0x4a && ascq == 0x00 )
5104141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Command phase error\n");
5105141cc406Sopenharmony_ci          else if ( asc == 0x2c && ascq == 0x00 )
5106141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Command sequence error\n");
5107141cc406Sopenharmony_ci          else if ( asc == 0x4b && ascq == 0x00 )
5108141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Data phase error\n");
5109141cc406Sopenharmony_ci          else if ( asc == 0x40 )
5110141cc406Sopenharmony_ci            {
5111141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Hardware diagnostic failure:\n");
5112141cc406Sopenharmony_ci              switch ( ascq )
5113141cc406Sopenharmony_ci                {
5114141cc406Sopenharmony_ci                  case RQS_ASCQ_CPUERR:
5115141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: CPU error\n");
5116141cc406Sopenharmony_ci                    break;
5117141cc406Sopenharmony_ci                  case RQS_ASCQ_SRAMERR:
5118141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: SRAM error\n");
5119141cc406Sopenharmony_ci                    break;
5120141cc406Sopenharmony_ci                  case RQS_ASCQ_DRAMERR:
5121141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: DRAM error\n");
5122141cc406Sopenharmony_ci                    break;
5123141cc406Sopenharmony_ci                  case RQS_ASCQ_DCOFF:
5124141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: DC Offset error\n");
5125141cc406Sopenharmony_ci                    break;
5126141cc406Sopenharmony_ci                  case RQS_ASCQ_GAIN:
5127141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: Gain error\n");
5128141cc406Sopenharmony_ci                    break;
5129141cc406Sopenharmony_ci                  case RQS_ASCQ_POS:
5130141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: Positioning error\n");
5131141cc406Sopenharmony_ci                    break;
5132141cc406Sopenharmony_ci                  default:
5133141cc406Sopenharmony_ci                    DBG(5, "scsi_sense_handler: Unknown combination of ASC"
5134141cc406Sopenharmony_ci                           " (0x%02x) and ASCQ (0x%02x)\n", asc, ascq);
5135141cc406Sopenharmony_ci                    break;
5136141cc406Sopenharmony_ci                }
5137141cc406Sopenharmony_ci            }
5138141cc406Sopenharmony_ci          else if ( asc == 0x00  && ascq == 0x05)
5139141cc406Sopenharmony_ci            {
5140141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: End of data detected\n");
5141141cc406Sopenharmony_ci              return SANE_STATUS_EOF;
5142141cc406Sopenharmony_ci            }
5143141cc406Sopenharmony_ci          else if ( asc == 0x3d  && ascq == 0x00)
5144141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Invalid bit in IDENTIFY\n");
5145141cc406Sopenharmony_ci          else if ( asc == 0x2c && ascq == 0x02 )
5146141cc406Sopenharmony_ci/* Ok */      DBG(5, "scsi_sense_handler: Invalid comb. of windows specified\n");
5147141cc406Sopenharmony_ci          else if ( asc == 0x20 && ascq == 0x00 )
5148141cc406Sopenharmony_ci/* Ok */      DBG(5, "scsi_sense_handler: Invalid command opcode\n");
5149141cc406Sopenharmony_ci          else if ( asc == 0x24 && ascq == 0x00 )
5150141cc406Sopenharmony_ci/* Ok */      DBG(5, "scsi_sense_handler: Invalid field in CDB\n");
5151141cc406Sopenharmony_ci          else if ( asc == 0x26 && ascq == 0x00 )
5152141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Invalid field in the param list\n");
5153141cc406Sopenharmony_ci          else if ( asc == 0x49 && ascq == 0x00 )
5154141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Invalid message error\n");
5155141cc406Sopenharmony_ci          else if ( asc == 0x60 && ascq == 0x00 )
5156141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Lamp failure\n");
5157141cc406Sopenharmony_ci          else if ( asc == 0x25 && ascq == 0x00 )
5158141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Unsupported logic. unit\n");
5159141cc406Sopenharmony_ci          else if ( asc == 0x53 && ascq == 0x00 )
5160141cc406Sopenharmony_ci            {
5161141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: ADF paper jam or no paper\n");
5162141cc406Sopenharmony_ci              return SANE_STATUS_NO_DOCS;
5163141cc406Sopenharmony_ci            }
5164141cc406Sopenharmony_ci          else if ( asc == 0x54 && ascq == 0x00 )
5165141cc406Sopenharmony_ci            {
5166141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Media bumping\n");
5167141cc406Sopenharmony_ci              return SANE_STATUS_JAMMED; /* Don't know if this is right! */
5168141cc406Sopenharmony_ci            }
5169141cc406Sopenharmony_ci          else if ( asc == 0x55 && ascq == 0x00 )
5170141cc406Sopenharmony_ci            {
5171141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Scan Job stopped or cancelled\n");
5172141cc406Sopenharmony_ci              return SANE_STATUS_CANCELLED;
5173141cc406Sopenharmony_ci            }
5174141cc406Sopenharmony_ci          else if ( asc == 0x3a && ascq == 0x00 )
5175141cc406Sopenharmony_ci            {
5176141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Media (ADF or TMA) not available\n");
5177141cc406Sopenharmony_ci              return SANE_STATUS_NO_DOCS;
5178141cc406Sopenharmony_ci            }
5179141cc406Sopenharmony_ci          else if ( asc == 0x3a && ascq == 0x01 )
5180141cc406Sopenharmony_ci            {
5181141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Door is not closed\n");
5182141cc406Sopenharmony_ci              return SANE_STATUS_COVER_OPEN;
5183141cc406Sopenharmony_ci            }
5184141cc406Sopenharmony_ci          else if ( asc == 0x3a && ascq == 0x02 )
5185141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Door is not opened\n");
5186141cc406Sopenharmony_ci          else if ( asc == 0x00 && ascq == 0x00 )
5187141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler:  No additional sense information\n");
5188141cc406Sopenharmony_ci/* Ok */  else if ( asc == 0x1a && ascq == 0x00 )
5189141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Parameter list length error\n");
5190141cc406Sopenharmony_ci          else if ( asc == 0x26 && ascq == 0x02 )
5191141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Parameter value invalid\n");
5192141cc406Sopenharmony_ci          else if ( asc == 0x03 && ascq == 0x00 )
5193141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Peripheral device write fault - "
5194141cc406Sopenharmony_ci                     "Firmware Download Error\n");
5195141cc406Sopenharmony_ci          else if ( asc == 0x2c && ascq == 0x01 )
5196141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Too many windows specified\n");
5197141cc406Sopenharmony_ci          else if ( asc == 0x80 && ascq == 0x00 )
5198141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Target abort scan\n");
5199141cc406Sopenharmony_ci          else if ( asc == 0x96 && ascq == 0x08 )
5200141cc406Sopenharmony_ci            {
5201141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Firewire Device busy\n");
5202141cc406Sopenharmony_ci              return SANE_STATUS_DEVICE_BUSY;
5203141cc406Sopenharmony_ci            }
5204141cc406Sopenharmony_ci          else
5205141cc406Sopenharmony_ci              DBG(5, "scsi_sense_handler: Unknown combination of SENSE KEY "
5206141cc406Sopenharmony_ci                     "(0x%02x), ASC (0x%02x) and ASCQ (0x%02x)\n",
5207141cc406Sopenharmony_ci                      sense_key, asc, ascq);
5208141cc406Sopenharmony_ci
5209141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
5210141cc406Sopenharmony_ci
5211141cc406Sopenharmony_ci        default:
5212141cc406Sopenharmony_ci           DBG(5, "scsi_sense_handler: Unknown sense key (0x%02x)\n",
5213141cc406Sopenharmony_ci                   sense_key);
5214141cc406Sopenharmony_ci           return SANE_STATUS_IO_ERROR;
5215141cc406Sopenharmony_ci    }
5216141cc406Sopenharmony_ci}
5217141cc406Sopenharmony_ci
5218141cc406Sopenharmony_ci
5219141cc406Sopenharmony_ci/*---------- scsi_test_unit_ready() ------------------------------------------*/
5220141cc406Sopenharmony_ci
5221141cc406Sopenharmony_cistatic SANE_Status
5222141cc406Sopenharmony_ciscsi_test_unit_ready(Microtek2_Device *md)
5223141cc406Sopenharmony_ci{
5224141cc406Sopenharmony_ci    SANE_Status status;
5225141cc406Sopenharmony_ci    uint8_t tur[TUR_CMD_L];
5226141cc406Sopenharmony_ci    int sfd;
5227141cc406Sopenharmony_ci
5228141cc406Sopenharmony_ci
5229141cc406Sopenharmony_ci    DBG(30, "scsi_test_unit_ready: md=%s\n", md->name);
5230141cc406Sopenharmony_ci
5231141cc406Sopenharmony_ci    TUR_CMD(tur);
5232141cc406Sopenharmony_ci    status = sanei_scsi_open(md->name, &sfd, scsi_sense_handler, 0);
5233141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5234141cc406Sopenharmony_ci      {
5235141cc406Sopenharmony_ci	DBG(1, "scsi_test_unit_ready: open '%s'\n", sane_strstatus(status));
5236141cc406Sopenharmony_ci	return status;
5237141cc406Sopenharmony_ci      }
5238141cc406Sopenharmony_ci
5239141cc406Sopenharmony_ci    if ( md_dump >= 2 )
5240141cc406Sopenharmony_ci        dump_area2(tur, sizeof(tur), "testunitready");
5241141cc406Sopenharmony_ci
5242141cc406Sopenharmony_ci    status = sanei_scsi_cmd(sfd, tur, sizeof(tur), NULL, 0);
5243141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5244141cc406Sopenharmony_ci        DBG(1, "scsi_test_unit_ready: cmd '%s'\n", sane_strstatus(status));
5245141cc406Sopenharmony_ci
5246141cc406Sopenharmony_ci    sanei_scsi_close(sfd);
5247141cc406Sopenharmony_ci    return status;
5248141cc406Sopenharmony_ci}
5249141cc406Sopenharmony_ci
5250141cc406Sopenharmony_ci
5251141cc406Sopenharmony_ci/*---------- sane_start() ----------------------------------------------------*/
5252141cc406Sopenharmony_ci
5253141cc406Sopenharmony_ciSANE_Status
5254141cc406Sopenharmony_cisane_start(SANE_Handle handle)
5255141cc406Sopenharmony_ci{
5256141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
5257141cc406Sopenharmony_ci    Microtek2_Scanner *ms = handle;
5258141cc406Sopenharmony_ci    Microtek2_Device *md;
5259141cc406Sopenharmony_ci    Microtek2_Info *mi;
5260141cc406Sopenharmony_ci    uint8_t *pos;
5261141cc406Sopenharmony_ci    int color, rc, retry;
5262141cc406Sopenharmony_ci
5263141cc406Sopenharmony_ci    DBG(30, "sane_start: handle=0x%p\n", handle);
5264141cc406Sopenharmony_ci
5265141cc406Sopenharmony_ci    md = ms->dev;
5266141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
5267141cc406Sopenharmony_ci    ms->n_control_bytes = md->n_control_bytes;
5268141cc406Sopenharmony_ci
5269141cc406Sopenharmony_ci    if ( md->model_flags & MD_READ_CONTROL_BIT )
5270141cc406Sopenharmony_ci      {
5271141cc406Sopenharmony_ci        if (ms->control_bytes) free((void *)ms->control_bytes);
5272141cc406Sopenharmony_ci        ms->control_bytes = (uint8_t *) malloc(ms->n_control_bytes);
5273141cc406Sopenharmony_ci        DBG(100, "sane_start: ms->control_bytes=%p, malloc'd %lu bytes\n",
5274141cc406Sopenharmony_ci                  (void *) ms->control_bytes, (u_long) ms->n_control_bytes);
5275141cc406Sopenharmony_ci        if ( ms->control_bytes == NULL )
5276141cc406Sopenharmony_ci          {
5277141cc406Sopenharmony_ci            DBG(1, "sane_start: malloc() for control bits failed\n");
5278141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
5279141cc406Sopenharmony_ci            goto cleanup;
5280141cc406Sopenharmony_ci          }
5281141cc406Sopenharmony_ci      }
5282141cc406Sopenharmony_ci
5283141cc406Sopenharmony_ci    if (ms->sfd < 0) /* first or only pass of this scan */
5284141cc406Sopenharmony_ci      {
5285141cc406Sopenharmony_ci        /* open device */
5286141cc406Sopenharmony_ci        for ( retry = 0; retry < 10; retry++ )
5287141cc406Sopenharmony_ci	  {
5288141cc406Sopenharmony_ci            status = sanei_scsi_open (md->sane.name, &ms->sfd,
5289141cc406Sopenharmony_ci                                      scsi_sense_handler, 0);
5290141cc406Sopenharmony_ci            if ( status != SANE_STATUS_DEVICE_BUSY )
5291141cc406Sopenharmony_ci	      break;
5292141cc406Sopenharmony_ci            DBG(30, "sane_start: Scanner busy, trying again\n");
5293141cc406Sopenharmony_ci            sleep(1);
5294141cc406Sopenharmony_ci	  }
5295141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5296141cc406Sopenharmony_ci          {
5297141cc406Sopenharmony_ci            DBG(1, "sane_start: scsi_open: '%s'\n", sane_strstatus(status));
5298141cc406Sopenharmony_ci            goto cleanup;
5299141cc406Sopenharmony_ci          }
5300141cc406Sopenharmony_ci
5301141cc406Sopenharmony_ci        status = scsi_read_system_status(md, ms->sfd);
5302141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5303141cc406Sopenharmony_ci            goto cleanup;
5304141cc406Sopenharmony_ci
5305141cc406Sopenharmony_ci        if ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
5306141cc406Sopenharmony_ci            DBG(30, "sane_start: backend calibration on\n");
5307141cc406Sopenharmony_ci        else
5308141cc406Sopenharmony_ci            DBG(30, "sane_start: backend calibration off\n");
5309141cc406Sopenharmony_ci
5310141cc406Sopenharmony_ci        if ( ( ms->val[OPT_CALIB_BACKEND].w == SANE_TRUE )
5311141cc406Sopenharmony_ci             && !( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING ) )
5312141cc406Sopenharmony_ci          {
5313141cc406Sopenharmony_ci	    /* Read shading only once - possible with CIS scanners */
5314141cc406Sopenharmony_ci	    /* assuming only CIS scanners use Controlbits */
5315141cc406Sopenharmony_ci	    if ( ( md->shading_table_w == NULL )
5316141cc406Sopenharmony_ci                 || !( md->model_flags & MD_READ_CONTROL_BIT ) )
5317141cc406Sopenharmony_ci              {
5318141cc406Sopenharmony_ci		status = get_scan_parameters(ms);
5319141cc406Sopenharmony_ci                if ( status != SANE_STATUS_GOOD )
5320141cc406Sopenharmony_ci                        goto cleanup;
5321141cc406Sopenharmony_ci
5322141cc406Sopenharmony_ci                status = read_shading_image(ms);
5323141cc406Sopenharmony_ci                if ( status != SANE_STATUS_GOOD )
5324141cc406Sopenharmony_ci                        goto cleanup;
5325141cc406Sopenharmony_ci              }
5326141cc406Sopenharmony_ci          }
5327141cc406Sopenharmony_ci
5328141cc406Sopenharmony_ci	status = get_scan_parameters(ms);
5329141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5330141cc406Sopenharmony_ci            goto cleanup;
5331141cc406Sopenharmony_ci
5332141cc406Sopenharmony_ci        status = scsi_read_system_status(md, ms->sfd);
5333141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5334141cc406Sopenharmony_ci            goto cleanup;
5335141cc406Sopenharmony_ci
5336141cc406Sopenharmony_ci        md->status.aloff |= 128;
5337141cc406Sopenharmony_ci        md->status.timeremain = 10;
5338141cc406Sopenharmony_ci
5339141cc406Sopenharmony_ci        if ( ms->scan_source == MS_SOURCE_FLATBED
5340141cc406Sopenharmony_ci             || ms->scan_source == MS_SOURCE_ADF )
5341141cc406Sopenharmony_ci          {
5342141cc406Sopenharmony_ci            md->status.flamp |= MD_FLAMP_ON;
5343141cc406Sopenharmony_ci            md->status.tlamp &= ~MD_TLAMP_ON;
5344141cc406Sopenharmony_ci          }
5345141cc406Sopenharmony_ci        else
5346141cc406Sopenharmony_ci          {
5347141cc406Sopenharmony_ci            md->status.flamp &= ~MD_FLAMP_ON;
5348141cc406Sopenharmony_ci            md->status.tlamp |= MD_TLAMP_ON;
5349141cc406Sopenharmony_ci          }
5350141cc406Sopenharmony_ci
5351141cc406Sopenharmony_ci        if ( ms->lightlid35 )
5352141cc406Sopenharmony_ci          {
5353141cc406Sopenharmony_ci            md->status.flamp &= ~MD_FLAMP_ON;
5354141cc406Sopenharmony_ci/*            md->status.tlamp |= MD_TLAMP_ON;*/
5355141cc406Sopenharmony_ci/* with this line on some scanners (X6, 0x91) the Flamp goes on  */
5356141cc406Sopenharmony_ci          }
5357141cc406Sopenharmony_ci
5358141cc406Sopenharmony_ci        if ( ms->no_backtracking )
5359141cc406Sopenharmony_ci            md->status.ntrack |= MD_NTRACK_ON;
5360141cc406Sopenharmony_ci        else
5361141cc406Sopenharmony_ci            md->status.ntrack &= ~MD_NTRACK_ON;
5362141cc406Sopenharmony_ci
5363141cc406Sopenharmony_ci        status = scsi_send_system_status(md, ms->sfd);
5364141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5365141cc406Sopenharmony_ci            goto cleanup;
5366141cc406Sopenharmony_ci
5367141cc406Sopenharmony_ci        /* calculate gamma: we assume, that the gamma values are transferred */
5368141cc406Sopenharmony_ci        /* with one send gamma command, even if it is a 3 pass scanner */
5369141cc406Sopenharmony_ci        if ( md->model_flags & MD_NO_GAMMA )
5370141cc406Sopenharmony_ci          {
5371141cc406Sopenharmony_ci            ms->lut_size = (int) pow(2.0, (double) ms->depth);
5372141cc406Sopenharmony_ci            ms->lut_entry_size = ms->depth > 8 ? 2 : 1;
5373141cc406Sopenharmony_ci          }
5374141cc406Sopenharmony_ci        else
5375141cc406Sopenharmony_ci          {
5376141cc406Sopenharmony_ci            get_lut_size(mi, &ms->lut_size, &ms->lut_entry_size);
5377141cc406Sopenharmony_ci          }
5378141cc406Sopenharmony_ci        ms->lut_size_bytes = ms->lut_size * ms->lut_entry_size;
5379141cc406Sopenharmony_ci        ms->word = (ms->lut_entry_size == 2);
5380141cc406Sopenharmony_ci
5381141cc406Sopenharmony_ci        ms->gamma_table = (uint8_t *) malloc(3 * ms->lut_size_bytes );
5382141cc406Sopenharmony_ci        DBG(100, "sane_start: ms->gamma_table=%p, malloc'd %d bytes\n",
5383141cc406Sopenharmony_ci                  (void *) ms->gamma_table, 3 * ms->lut_size_bytes);
5384141cc406Sopenharmony_ci        if ( ms->gamma_table == NULL )
5385141cc406Sopenharmony_ci          {
5386141cc406Sopenharmony_ci            DBG(1, "sane_start: malloc for gammatable failed\n");
5387141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
5388141cc406Sopenharmony_ci            goto cleanup;
5389141cc406Sopenharmony_ci          }
5390141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
5391141cc406Sopenharmony_ci          {
5392141cc406Sopenharmony_ci            pos = ms->gamma_table + color * ms->lut_size_bytes;
5393141cc406Sopenharmony_ci            calculate_gamma(ms, pos, color, ms->gamma_mode);
5394141cc406Sopenharmony_ci          }
5395141cc406Sopenharmony_ci
5396141cc406Sopenharmony_ci        /* Some models ignore the settings for the exposure time, */
5397141cc406Sopenharmony_ci        /* so we must do it ourselves. Apparently this seems to be */
5398141cc406Sopenharmony_ci        /* the case for all models that have the chunky data format */
5399141cc406Sopenharmony_ci
5400141cc406Sopenharmony_ci        if ( mi->data_format == MI_DATAFMT_CHUNKY )
5401141cc406Sopenharmony_ci            set_exposure(ms);
5402141cc406Sopenharmony_ci
5403141cc406Sopenharmony_ci        if ( ! (md->model_flags & MD_NO_GAMMA) )
5404141cc406Sopenharmony_ci          {
5405141cc406Sopenharmony_ci            status = scsi_send_gamma(ms);
5406141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
5407141cc406Sopenharmony_ci                goto cleanup;
5408141cc406Sopenharmony_ci          }
5409141cc406Sopenharmony_ci
5410141cc406Sopenharmony_ci        status = scsi_set_window(ms, 1);
5411141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5412141cc406Sopenharmony_ci            goto cleanup;
5413141cc406Sopenharmony_ci
5414141cc406Sopenharmony_ci        ms->scanning = SANE_TRUE;
5415141cc406Sopenharmony_ci        ms->cancelled = SANE_FALSE;
5416141cc406Sopenharmony_ci      }
5417141cc406Sopenharmony_ci
5418141cc406Sopenharmony_ci    ++ms->current_pass;
5419141cc406Sopenharmony_ci
5420141cc406Sopenharmony_ci    status = scsi_read_image_info(ms);
5421141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5422141cc406Sopenharmony_ci        goto cleanup;
5423141cc406Sopenharmony_ci
5424141cc406Sopenharmony_ci    status = prepare_buffers(ms);
5425141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5426141cc406Sopenharmony_ci        goto cleanup;
5427141cc406Sopenharmony_ci
5428141cc406Sopenharmony_ci    status = calculate_sane_params(ms);
5429141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
5430141cc406Sopenharmony_ci        goto cleanup;
5431141cc406Sopenharmony_ci
5432141cc406Sopenharmony_ci    if ( !( md->model_flags & MD_NO_RIS_COMMAND ) )
5433141cc406Sopenharmony_ci      {
5434141cc406Sopenharmony_ci        /* !!FIXME!! - hack for C6USB because RIS over USB doesn't wait until */
5435141cc406Sopenharmony_ci        /* scanner ready */
5436141cc406Sopenharmony_ci        if (mi->model_code == 0x9a)
5437141cc406Sopenharmony_ci            sleep(2);
5438141cc406Sopenharmony_ci
5439141cc406Sopenharmony_ci        status = scsi_wait_for_image(ms);
5440141cc406Sopenharmony_ci        if ( status  != SANE_STATUS_GOOD )
5441141cc406Sopenharmony_ci            goto cleanup;
5442141cc406Sopenharmony_ci      }
5443141cc406Sopenharmony_ci
5444141cc406Sopenharmony_ci    if ( ms->calib_backend
5445141cc406Sopenharmony_ci         && ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5446141cc406Sopenharmony_ci         && ( ( md->shading_table_w == NULL )
5447141cc406Sopenharmony_ci              || ( ms->mode != md->shading_table_contents )
5448141cc406Sopenharmony_ci            )
5449141cc406Sopenharmony_ci       )
5450141cc406Sopenharmony_ci      {
5451141cc406Sopenharmony_ci        status = read_cx_shading(ms);
5452141cc406Sopenharmony_ci        if ( status  != SANE_STATUS_GOOD )
5453141cc406Sopenharmony_ci	  goto cleanup;
5454141cc406Sopenharmony_ci      }
5455141cc406Sopenharmony_ci
5456141cc406Sopenharmony_ci    if ( ms->lightlid35 )
5457141cc406Sopenharmony_ci    /* hopefully this leads to a switched off flatbed lamp with lightlid */
5458141cc406Sopenharmony_ci      {
5459141cc406Sopenharmony_ci        status = scsi_read_system_status(md, ms->sfd);
5460141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5461141cc406Sopenharmony_ci            goto cleanup;
5462141cc406Sopenharmony_ci
5463141cc406Sopenharmony_ci        md->status.flamp &= ~MD_FLAMP_ON;
5464141cc406Sopenharmony_ci        md->status.tlamp &= ~MD_TLAMP_ON;
5465141cc406Sopenharmony_ci
5466141cc406Sopenharmony_ci        status = scsi_send_system_status(md, ms->sfd);
5467141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5468141cc406Sopenharmony_ci            goto cleanup;
5469141cc406Sopenharmony_ci      }
5470141cc406Sopenharmony_ci
5471141cc406Sopenharmony_ci    if ( md->model_flags & MD_READ_CONTROL_BIT )
5472141cc406Sopenharmony_ci      {
5473141cc406Sopenharmony_ci        status = scsi_read_control_bits(ms);
5474141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
5475141cc406Sopenharmony_ci            goto cleanup;
5476141cc406Sopenharmony_ci
5477141cc406Sopenharmony_ci        if ( ms->calib_backend )
5478141cc406Sopenharmony_ci          {
5479141cc406Sopenharmony_ci            status = condense_shading(ms);
5480141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
5481141cc406Sopenharmony_ci               goto cleanup;
5482141cc406Sopenharmony_ci          }
5483141cc406Sopenharmony_ci      }
5484141cc406Sopenharmony_ci
5485141cc406Sopenharmony_ci    /* open a pipe and fork a child process, that actually reads the data */
5486141cc406Sopenharmony_ci    rc = pipe(ms->fd);
5487141cc406Sopenharmony_ci    if ( rc == -1 )
5488141cc406Sopenharmony_ci      {
5489141cc406Sopenharmony_ci        DBG(1, "sane_start: pipe failed\n");
5490141cc406Sopenharmony_ci        status = SANE_STATUS_IO_ERROR;
5491141cc406Sopenharmony_ci        goto cleanup;
5492141cc406Sopenharmony_ci      }
5493141cc406Sopenharmony_ci
5494141cc406Sopenharmony_ci    /* create reader routine as new thread or process */
5495141cc406Sopenharmony_ci    ms->pid = sanei_thread_begin( reader_process,(void*) ms);
5496141cc406Sopenharmony_ci
5497141cc406Sopenharmony_ci    if ( !sanei_thread_is_valid (ms->pid) )
5498141cc406Sopenharmony_ci      {
5499141cc406Sopenharmony_ci        DBG(1, "sane_start: fork failed\n");
5500141cc406Sopenharmony_ci        status = SANE_STATUS_IO_ERROR;
5501141cc406Sopenharmony_ci        goto cleanup;
5502141cc406Sopenharmony_ci      }
5503141cc406Sopenharmony_ci
5504141cc406Sopenharmony_ci    if (sanei_thread_is_forked()) close(ms->fd[1]);
5505141cc406Sopenharmony_ci
5506141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
5507141cc406Sopenharmony_ci
5508141cc406Sopenharmony_cicleanup:
5509141cc406Sopenharmony_ci    cleanup_scanner(ms);
5510141cc406Sopenharmony_ci    return status;
5511141cc406Sopenharmony_ci}
5512141cc406Sopenharmony_ci
5513141cc406Sopenharmony_ci/*---------- prepare_buffers -------------------------------------------------*/
5514141cc406Sopenharmony_ci
5515141cc406Sopenharmony_cistatic SANE_Status
5516141cc406Sopenharmony_ciprepare_buffers(Microtek2_Scanner *ms)
5517141cc406Sopenharmony_ci{
5518141cc406Sopenharmony_ci    SANE_Status status;
5519141cc406Sopenharmony_ci    Microtek2_Device *md;
5520141cc406Sopenharmony_ci    Microtek2_Info *mi;
5521141cc406Sopenharmony_ci    uint32_t strip_lines;
5522141cc406Sopenharmony_ci    int i;
5523141cc406Sopenharmony_ci
5524141cc406Sopenharmony_ci    status = SANE_STATUS_GOOD;
5525141cc406Sopenharmony_ci    DBG(30, "prepare_buffers: ms=0x%p\n", (void *) ms);
5526141cc406Sopenharmony_ci
5527141cc406Sopenharmony_ci    md = ms->dev;
5528141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
5529141cc406Sopenharmony_ci
5530141cc406Sopenharmony_ci    /* calculate maximum number of lines to read */
5531141cc406Sopenharmony_ci    strip_lines = (int) ((double) ms->y_resolution_dpi * md->opts.strip_height);
5532141cc406Sopenharmony_ci    if ( strip_lines == 0 )
5533141cc406Sopenharmony_ci        strip_lines = 1;
5534141cc406Sopenharmony_ci
5535141cc406Sopenharmony_ci    /* calculate number of lines that fit into the source buffer */
5536141cc406Sopenharmony_ci#ifdef TESTBACKEND
5537141cc406Sopenharmony_ci    ms->src_max_lines = MIN( 5000000 / ms->bpl, strip_lines);
5538141cc406Sopenharmony_ci#else
5539141cc406Sopenharmony_ci    ms->src_max_lines = MIN( sanei_scsi_max_request_size / ms->bpl, strip_lines);
5540141cc406Sopenharmony_ci#endif
5541141cc406Sopenharmony_ci    if ( ms->src_max_lines == 0 )
5542141cc406Sopenharmony_ci      {
5543141cc406Sopenharmony_ci        DBG(1, "sane_start: Scan buffer too small\n");
5544141cc406Sopenharmony_ci        status = SANE_STATUS_IO_ERROR;
5545141cc406Sopenharmony_ci        goto cleanup;
5546141cc406Sopenharmony_ci      }
5547141cc406Sopenharmony_ci
5548141cc406Sopenharmony_ci    /* allocate buffers */
5549141cc406Sopenharmony_ci    ms->src_buffer_size = ms->src_max_lines * ms->bpl;
5550141cc406Sopenharmony_ci
5551141cc406Sopenharmony_ci    if ( ms->mode == MS_MODE_COLOR && mi->data_format == MI_DATAFMT_LPLSEGREG )
5552141cc406Sopenharmony_ci      {
5553141cc406Sopenharmony_ci        /* In this case the data is not necessarily in the order RGB */
5554141cc406Sopenharmony_ci        /* and there may be different numbers of read red, green and blue */
5555141cc406Sopenharmony_ci        /* segments. We allocate a second buffer to read new lines in */
5556141cc406Sopenharmony_ci        /* and hold undelivered pixels in the other buffer */
5557141cc406Sopenharmony_ci        int extra_buf_size;
5558141cc406Sopenharmony_ci
5559141cc406Sopenharmony_ci        extra_buf_size = 2 * ms->bpl * mi->ccd_gap
5560141cc406Sopenharmony_ci                         * (int) ceil( (double) mi->max_yresolution
5561141cc406Sopenharmony_ci                                      / (double) mi->opt_resolution);
5562141cc406Sopenharmony_ci        for ( i = 0; i < 2; i++ )
5563141cc406Sopenharmony_ci          {
5564141cc406Sopenharmony_ci            if ( ms->buf.src_buffer[i] )
5565141cc406Sopenharmony_ci                free((void *) ms->buf.src_buffer[i]);
5566141cc406Sopenharmony_ci            ms->buf.src_buffer[i] = (uint8_t *) malloc(ms->src_buffer_size
5567141cc406Sopenharmony_ci                                    + extra_buf_size);
5568141cc406Sopenharmony_ci            DBG(100, "prepare_buffers: ms->buf.src_buffer[%d]=%p,"
5569141cc406Sopenharmony_ci                     "malloc'd %d bytes\n", i, (void *) ms->buf.src_buffer[i],
5570141cc406Sopenharmony_ci                     ms->src_buffer_size + extra_buf_size);
5571141cc406Sopenharmony_ci            if ( ms->buf.src_buffer[i] == NULL )
5572141cc406Sopenharmony_ci              {
5573141cc406Sopenharmony_ci                DBG(1, "sane_start: malloc for scan buffer failed\n");
5574141cc406Sopenharmony_ci                status = SANE_STATUS_NO_MEM;
5575141cc406Sopenharmony_ci                goto cleanup;
5576141cc406Sopenharmony_ci              }
5577141cc406Sopenharmony_ci          }
5578141cc406Sopenharmony_ci        ms->buf.free_lines = ms->src_max_lines + extra_buf_size / ms->bpl;
5579141cc406Sopenharmony_ci        ms->buf.free_max_lines = ms->buf.free_lines;
5580141cc406Sopenharmony_ci        ms->buf.src_buf = ms->buf.src_buffer[0];
5581141cc406Sopenharmony_ci        ms->buf.current_src = 0;         /* index to current buffer */
5582141cc406Sopenharmony_ci      }
5583141cc406Sopenharmony_ci    else
5584141cc406Sopenharmony_ci      {
5585141cc406Sopenharmony_ci        if ( ms->buf.src_buf )
5586141cc406Sopenharmony_ci            free((void *) ms->buf.src_buf);
5587141cc406Sopenharmony_ci        ms->buf.src_buf = malloc(ms->src_buffer_size);
5588141cc406Sopenharmony_ci        DBG(100, "sane_start: ms->buf.src_buf=%p, malloc'd %d bytes\n",
5589141cc406Sopenharmony_ci                  (void *) ms->buf.src_buf, ms->src_buffer_size);
5590141cc406Sopenharmony_ci        if ( ms->buf.src_buf == NULL )
5591141cc406Sopenharmony_ci          {
5592141cc406Sopenharmony_ci            DBG(1, "sane_start: malloc for scan buffer failed\n");
5593141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
5594141cc406Sopenharmony_ci            goto cleanup;
5595141cc406Sopenharmony_ci          }
5596141cc406Sopenharmony_ci      }
5597141cc406Sopenharmony_ci
5598141cc406Sopenharmony_ci    for ( i = 0; i < 3; i++ )
5599141cc406Sopenharmony_ci      {
5600141cc406Sopenharmony_ci        ms->buf.current_pos[i] = ms->buf.src_buffer[0];
5601141cc406Sopenharmony_ci        ms->buf.planes[0][i] = 0;
5602141cc406Sopenharmony_ci        ms->buf.planes[1][i] = 0;
5603141cc406Sopenharmony_ci      }
5604141cc406Sopenharmony_ci
5605141cc406Sopenharmony_ci    /* allocate a temporary buffer for the data, if auto_adjust threshold */
5606141cc406Sopenharmony_ci    /* is selected. */
5607141cc406Sopenharmony_ci
5608141cc406Sopenharmony_ci    if ( ms->auto_adjust == 1 )
5609141cc406Sopenharmony_ci      {
5610141cc406Sopenharmony_ci        ms->temporary_buffer = (uint8_t *) malloc(ms->remaining_bytes);
5611141cc406Sopenharmony_ci        DBG(100, "sane_start: ms->temporary_buffer=%p, malloc'd %d bytes\n",
5612141cc406Sopenharmony_ci                  (void *) ms->temporary_buffer, ms->remaining_bytes);
5613141cc406Sopenharmony_ci        if ( ms->temporary_buffer == NULL )
5614141cc406Sopenharmony_ci          {
5615141cc406Sopenharmony_ci            DBG(1, "sane_start: malloc() for temporary buffer failed\n");
5616141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
5617141cc406Sopenharmony_ci            goto cleanup;
5618141cc406Sopenharmony_ci          }
5619141cc406Sopenharmony_ci      }
5620141cc406Sopenharmony_ci    else
5621141cc406Sopenharmony_ci        ms->temporary_buffer = NULL;
5622141cc406Sopenharmony_ci
5623141cc406Sopenharmony_ci    /* some data formats have additional information in a scan line, which */
5624141cc406Sopenharmony_ci    /* is not transferred to the frontend; real_bpl is the number of bytes */
5625141cc406Sopenharmony_ci    /* per line, that is copied into the frontend's buffer */
5626141cc406Sopenharmony_ci    ms->real_bpl = (uint32_t) ceil( ((double) ms->ppl *
5627141cc406Sopenharmony_ci                                      (double) ms->bits_per_pixel_out) / 8.0 );
5628141cc406Sopenharmony_ci    if ( mi->onepass && ms->mode == MS_MODE_COLOR )
5629141cc406Sopenharmony_ci        ms->real_bpl *= 3;
5630141cc406Sopenharmony_ci
5631141cc406Sopenharmony_ci    ms->real_remaining_bytes = ms->real_bpl * ms->src_remaining_lines;
5632141cc406Sopenharmony_ci
5633141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
5634141cc406Sopenharmony_ci
5635141cc406Sopenharmony_cicleanup:
5636141cc406Sopenharmony_ci    cleanup_scanner(ms);
5637141cc406Sopenharmony_ci    return status;
5638141cc406Sopenharmony_ci
5639141cc406Sopenharmony_ci}
5640141cc406Sopenharmony_cistatic void
5641141cc406Sopenharmony_ciwrite_shading_buf_pnm(Microtek2_Scanner *ms, uint32_t lines)
5642141cc406Sopenharmony_ci{
5643141cc406Sopenharmony_ci  FILE *outfile;
5644141cc406Sopenharmony_ci  uint16_t pixel, color, linenr, factor;
5645141cc406Sopenharmony_ci  unsigned char  img_val_out;
5646141cc406Sopenharmony_ci  float img_val = 0;
5647141cc406Sopenharmony_ci  Microtek2_Device *md;
5648141cc406Sopenharmony_ci  Microtek2_Info *mi;
5649141cc406Sopenharmony_ci
5650141cc406Sopenharmony_ci  md = ms->dev;
5651141cc406Sopenharmony_ci  mi = &md->info[md->scan_source];
5652141cc406Sopenharmony_ci
5653141cc406Sopenharmony_ci  if ( mi->depth & MI_HASDEPTH_16 )
5654141cc406Sopenharmony_ci      factor = 256;
5655141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_14 )
5656141cc406Sopenharmony_ci      factor = 64;
5657141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_12 )
5658141cc406Sopenharmony_ci      factor = 16;
5659141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_10 )
5660141cc406Sopenharmony_ci      factor = 4;
5661141cc406Sopenharmony_ci  else
5662141cc406Sopenharmony_ci      factor = 1;
5663141cc406Sopenharmony_ci  if ( md->model_flags & MD_16BIT_TRANSFER )
5664141cc406Sopenharmony_ci      factor = 256;
5665141cc406Sopenharmony_ci
5666141cc406Sopenharmony_ci  outfile = fopen("shading_buf_w.pnm", "w");
5667141cc406Sopenharmony_ci  fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n",
5668141cc406Sopenharmony_ci          mi->geo_width / mi->calib_divisor, lines);
5669141cc406Sopenharmony_ci  for ( linenr=0; linenr < lines; linenr++ )
5670141cc406Sopenharmony_ci    {
5671141cc406Sopenharmony_ci      if (mi->data_format == MI_DATAFMT_LPLSEGREG)
5672141cc406Sopenharmony_ci        {
5673141cc406Sopenharmony_ci	  DBG(1, "Output of shading buffer unsupported for"
5674141cc406Sopenharmony_ci                           "Segreg Data format\n");
5675141cc406Sopenharmony_ci          break;
5676141cc406Sopenharmony_ci        }
5677141cc406Sopenharmony_ci
5678141cc406Sopenharmony_ci      for ( pixel=0;
5679141cc406Sopenharmony_ci            pixel < (uint16_t) (mi->geo_width / mi->calib_divisor);
5680141cc406Sopenharmony_ci            pixel++)
5681141cc406Sopenharmony_ci        {
5682141cc406Sopenharmony_ci          for ( color=0; color < 3; color++ )
5683141cc406Sopenharmony_ci            {
5684141cc406Sopenharmony_ci              switch( mi->data_format )
5685141cc406Sopenharmony_ci                {
5686141cc406Sopenharmony_ci                  case MI_DATAFMT_LPLCONCAT:
5687141cc406Sopenharmony_ci                    if ( md->shading_depth > 8)
5688141cc406Sopenharmony_ci                      img_val = *((uint16_t *) ms->shading_image
5689141cc406Sopenharmony_ci                                 + linenr * ( ms->bpl / ms->lut_entry_size )
5690141cc406Sopenharmony_ci                                 + mi->color_sequence[color]
5691141cc406Sopenharmony_ci                                      * ( ms->bpl / ms->lut_entry_size / 3 )
5692141cc406Sopenharmony_ci                                 + pixel);
5693141cc406Sopenharmony_ci                    else
5694141cc406Sopenharmony_ci                      img_val = *((uint8_t *) ms->shading_image
5695141cc406Sopenharmony_ci                                 + linenr * ( ms->bpl / ms->lut_entry_size )
5696141cc406Sopenharmony_ci                                 + mi->color_sequence[color]
5697141cc406Sopenharmony_ci                                      * ( ms->bpl / ms->lut_entry_size / 3 )
5698141cc406Sopenharmony_ci                                 + pixel);
5699141cc406Sopenharmony_ci
5700141cc406Sopenharmony_ci                    break;
5701141cc406Sopenharmony_ci                  case MI_DATAFMT_CHUNKY:
5702141cc406Sopenharmony_ci                  case MI_DATAFMT_9800:
5703141cc406Sopenharmony_ci                    img_val = *((uint16_t *)ms->shading_image
5704141cc406Sopenharmony_ci                               + linenr * 3 * ( mi->geo_width
5705141cc406Sopenharmony_ci                                                / mi->calib_divisor )
5706141cc406Sopenharmony_ci                               + 3 * pixel
5707141cc406Sopenharmony_ci                               + mi->color_sequence[color]);
5708141cc406Sopenharmony_ci                    break;
5709141cc406Sopenharmony_ci                }
5710141cc406Sopenharmony_ci              img_val /= factor;
5711141cc406Sopenharmony_ci              img_val_out = (unsigned char)img_val;
5712141cc406Sopenharmony_ci              fputc(img_val_out, outfile);
5713141cc406Sopenharmony_ci            }
5714141cc406Sopenharmony_ci        }
5715141cc406Sopenharmony_ci    }
5716141cc406Sopenharmony_ci  fclose(outfile);
5717141cc406Sopenharmony_ci
5718141cc406Sopenharmony_ci  return;
5719141cc406Sopenharmony_ci}
5720141cc406Sopenharmony_ci
5721141cc406Sopenharmony_cistatic void
5722141cc406Sopenharmony_ciwrite_shading_pnm(Microtek2_Scanner *ms)
5723141cc406Sopenharmony_ci{
5724141cc406Sopenharmony_ci  FILE *outfile_w = NULL, *outfile_d = NULL;
5725141cc406Sopenharmony_ci  int pixel, color, line, offset, num_shading_pixels, output_height;
5726141cc406Sopenharmony_ci  uint16_t img_val, factor;
5727141cc406Sopenharmony_ci
5728141cc406Sopenharmony_ci  Microtek2_Device *md;
5729141cc406Sopenharmony_ci  Microtek2_Info *mi;
5730141cc406Sopenharmony_ci
5731141cc406Sopenharmony_ci  output_height = 180;
5732141cc406Sopenharmony_ci  md = ms->dev;
5733141cc406Sopenharmony_ci  mi = &md->info[md->scan_source];
5734141cc406Sopenharmony_ci
5735141cc406Sopenharmony_ci  DBG(30, "write_shading_pnm: ms=%p\n", (void *) ms);
5736141cc406Sopenharmony_ci
5737141cc406Sopenharmony_ci  if ( mi->depth & MI_HASDEPTH_16 )
5738141cc406Sopenharmony_ci      factor = 256;
5739141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_14 )
5740141cc406Sopenharmony_ci      factor = 64;
5741141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_12 )
5742141cc406Sopenharmony_ci      factor = 16;
5743141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_10 )
5744141cc406Sopenharmony_ci      factor = 4;
5745141cc406Sopenharmony_ci  else
5746141cc406Sopenharmony_ci      factor = 1;
5747141cc406Sopenharmony_ci  if ( md->model_flags & MD_16BIT_TRANSFER )
5748141cc406Sopenharmony_ci      factor = 256;
5749141cc406Sopenharmony_ci
5750141cc406Sopenharmony_ci  if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5751141cc406Sopenharmony_ci    num_shading_pixels = ms->n_control_bytes * 8;
5752141cc406Sopenharmony_ci  else
5753141cc406Sopenharmony_ci    num_shading_pixels = mi->geo_width / mi->calib_divisor;
5754141cc406Sopenharmony_ci  if ( md->shading_table_w != NULL )
5755141cc406Sopenharmony_ci    {
5756141cc406Sopenharmony_ci      outfile_w = fopen("microtek2_shading_w.pnm", "w");
5757141cc406Sopenharmony_ci      fprintf(outfile_w, "P6\n#imagedata\n%d %d\n255\n",
5758141cc406Sopenharmony_ci                      num_shading_pixels, output_height);
5759141cc406Sopenharmony_ci    }
5760141cc406Sopenharmony_ci  if ( md->shading_table_d != NULL )
5761141cc406Sopenharmony_ci    {
5762141cc406Sopenharmony_ci      outfile_d = fopen("microtek2_shading_d.pnm", "w");
5763141cc406Sopenharmony_ci      fprintf(outfile_d, "P6\n#imagedata\n%d %d\n255\n",
5764141cc406Sopenharmony_ci                      num_shading_pixels, output_height);
5765141cc406Sopenharmony_ci    }
5766141cc406Sopenharmony_ci  for ( line=0; line < output_height; ++line )
5767141cc406Sopenharmony_ci    {
5768141cc406Sopenharmony_ci      for ( pixel=0; pixel < num_shading_pixels ; ++pixel)
5769141cc406Sopenharmony_ci        {
5770141cc406Sopenharmony_ci          for ( color=0; color < 3; ++color )
5771141cc406Sopenharmony_ci            {
5772141cc406Sopenharmony_ci              offset = mi->color_sequence[color]
5773141cc406Sopenharmony_ci                        * num_shading_pixels
5774141cc406Sopenharmony_ci                        + pixel;
5775141cc406Sopenharmony_ci              if ( md->shading_table_w != NULL )
5776141cc406Sopenharmony_ci                {
5777141cc406Sopenharmony_ci                  if ( ms->lut_entry_size == 2 )
5778141cc406Sopenharmony_ci                    {
5779141cc406Sopenharmony_ci                      img_val = *((uint16_t *) md->shading_table_w + offset );
5780141cc406Sopenharmony_ci                      img_val /= factor;
5781141cc406Sopenharmony_ci                    }
5782141cc406Sopenharmony_ci                  else
5783141cc406Sopenharmony_ci                      img_val = *((uint8_t *) md->shading_table_w + offset );
5784141cc406Sopenharmony_ci                  fputc((unsigned char)img_val, outfile_w);
5785141cc406Sopenharmony_ci                }
5786141cc406Sopenharmony_ci
5787141cc406Sopenharmony_ci              if ( md->shading_table_d != NULL )
5788141cc406Sopenharmony_ci                {
5789141cc406Sopenharmony_ci                  if ( ms->lut_entry_size == 2 )
5790141cc406Sopenharmony_ci                    {
5791141cc406Sopenharmony_ci                      img_val = *((uint16_t *) md->shading_table_d + offset );
5792141cc406Sopenharmony_ci                      img_val /= factor;
5793141cc406Sopenharmony_ci                    }
5794141cc406Sopenharmony_ci                  else
5795141cc406Sopenharmony_ci                      img_val = *((uint8_t *) md->shading_table_d + offset );
5796141cc406Sopenharmony_ci                  fputc((unsigned char)img_val, outfile_d);
5797141cc406Sopenharmony_ci                }
5798141cc406Sopenharmony_ci            }
5799141cc406Sopenharmony_ci        }
5800141cc406Sopenharmony_ci    }
5801141cc406Sopenharmony_ci  if ( md->shading_table_w != NULL )
5802141cc406Sopenharmony_ci    fclose(outfile_w);
5803141cc406Sopenharmony_ci  if ( md->shading_table_d != NULL )
5804141cc406Sopenharmony_ci    fclose(outfile_d);
5805141cc406Sopenharmony_ci
5806141cc406Sopenharmony_ci  return;
5807141cc406Sopenharmony_ci}
5808141cc406Sopenharmony_ci
5809141cc406Sopenharmony_cistatic void
5810141cc406Sopenharmony_ciwrite_cshading_pnm(Microtek2_Scanner *ms)
5811141cc406Sopenharmony_ci{
5812141cc406Sopenharmony_ci  FILE *outfile;
5813141cc406Sopenharmony_ci  Microtek2_Device *md;
5814141cc406Sopenharmony_ci  Microtek2_Info *mi;
5815141cc406Sopenharmony_ci  int pixel, color, line, offset, img_val, img_height=30, factor;
5816141cc406Sopenharmony_ci
5817141cc406Sopenharmony_ci  md = ms->dev;
5818141cc406Sopenharmony_ci  mi = &md->info[md->scan_source];
5819141cc406Sopenharmony_ci
5820141cc406Sopenharmony_ci  if ( mi->depth & MI_HASDEPTH_16 )
5821141cc406Sopenharmony_ci      factor = 256;
5822141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_14 )
5823141cc406Sopenharmony_ci      factor = 64;
5824141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_12 )
5825141cc406Sopenharmony_ci      factor = 16;
5826141cc406Sopenharmony_ci  else if ( mi->depth & MI_HASDEPTH_10 )
5827141cc406Sopenharmony_ci      factor = 4;
5828141cc406Sopenharmony_ci  else
5829141cc406Sopenharmony_ci      factor = 1;
5830141cc406Sopenharmony_ci  if ( md->model_flags & MD_16BIT_TRANSFER )
5831141cc406Sopenharmony_ci      factor = 256;
5832141cc406Sopenharmony_ci
5833141cc406Sopenharmony_ci  outfile = fopen("microtek2_cshading_w.pnm", "w");
5834141cc406Sopenharmony_ci  if ( ms->mode == MS_MODE_COLOR )
5835141cc406Sopenharmony_ci    fprintf(outfile, "P6\n#imagedata\n%d %d\n255\n", ms->ppl, img_height);
5836141cc406Sopenharmony_ci  else
5837141cc406Sopenharmony_ci    fprintf(outfile, "P5\n#imagedata\n%d %d\n255\n", ms->ppl, img_height);
5838141cc406Sopenharmony_ci
5839141cc406Sopenharmony_ci  for ( line=0; line < img_height; ++line )
5840141cc406Sopenharmony_ci    {
5841141cc406Sopenharmony_ci      for ( pixel=0; pixel < (int)ms->ppl; ++pixel)
5842141cc406Sopenharmony_ci        {
5843141cc406Sopenharmony_ci          for ( color=0; color < 3; ++color )
5844141cc406Sopenharmony_ci            {
5845141cc406Sopenharmony_ci              offset = color * (int)ms->ppl + pixel;
5846141cc406Sopenharmony_ci              if ( ms->lut_entry_size == 1 )
5847141cc406Sopenharmony_ci                img_val = (int) *((uint8_t *)ms->condensed_shading_w + offset);
5848141cc406Sopenharmony_ci              else
5849141cc406Sopenharmony_ci                {
5850141cc406Sopenharmony_ci                  img_val = (int) *((uint16_t *)ms->condensed_shading_w
5851141cc406Sopenharmony_ci                                                 + offset);
5852141cc406Sopenharmony_ci                  img_val /= factor;
5853141cc406Sopenharmony_ci                }
5854141cc406Sopenharmony_ci              fputc((unsigned char)img_val, outfile);
5855141cc406Sopenharmony_ci              if ( ms->mode == MS_MODE_GRAY )
5856141cc406Sopenharmony_ci                break;
5857141cc406Sopenharmony_ci            }
5858141cc406Sopenharmony_ci        }
5859141cc406Sopenharmony_ci    }
5860141cc406Sopenharmony_ci  fclose(outfile);
5861141cc406Sopenharmony_ci
5862141cc406Sopenharmony_ci  return;
5863141cc406Sopenharmony_ci}
5864141cc406Sopenharmony_ci
5865141cc406Sopenharmony_ci
5866141cc406Sopenharmony_ci
5867141cc406Sopenharmony_ci/*---------- condense_shading() ----------------------------------------------*/
5868141cc406Sopenharmony_ci
5869141cc406Sopenharmony_cistatic SANE_Status
5870141cc406Sopenharmony_cicondense_shading(Microtek2_Scanner *ms)
5871141cc406Sopenharmony_ci{
5872141cc406Sopenharmony_ci    /* This function extracts the relevant shading pixels from */
5873141cc406Sopenharmony_ci    /* the shading image according to the 1's in the result of */
5874141cc406Sopenharmony_ci    /* 'read control bits', and stores them in a memory block. */
5875141cc406Sopenharmony_ci    /* We will then have as many shading pixels as there are */
5876141cc406Sopenharmony_ci    /* pixels per line. The order of the pixels in the condensed */
5877141cc406Sopenharmony_ci    /* shading data block will always be left to right. The color */
5878141cc406Sopenharmony_ci    /* sequence remains unchanged. */
5879141cc406Sopenharmony_ci
5880141cc406Sopenharmony_ci    Microtek2_Device *md;
5881141cc406Sopenharmony_ci    Microtek2_Info *mi;
5882141cc406Sopenharmony_ci    uint32_t byte;
5883141cc406Sopenharmony_ci    uint32_t cond_length;       /* bytes per condensed shading line */
5884141cc406Sopenharmony_ci    int color, count, lfd_bit;
5885141cc406Sopenharmony_ci    int shad_bplc, shad_pixels;  /* bytes per line & color in shading image */
5886141cc406Sopenharmony_ci    int bit, flag;
5887141cc406Sopenharmony_ci    uint32_t sh_offset, csh_offset;
5888141cc406Sopenharmony_ci    int gray_filter_color = 1; /* which color of the shading is taken for gray*/
5889141cc406Sopenharmony_ci
5890141cc406Sopenharmony_ci    md = ms->dev;
5891141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
5892141cc406Sopenharmony_ci
5893141cc406Sopenharmony_ci    DBG(30, "condense_shading: ms=%p, ppl=%d\n", (void *) ms, ms->ppl);
5894141cc406Sopenharmony_ci    if ( md->shading_table_w == NULL )
5895141cc406Sopenharmony_ci      {
5896141cc406Sopenharmony_ci        DBG(1, "condense shading: no shading table found, skip shading\n");
5897141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
5898141cc406Sopenharmony_ci      }
5899141cc406Sopenharmony_ci
5900141cc406Sopenharmony_ci    get_lut_size( mi, &ms->lut_size, &ms->lut_entry_size );
5901141cc406Sopenharmony_ci
5902141cc406Sopenharmony_ci    if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5903141cc406Sopenharmony_ci      {
5904141cc406Sopenharmony_ci        shad_pixels = ms->n_control_bytes * 8;
5905141cc406Sopenharmony_ci        gray_filter_color = 0;  /* 336CX reads only one shading in gray mode*/
5906141cc406Sopenharmony_ci      }
5907141cc406Sopenharmony_ci    else
5908141cc406Sopenharmony_ci        shad_pixels = mi->geo_width;
5909141cc406Sopenharmony_ci
5910141cc406Sopenharmony_ci    shad_bplc = shad_pixels * ms->lut_entry_size;
5911141cc406Sopenharmony_ci
5912141cc406Sopenharmony_ci    if ( md_dump >= 3 )
5913141cc406Sopenharmony_ci      {
5914141cc406Sopenharmony_ci        dump_area2(md->shading_table_w, shad_bplc * 3, "shading_table_w");
5915141cc406Sopenharmony_ci        if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5916141cc406Sopenharmony_ci          write_shading_pnm(ms);
5917141cc406Sopenharmony_ci      }
5918141cc406Sopenharmony_ci
5919141cc406Sopenharmony_ci    cond_length = ms->bpl * ms->lut_entry_size;
5920141cc406Sopenharmony_ci
5921141cc406Sopenharmony_ci    if ( ms->condensed_shading_w )
5922141cc406Sopenharmony_ci      {
5923141cc406Sopenharmony_ci        free((void*) ms->condensed_shading_w );
5924141cc406Sopenharmony_ci        ms->condensed_shading_w = NULL;
5925141cc406Sopenharmony_ci      }
5926141cc406Sopenharmony_ci    ms->condensed_shading_w = (uint8_t *)malloc(cond_length);
5927141cc406Sopenharmony_ci    DBG(100, "condense_shading: ms->condensed_shading_w=%p,"
5928141cc406Sopenharmony_ci             "malloc'd %d bytes\n",
5929141cc406Sopenharmony_ci              (void *) ms->condensed_shading_w, cond_length);
5930141cc406Sopenharmony_ci    if ( ms->condensed_shading_w == NULL )
5931141cc406Sopenharmony_ci      {
5932141cc406Sopenharmony_ci        DBG(1, "condense_shading: malloc for white table failed\n");
5933141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
5934141cc406Sopenharmony_ci      }
5935141cc406Sopenharmony_ci
5936141cc406Sopenharmony_ci    if ( md->shading_table_d != NULL )
5937141cc406Sopenharmony_ci      {
5938141cc406Sopenharmony_ci        if ( md_dump >= 3 )
5939141cc406Sopenharmony_ci           dump_area2(md->shading_table_d, shad_bplc * 3,
5940141cc406Sopenharmony_ci                      "shading_table_d");
5941141cc406Sopenharmony_ci
5942141cc406Sopenharmony_ci        if ( ms->condensed_shading_d )
5943141cc406Sopenharmony_ci          {
5944141cc406Sopenharmony_ci            free((void*) ms->condensed_shading_d );
5945141cc406Sopenharmony_ci            ms->condensed_shading_d = NULL;
5946141cc406Sopenharmony_ci          }
5947141cc406Sopenharmony_ci        ms->condensed_shading_d = (uint8_t *)malloc(cond_length);
5948141cc406Sopenharmony_ci        DBG(100, "condense_shading: ms->condensed_shading_d=%p,"
5949141cc406Sopenharmony_ci                 " malloc'd %d bytes\n",
5950141cc406Sopenharmony_ci                  (void *) ms->condensed_shading_d, cond_length);
5951141cc406Sopenharmony_ci        if ( ms->condensed_shading_d == NULL )
5952141cc406Sopenharmony_ci          {
5953141cc406Sopenharmony_ci            DBG(1, "condense_shading: malloc for dark table failed\n");
5954141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
5955141cc406Sopenharmony_ci          }
5956141cc406Sopenharmony_ci      }
5957141cc406Sopenharmony_ci
5958141cc406Sopenharmony_ci    DBG(128, "controlbit offset=%d\n", md->controlbit_offset);
5959141cc406Sopenharmony_ci
5960141cc406Sopenharmony_ci    count = 0;
5961141cc406Sopenharmony_ci
5962141cc406Sopenharmony_ci    for (lfd_bit = 0; ( lfd_bit < mi->geo_width ) && ( count < (int)ms->ppl );
5963141cc406Sopenharmony_ci         ++lfd_bit)
5964141cc406Sopenharmony_ci      {
5965141cc406Sopenharmony_ci        byte = ( lfd_bit + md->controlbit_offset ) / 8;
5966141cc406Sopenharmony_ci        bit = ( lfd_bit + md->controlbit_offset ) % 8;
5967141cc406Sopenharmony_ci
5968141cc406Sopenharmony_ci        if ( mi->direction & MI_DATSEQ_RTOL )
5969141cc406Sopenharmony_ci            flag = ((ms->control_bytes[byte] >> bit) & 0x01);
5970141cc406Sopenharmony_ci        else
5971141cc406Sopenharmony_ci            flag = ((ms->control_bytes[byte] >> (7 - bit)) & 0x01);
5972141cc406Sopenharmony_ci
5973141cc406Sopenharmony_ci        if ( flag == 1 ) /* flag==1 if byte's bit is set */
5974141cc406Sopenharmony_ci          {
5975141cc406Sopenharmony_ci            for ( color = 0; color < 3; ++color )
5976141cc406Sopenharmony_ci              {
5977141cc406Sopenharmony_ci                if ( ( ms->mode == MS_MODE_COLOR )
5978141cc406Sopenharmony_ci                     || ( ( ms->mode == MS_MODE_GRAY )
5979141cc406Sopenharmony_ci                           && ( color == gray_filter_color ) )
5980141cc406Sopenharmony_ci                     || ( ( ms->mode == MS_MODE_LINEARTFAKE )
5981141cc406Sopenharmony_ci                           && ( color == gray_filter_color ) )
5982141cc406Sopenharmony_ci                    )
5983141cc406Sopenharmony_ci                  {
5984141cc406Sopenharmony_ci                    sh_offset = color * shad_pixels + lfd_bit;
5985141cc406Sopenharmony_ci                    if ( md->model_flags & MD_PHANTOM336CX_TYPE_SHADING )
5986141cc406Sopenharmony_ci                      sh_offset += md->controlbit_offset;
5987141cc406Sopenharmony_ci                    if ( ms->mode == MS_MODE_COLOR )
5988141cc406Sopenharmony_ci                      csh_offset = color * ms->ppl + count;
5989141cc406Sopenharmony_ci                    else
5990141cc406Sopenharmony_ci                      csh_offset = count;
5991141cc406Sopenharmony_ci
5992141cc406Sopenharmony_ci                    if ( csh_offset > cond_length )
5993141cc406Sopenharmony_ci                      {
5994141cc406Sopenharmony_ci                        DBG(1, "condense_shading: wrong control bits data, " );
5995141cc406Sopenharmony_ci                        DBG(1, "csh_offset (%d) > cond_length(%d)\n",
5996141cc406Sopenharmony_ci                             csh_offset, cond_length );
5997141cc406Sopenharmony_ci                        csh_offset = cond_length;
5998141cc406Sopenharmony_ci                      }
5999141cc406Sopenharmony_ci
6000141cc406Sopenharmony_ci                    if ( ms->lut_entry_size == 2 )
6001141cc406Sopenharmony_ci                      {
6002141cc406Sopenharmony_ci                        *((uint16_t *)ms->condensed_shading_w + csh_offset) =
6003141cc406Sopenharmony_ci                                         *((uint16_t *)md->shading_table_w
6004141cc406Sopenharmony_ci                                          + sh_offset);
6005141cc406Sopenharmony_ci                        if ( ms->condensed_shading_d != NULL )
6006141cc406Sopenharmony_ci                          *((uint16_t *)ms->condensed_shading_d + csh_offset) =
6007141cc406Sopenharmony_ci                                         *((uint16_t *)md->shading_table_d
6008141cc406Sopenharmony_ci                                          + sh_offset);
6009141cc406Sopenharmony_ci                      }
6010141cc406Sopenharmony_ci                    else
6011141cc406Sopenharmony_ci                      {
6012141cc406Sopenharmony_ci                        *((uint8_t *)ms->condensed_shading_w + csh_offset) =
6013141cc406Sopenharmony_ci                                         *((uint8_t *)md->shading_table_w
6014141cc406Sopenharmony_ci                                          + sh_offset);
6015141cc406Sopenharmony_ci                        if ( ms->condensed_shading_d != NULL )
6016141cc406Sopenharmony_ci                          *((uint8_t *)ms->condensed_shading_d + csh_offset) =
6017141cc406Sopenharmony_ci                                         *((uint8_t *)md->shading_table_d
6018141cc406Sopenharmony_ci                                          + sh_offset);
6019141cc406Sopenharmony_ci                      }
6020141cc406Sopenharmony_ci                  }
6021141cc406Sopenharmony_ci              }
6022141cc406Sopenharmony_ci            ++count;
6023141cc406Sopenharmony_ci          }
6024141cc406Sopenharmony_ci      }
6025141cc406Sopenharmony_ci
6026141cc406Sopenharmony_ci    if ( md_dump >= 3 )
6027141cc406Sopenharmony_ci      {
6028141cc406Sopenharmony_ci        dump_area2(ms->condensed_shading_w, cond_length, "condensed_shading_w");
6029141cc406Sopenharmony_ci        if ( ms->condensed_shading_d != NULL )
6030141cc406Sopenharmony_ci          dump_area2(ms->condensed_shading_d, cond_length,
6031141cc406Sopenharmony_ci                     "condensed_shading_d");
6032141cc406Sopenharmony_ci
6033141cc406Sopenharmony_ci        write_cshading_pnm(ms);
6034141cc406Sopenharmony_ci      }
6035141cc406Sopenharmony_ci
6036141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6037141cc406Sopenharmony_ci}
6038141cc406Sopenharmony_ci
6039141cc406Sopenharmony_ci
6040141cc406Sopenharmony_ci/*---------- read_shading_image() --------------------------------------------*/
6041141cc406Sopenharmony_ci
6042141cc406Sopenharmony_cistatic SANE_Status
6043141cc406Sopenharmony_ciread_shading_image(Microtek2_Scanner *ms)
6044141cc406Sopenharmony_ci{
6045141cc406Sopenharmony_ci    SANE_Status status;
6046141cc406Sopenharmony_ci    Microtek2_Device *md;
6047141cc406Sopenharmony_ci    Microtek2_Info *mi;
6048141cc406Sopenharmony_ci    uint32_t lines;
6049141cc406Sopenharmony_ci    uint8_t *buf;
6050141cc406Sopenharmony_ci    int max_lines;
6051141cc406Sopenharmony_ci    int lines_to_read;
6052141cc406Sopenharmony_ci
6053141cc406Sopenharmony_ci    DBG(30, "read_shading_image: ms=%p\n", (void *) ms);
6054141cc406Sopenharmony_ci
6055141cc406Sopenharmony_ci    md = ms->dev;
6056141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
6057141cc406Sopenharmony_ci
6058141cc406Sopenharmony_ci
6059141cc406Sopenharmony_ci    if ( ! MI_WHITE_SHADING_ONLY(mi->shtrnsferequ)
6060141cc406Sopenharmony_ci        || ( md->model_flags & MD_PHANTOM_C6 ) )
6061141cc406Sopenharmony_ci
6062141cc406Sopenharmony_ci      /* Dark shading correction */
6063141cc406Sopenharmony_ci      /* ~~~~~~~~~~~~~~~~~~~~~~~ */
6064141cc406Sopenharmony_ci      {
6065141cc406Sopenharmony_ci        DBG(30, "read_shading_image: reading black data\n");
6066141cc406Sopenharmony_ci        md->status.ntrack |= MD_NTRACK_ON;
6067141cc406Sopenharmony_ci        md->status.ncalib &= ~MD_NCALIB_ON;
6068141cc406Sopenharmony_ci        md->status.flamp |= MD_FLAMP_ON;
6069141cc406Sopenharmony_ci        if ( md->model_flags & MD_PHANTOM_C6 )
6070141cc406Sopenharmony_ci          {
6071141cc406Sopenharmony_ci            md->status.stick |= MD_STICK_ON;
6072141cc406Sopenharmony_ci            md->status.reserved17 |= MD_RESERVED17_ON;
6073141cc406Sopenharmony_ci          }
6074141cc406Sopenharmony_ci
6075141cc406Sopenharmony_ci        get_calib_params(ms);
6076141cc406Sopenharmony_ci        if ( md->model_flags & MD_PHANTOM_C6 )
6077141cc406Sopenharmony_ci             ms->stay = 1;
6078141cc406Sopenharmony_ci
6079141cc406Sopenharmony_ci        status = scsi_send_system_status(md, ms->sfd);
6080141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6081141cc406Sopenharmony_ci            return status;
6082141cc406Sopenharmony_ci
6083141cc406Sopenharmony_ci        status = scsi_set_window(ms, 1);
6084141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6085141cc406Sopenharmony_ci            return status;
6086141cc406Sopenharmony_ci
6087141cc406Sopenharmony_ci#ifdef TESTBACKEND
6088141cc406Sopenharmony_ci        status = scsi_read_sh_image_info(ms);
6089141cc406Sopenharmony_ci#else
6090141cc406Sopenharmony_ci        status = scsi_read_image_info(ms);
6091141cc406Sopenharmony_ci#endif
6092141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6093141cc406Sopenharmony_ci            return status;
6094141cc406Sopenharmony_ci
6095141cc406Sopenharmony_ci        status = scsi_wait_for_image(ms);
6096141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6097141cc406Sopenharmony_ci            return status;
6098141cc406Sopenharmony_ci
6099141cc406Sopenharmony_ci        status = scsi_read_system_status(md, ms->sfd);
6100141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6101141cc406Sopenharmony_ci            return status;
6102141cc406Sopenharmony_ci
6103141cc406Sopenharmony_ci        md->status.flamp &= ~MD_FLAMP_ON;
6104141cc406Sopenharmony_ci
6105141cc406Sopenharmony_ci        status = scsi_send_system_status(md, ms->sfd);
6106141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6107141cc406Sopenharmony_ci            return status;
6108141cc406Sopenharmony_ci
6109141cc406Sopenharmony_ci        ms->shading_image = malloc(ms->bpl * ms->src_remaining_lines);
6110141cc406Sopenharmony_ci        DBG(100, "read shading image: ms->shading_image=%p,"
6111141cc406Sopenharmony_ci                 " malloc'd %d bytes\n",
6112141cc406Sopenharmony_ci                  (void *) ms->shading_image,
6113141cc406Sopenharmony_ci                  ms->bpl * ms->src_remaining_lines);
6114141cc406Sopenharmony_ci        if ( ms->shading_image == NULL )
6115141cc406Sopenharmony_ci          {
6116141cc406Sopenharmony_ci            DBG(1, "read_shading_image: malloc for buffer failed\n");
6117141cc406Sopenharmony_ci            return SANE_STATUS_NO_MEM;
6118141cc406Sopenharmony_ci          }
6119141cc406Sopenharmony_ci
6120141cc406Sopenharmony_ci        buf = ms->shading_image;
6121141cc406Sopenharmony_ci
6122141cc406Sopenharmony_ci#ifdef TESTBACKEND
6123141cc406Sopenharmony_ci        max_lines = 5000000 / ms->bpl;
6124141cc406Sopenharmony_ci#else
6125141cc406Sopenharmony_ci        max_lines = sanei_scsi_max_request_size / ms->bpl;
6126141cc406Sopenharmony_ci#endif
6127141cc406Sopenharmony_ci        if ( max_lines == 0 )
6128141cc406Sopenharmony_ci          {
6129141cc406Sopenharmony_ci            DBG(1, "read_shading_image: buffer too small\n");
6130141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
6131141cc406Sopenharmony_ci          }
6132141cc406Sopenharmony_ci        lines = ms->src_remaining_lines;
6133141cc406Sopenharmony_ci        while ( ms->src_remaining_lines > 0 )
6134141cc406Sopenharmony_ci          {
6135141cc406Sopenharmony_ci            lines_to_read = MIN(max_lines, ms->src_remaining_lines);
6136141cc406Sopenharmony_ci            ms->src_buffer_size = lines_to_read * ms->bpl;
6137141cc406Sopenharmony_ci            ms->transfer_length = ms->src_buffer_size;
6138141cc406Sopenharmony_ci#ifdef TESTBACKEND
6139141cc406Sopenharmony_ci            status = scsi_read_sh_d_image(ms, buf);
6140141cc406Sopenharmony_ci#else
6141141cc406Sopenharmony_ci            status = scsi_read_image(ms, buf, md->shading_depth>8 ? 2 : 1);
6142141cc406Sopenharmony_ci#endif
6143141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
6144141cc406Sopenharmony_ci              {
6145141cc406Sopenharmony_ci                DBG(1, "read_shading_image: read image failed: '%s'\n",
6146141cc406Sopenharmony_ci                        sane_strstatus(status));
6147141cc406Sopenharmony_ci                return status;
6148141cc406Sopenharmony_ci              }
6149141cc406Sopenharmony_ci
6150141cc406Sopenharmony_ci            ms->src_remaining_lines -= lines_to_read;
6151141cc406Sopenharmony_ci            buf += ms->src_buffer_size;
6152141cc406Sopenharmony_ci          }
6153141cc406Sopenharmony_ci
6154141cc406Sopenharmony_ci        status =  prepare_shading_data(ms, lines, &md->shading_table_d);
6155141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6156141cc406Sopenharmony_ci            return status;
6157141cc406Sopenharmony_ci
6158141cc406Sopenharmony_ci        /* send shading data to the device */
6159141cc406Sopenharmony_ci        /* Some models use "read_control bit", and the shading must be */
6160141cc406Sopenharmony_ci        /* applied by the backend later */
6161141cc406Sopenharmony_ci        if ( ! (md->model_flags & MD_READ_CONTROL_BIT) )
6162141cc406Sopenharmony_ci          {
6163141cc406Sopenharmony_ci            status =  shading_function(ms, md->shading_table_d);
6164141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
6165141cc406Sopenharmony_ci                return status;
6166141cc406Sopenharmony_ci
6167141cc406Sopenharmony_ci            ms->word = ms->lut_entry_size == 2 ? 1 : 0;
6168141cc406Sopenharmony_ci            ms->current_color = MS_COLOR_ALL;
6169141cc406Sopenharmony_ci            status = scsi_send_shading(ms,
6170141cc406Sopenharmony_ci                                       md->shading_table_d,
6171141cc406Sopenharmony_ci                                       3 * ms->lut_entry_size
6172141cc406Sopenharmony_ci                                         * mi->geo_width / mi->calib_divisor,
6173141cc406Sopenharmony_ci                                       1);
6174141cc406Sopenharmony_ci            if ( status != SANE_STATUS_GOOD )
6175141cc406Sopenharmony_ci                return status;
6176141cc406Sopenharmony_ci          }
6177141cc406Sopenharmony_ci
6178141cc406Sopenharmony_ci        DBG(100, "free memory for ms->shading_image at %p\n",
6179141cc406Sopenharmony_ci                  (void *) ms->shading_image);
6180141cc406Sopenharmony_ci        free((void *) ms->shading_image);
6181141cc406Sopenharmony_ci        ms->shading_image = NULL;
6182141cc406Sopenharmony_ci      }
6183141cc406Sopenharmony_ci
6184141cc406Sopenharmony_ci    /* white shading correction */
6185141cc406Sopenharmony_ci    /* ~~~~~~~~~~~~~~~~~~~~~~~~ */
6186141cc406Sopenharmony_ci    DBG(30, "read_shading_image: reading white data\n");
6187141cc406Sopenharmony_ci
6188141cc406Sopenharmony_ci    /* According to the doc NCalib must be set for white shading data */
6189141cc406Sopenharmony_ci    /* if we have a black and a white shading correction and must be */
6190141cc406Sopenharmony_ci    /* cleared if we have only a white shading collection */
6191141cc406Sopenharmony_ci    if ( ! MI_WHITE_SHADING_ONLY(mi->shtrnsferequ)
6192141cc406Sopenharmony_ci        || ( md->model_flags & MD_PHANTOM_C6 ) )
6193141cc406Sopenharmony_ci      md->status.ncalib |= MD_NCALIB_ON;
6194141cc406Sopenharmony_ci    else
6195141cc406Sopenharmony_ci      md->status.ncalib &= ~MD_NCALIB_ON;
6196141cc406Sopenharmony_ci
6197141cc406Sopenharmony_ci    md->status.flamp |= MD_FLAMP_ON;
6198141cc406Sopenharmony_ci/*    md->status.tlamp &= ~MD_TLAMP_ON;  */
6199141cc406Sopenharmony_ci    md->status.ntrack |= MD_NTRACK_ON;
6200141cc406Sopenharmony_ci
6201141cc406Sopenharmony_ci    if ( md->model_flags & MD_PHANTOM_C6 )
6202141cc406Sopenharmony_ci      {
6203141cc406Sopenharmony_ci        md->status.stick &= ~MD_STICK_ON;
6204141cc406Sopenharmony_ci        md->status.reserved17 |= MD_RESERVED17_ON;
6205141cc406Sopenharmony_ci      }
6206141cc406Sopenharmony_ci
6207141cc406Sopenharmony_ci    get_calib_params(ms);
6208141cc406Sopenharmony_ci
6209141cc406Sopenharmony_ci#ifdef NO_PHANTOMTYPE_SHADING
6210141cc406Sopenharmony_ci/*    md->status.stick &= ~MD_STICK_ON; */
6211141cc406Sopenharmony_ci/*    md->status.ncalib &= ~MD_NCALIB_ON; */
6212141cc406Sopenharmony_ci/*    md->status.reserved17 &= ~MD_RESERVED17_ON; */
6213141cc406Sopenharmony_ci    ms->rawdat = 0;
6214141cc406Sopenharmony_ci#endif
6215141cc406Sopenharmony_ci
6216141cc406Sopenharmony_ci    status = scsi_send_system_status(md, ms->sfd);
6217141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6218141cc406Sopenharmony_ci        return status;
6219141cc406Sopenharmony_ci
6220141cc406Sopenharmony_ci    status = scsi_set_window(ms, 1);
6221141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6222141cc406Sopenharmony_ci        return status;
6223141cc406Sopenharmony_ci
6224141cc406Sopenharmony_ci#ifdef TESTBACKEND
6225141cc406Sopenharmony_ci    status = scsi_read_sh_image_info(ms);
6226141cc406Sopenharmony_ci#else
6227141cc406Sopenharmony_ci    status = scsi_read_image_info(ms);
6228141cc406Sopenharmony_ci#endif
6229141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6230141cc406Sopenharmony_ci        return status;
6231141cc406Sopenharmony_ci
6232141cc406Sopenharmony_ci    status = scsi_wait_for_image(ms);
6233141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6234141cc406Sopenharmony_ci        return status;
6235141cc406Sopenharmony_ci
6236141cc406Sopenharmony_ci#ifdef NO_PHANTOMTYPE_SHADING
6237141cc406Sopenharmony_ci    if ( !( md->model_flags & MD_READ_CONTROL_BIT ) )
6238141cc406Sopenharmony_ci      {
6239141cc406Sopenharmony_ci#endif
6240141cc406Sopenharmony_ci	status = scsi_read_system_status(md, ms->sfd);
6241141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6242141cc406Sopenharmony_ci            return status;
6243141cc406Sopenharmony_ci#ifdef NO_PHANTOMTYPE_SHADING
6244141cc406Sopenharmony_ci      }
6245141cc406Sopenharmony_ci#endif
6246141cc406Sopenharmony_ci
6247141cc406Sopenharmony_ci#ifdef NO_PHANTOMTYPE_SHADING
6248141cc406Sopenharmony_ci    if ( mi->model_code == 0x94 )
6249141cc406Sopenharmony_ci        status = scsi_read_control_bits(ms);
6250141cc406Sopenharmony_ci#endif
6251141cc406Sopenharmony_ci
6252141cc406Sopenharmony_ci    ms->shading_image = malloc(ms->bpl * ms->src_remaining_lines);
6253141cc406Sopenharmony_ci    DBG(100, "read shading image: ms->shading_image=%p, malloc'd %d bytes\n",
6254141cc406Sopenharmony_ci              (void *) ms->shading_image, ms->bpl * ms->src_remaining_lines);
6255141cc406Sopenharmony_ci    if ( ms->shading_image == NULL )
6256141cc406Sopenharmony_ci      {
6257141cc406Sopenharmony_ci        DBG(1, "read_shading_image: malloc for buffer failed\n");
6258141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
6259141cc406Sopenharmony_ci      }
6260141cc406Sopenharmony_ci
6261141cc406Sopenharmony_ci    buf = ms->shading_image;
6262141cc406Sopenharmony_ci#ifdef TESTBACKEND
6263141cc406Sopenharmony_ci    max_lines = 5000000 / ms->bpl;
6264141cc406Sopenharmony_ci#else
6265141cc406Sopenharmony_ci    max_lines = sanei_scsi_max_request_size / ms->bpl;
6266141cc406Sopenharmony_ci#endif
6267141cc406Sopenharmony_ci    if ( max_lines == 0 )
6268141cc406Sopenharmony_ci      {
6269141cc406Sopenharmony_ci        DBG(1, "read_shading_image: buffer too small\n");
6270141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
6271141cc406Sopenharmony_ci      }
6272141cc406Sopenharmony_ci    lines = ms->src_remaining_lines;
6273141cc406Sopenharmony_ci    while ( ms->src_remaining_lines > 0 )
6274141cc406Sopenharmony_ci      {
6275141cc406Sopenharmony_ci        lines_to_read = MIN(max_lines, ms->src_remaining_lines);
6276141cc406Sopenharmony_ci        ms->src_buffer_size = lines_to_read * ms->bpl;
6277141cc406Sopenharmony_ci        ms->transfer_length = ms->src_buffer_size;
6278141cc406Sopenharmony_ci
6279141cc406Sopenharmony_ci#ifdef TESTBACKEND
6280141cc406Sopenharmony_ci        status = scsi_read_sh_w_image(ms, buf);
6281141cc406Sopenharmony_ci#else
6282141cc406Sopenharmony_ci	status = scsi_read_image(ms, buf, md->shading_depth>8 ? 2 : 1);
6283141cc406Sopenharmony_ci#endif
6284141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6285141cc406Sopenharmony_ci            return status;
6286141cc406Sopenharmony_ci
6287141cc406Sopenharmony_ci        ms->src_remaining_lines -= lines_to_read;
6288141cc406Sopenharmony_ci        buf += ms->src_buffer_size;
6289141cc406Sopenharmony_ci      }
6290141cc406Sopenharmony_ci
6291141cc406Sopenharmony_ci    status =  prepare_shading_data(ms, lines, &md->shading_table_w);
6292141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6293141cc406Sopenharmony_ci        return status;
6294141cc406Sopenharmony_ci
6295141cc406Sopenharmony_ci    if ( md_dump >= 3 )
6296141cc406Sopenharmony_ci      {
6297141cc406Sopenharmony_ci        write_shading_buf_pnm(ms, lines);
6298141cc406Sopenharmony_ci        write_shading_pnm(ms);
6299141cc406Sopenharmony_ci      }
6300141cc406Sopenharmony_ci
6301141cc406Sopenharmony_ci    /* send shading data to the device */
6302141cc406Sopenharmony_ci    /* Some models use "read_control bit", and the shading must be */
6303141cc406Sopenharmony_ci    /* applied by the backend later */
6304141cc406Sopenharmony_ci    if ( ! (md->model_flags & MD_READ_CONTROL_BIT) )
6305141cc406Sopenharmony_ci      {
6306141cc406Sopenharmony_ci        status =  shading_function(ms, md->shading_table_w);
6307141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6308141cc406Sopenharmony_ci            return status;
6309141cc406Sopenharmony_ci
6310141cc406Sopenharmony_ci        ms->word = ms->lut_entry_size == 2 ? 1 : 0;
6311141cc406Sopenharmony_ci        ms->current_color = MS_COLOR_ALL;
6312141cc406Sopenharmony_ci        status = scsi_send_shading(ms,
6313141cc406Sopenharmony_ci                                   md->shading_table_w,
6314141cc406Sopenharmony_ci                                   3 * ms->lut_entry_size
6315141cc406Sopenharmony_ci                                   * mi->geo_width / mi->calib_divisor,
6316141cc406Sopenharmony_ci                                   0);
6317141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6318141cc406Sopenharmony_ci            return status;
6319141cc406Sopenharmony_ci      }
6320141cc406Sopenharmony_ci
6321141cc406Sopenharmony_ci    ms->rawdat = 0;
6322141cc406Sopenharmony_ci    ms->stay = 0;
6323141cc406Sopenharmony_ci    md->status.ncalib |= MD_NCALIB_ON;
6324141cc406Sopenharmony_ci
6325141cc406Sopenharmony_ci    if ( md->model_flags & MD_PHANTOM_C6 )
6326141cc406Sopenharmony_ci      {
6327141cc406Sopenharmony_ci        md->status.stick &= ~MD_STICK_ON;
6328141cc406Sopenharmony_ci        md->status.reserved17 &= ~MD_RESERVED17_ON;
6329141cc406Sopenharmony_ci      }
6330141cc406Sopenharmony_ci
6331141cc406Sopenharmony_ci#ifdef NO_PHANTOMTYPE_SHADING
6332141cc406Sopenharmony_ci    if (mi->model_code == 0x94)
6333141cc406Sopenharmony_ci        md->status.ncalib &= ~MD_NCALIB_ON;
6334141cc406Sopenharmony_ci#endif
6335141cc406Sopenharmony_ci
6336141cc406Sopenharmony_ci    status = scsi_send_system_status(md, ms->sfd);
6337141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6338141cc406Sopenharmony_ci        return status;
6339141cc406Sopenharmony_ci
6340141cc406Sopenharmony_ci    DBG(100, "free memory for ms->shading_image at %p\n",
6341141cc406Sopenharmony_ci              (void *) ms->shading_image);
6342141cc406Sopenharmony_ci    free((void *) ms->shading_image);
6343141cc406Sopenharmony_ci    ms->shading_image = NULL;
6344141cc406Sopenharmony_ci
6345141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6346141cc406Sopenharmony_ci
6347141cc406Sopenharmony_ci}
6348141cc406Sopenharmony_ci
6349141cc406Sopenharmony_ci/*---------- prepare_shading_data() ------------------------------------------*/
6350141cc406Sopenharmony_ci
6351141cc406Sopenharmony_cistatic SANE_Status
6352141cc406Sopenharmony_ciprepare_shading_data(Microtek2_Scanner *ms, uint32_t lines, uint8_t **data)
6353141cc406Sopenharmony_ci{
6354141cc406Sopenharmony_ci  /* This function calculates one line of black or white shading data */
6355141cc406Sopenharmony_ci  /* from the shading image. At the end we have one line. The */
6356141cc406Sopenharmony_ci  /* color sequence is unchanged. */
6357141cc406Sopenharmony_ci
6358141cc406Sopenharmony_ci#define MICROTEK2_CALIB_USE_MEDIAN
6359141cc406Sopenharmony_ci
6360141cc406Sopenharmony_ci  Microtek2_Device *md;
6361141cc406Sopenharmony_ci  Microtek2_Info *mi;
6362141cc406Sopenharmony_ci  uint32_t length,line;
6363141cc406Sopenharmony_ci  int color, i;
6364141cc406Sopenharmony_ci  SANE_Status status;
6365141cc406Sopenharmony_ci
6366141cc406Sopenharmony_ci#ifdef  MICROTEK2_CALIB_USE_MEDIAN
6367141cc406Sopenharmony_ci  uint16_t *sortbuf, value;
6368141cc406Sopenharmony_ci#else
6369141cc406Sopenharmony_ci  uint32_t value;
6370141cc406Sopenharmony_ci#endif
6371141cc406Sopenharmony_ci
6372141cc406Sopenharmony_ci  DBG(30, "prepare_shading_data: ms=%p, lines=%d, *data=%p\n",
6373141cc406Sopenharmony_ci           (void *) ms, lines, (void *) *data);
6374141cc406Sopenharmony_ci
6375141cc406Sopenharmony_ci  md = ms->dev;
6376141cc406Sopenharmony_ci  mi = &md->info[md->scan_source];
6377141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
6378141cc406Sopenharmony_ci
6379141cc406Sopenharmony_ci  get_lut_size(mi, &ms->lut_size, &ms->lut_entry_size);
6380141cc406Sopenharmony_ci  length = 3 * ms->lut_entry_size * mi->geo_width / mi->calib_divisor;
6381141cc406Sopenharmony_ci
6382141cc406Sopenharmony_ci  if ( *data == NULL )
6383141cc406Sopenharmony_ci    {
6384141cc406Sopenharmony_ci      *data = (uint8_t *) malloc(length);
6385141cc406Sopenharmony_ci      DBG(100, "prepare_shading_data: malloc'd %d bytes at %p\n",
6386141cc406Sopenharmony_ci                length, (void *) *data);
6387141cc406Sopenharmony_ci      if ( *data == NULL )
6388141cc406Sopenharmony_ci        {
6389141cc406Sopenharmony_ci          DBG(1, "prepare_shading_data: malloc for shading table failed\n");
6390141cc406Sopenharmony_ci          return SANE_STATUS_NO_MEM;
6391141cc406Sopenharmony_ci        }
6392141cc406Sopenharmony_ci    }
6393141cc406Sopenharmony_ci
6394141cc406Sopenharmony_ci#ifdef  MICROTEK2_CALIB_USE_MEDIAN
6395141cc406Sopenharmony_ci  sortbuf = malloc( lines * ms->lut_entry_size );
6396141cc406Sopenharmony_ci  DBG(100, "prepare_shading_data: sortbuf= %p, malloc'd %d Bytes\n",
6397141cc406Sopenharmony_ci            (void *) sortbuf, lines * ms->lut_entry_size);
6398141cc406Sopenharmony_ci  if ( sortbuf == NULL )
6399141cc406Sopenharmony_ci    {
6400141cc406Sopenharmony_ci      DBG(1, "prepare_shading_data: malloc for sort buffer failed\n");
6401141cc406Sopenharmony_ci      return SANE_STATUS_NO_MEM;
6402141cc406Sopenharmony_ci    }
6403141cc406Sopenharmony_ci#endif
6404141cc406Sopenharmony_ci
6405141cc406Sopenharmony_ci  switch( mi->data_format )
6406141cc406Sopenharmony_ci    {
6407141cc406Sopenharmony_ci      case MI_DATAFMT_LPLCONCAT:
6408141cc406Sopenharmony_ci        if ( ms->lut_entry_size == 1 )
6409141cc406Sopenharmony_ci          {
6410141cc406Sopenharmony_ci            DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n");
6411141cc406Sopenharmony_ci            return SANE_STATUS_UNSUPPORTED;
6412141cc406Sopenharmony_ci          }
6413141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
6414141cc406Sopenharmony_ci          {
6415141cc406Sopenharmony_ci            for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6416141cc406Sopenharmony_ci              {
6417141cc406Sopenharmony_ci                value = 0;
6418141cc406Sopenharmony_ci                for ( line = 0; line < lines; line++ )
6419141cc406Sopenharmony_ci#ifndef  MICROTEK2_CALIB_USE_MEDIAN
6420141cc406Sopenharmony_ci/*  average the shading lines to get the shading data */
6421141cc406Sopenharmony_ci                      value += *((uint16_t *) ms->shading_image
6422141cc406Sopenharmony_ci                             + line * ( ms->bpl / ms->lut_entry_size )
6423141cc406Sopenharmony_ci                             + color * ( ms->bpl / ms->lut_entry_size / 3 )
6424141cc406Sopenharmony_ci                             + i);
6425141cc406Sopenharmony_ci                value /= lines;
6426141cc406Sopenharmony_ci                *((uint16_t *) *data
6427141cc406Sopenharmony_ci                   + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6428141cc406Sopenharmony_ci                                           (uint16_t) MIN(0xffff, value);
6429141cc406Sopenharmony_ci#else
6430141cc406Sopenharmony_ci/*  use a median filter to get the shading data -- should be better */
6431141cc406Sopenharmony_ci                    *(sortbuf + line ) =
6432141cc406Sopenharmony_ci                          *((uint16_t *) ms->shading_image
6433141cc406Sopenharmony_ci                             + line * ( ms->bpl / ms->lut_entry_size )
6434141cc406Sopenharmony_ci                             + color * ( ms->bpl / ms->lut_entry_size / 3 )
6435141cc406Sopenharmony_ci                             + i);
6436141cc406Sopenharmony_ci                qsort(sortbuf, lines, sizeof(uint16_t),
6437141cc406Sopenharmony_ci                       (qsortfunc)compare_func_16);
6438141cc406Sopenharmony_ci                value = *(sortbuf + ( lines - 1 ) / 2 );
6439141cc406Sopenharmony_ci                *((uint16_t *) *data
6440141cc406Sopenharmony_ci                   + color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6441141cc406Sopenharmony_ci#endif
6442141cc406Sopenharmony_ci              }
6443141cc406Sopenharmony_ci          }
6444141cc406Sopenharmony_ci        break;
6445141cc406Sopenharmony_ci
6446141cc406Sopenharmony_ci      case MI_DATAFMT_CHUNKY:
6447141cc406Sopenharmony_ci      case MI_DATAFMT_9800:
6448141cc406Sopenharmony_ci        if ( ms->lut_entry_size == 1 )
6449141cc406Sopenharmony_ci          {
6450141cc406Sopenharmony_ci            DBG(1, "prepare_shading_data: wordsize == 1 unsupported\n");
6451141cc406Sopenharmony_ci            return SANE_STATUS_UNSUPPORTED;
6452141cc406Sopenharmony_ci          }
6453141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
6454141cc406Sopenharmony_ci          {
6455141cc406Sopenharmony_ci            for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6456141cc406Sopenharmony_ci              {
6457141cc406Sopenharmony_ci                value = 0;
6458141cc406Sopenharmony_ci                for ( line = 0; line < lines; line++ )
6459141cc406Sopenharmony_ci#ifndef  MICROTEK2_CALIB_USE_MEDIAN
6460141cc406Sopenharmony_ci/*  average the shading lines to get the shading data */
6461141cc406Sopenharmony_ci                    value += *((uint16_t *) ms->shading_image
6462141cc406Sopenharmony_ci                             + line * 3 * mi->geo_width / mi->calib_divisor
6463141cc406Sopenharmony_ci                             + 3 * i
6464141cc406Sopenharmony_ci                             + color);
6465141cc406Sopenharmony_ci
6466141cc406Sopenharmony_ci                value /= lines;
6467141cc406Sopenharmony_ci                *((uint16_t *) *data
6468141cc406Sopenharmony_ci                 + color * ( mi->geo_width / mi->calib_divisor ) + i) =
6469141cc406Sopenharmony_ci                                               (uint16_t) MIN(0xffff, value);
6470141cc406Sopenharmony_ci#else
6471141cc406Sopenharmony_ci/*  use a median filter to get the shading data -- should be better */
6472141cc406Sopenharmony_ci                    *(sortbuf + line ) =
6473141cc406Sopenharmony_ci                          *((uint16_t *) ms->shading_image
6474141cc406Sopenharmony_ci                             + line * 3 * mi->geo_width / mi->calib_divisor
6475141cc406Sopenharmony_ci                             + 3 * i
6476141cc406Sopenharmony_ci                             + color);
6477141cc406Sopenharmony_ci                qsort(sortbuf, lines, sizeof(uint16_t),
6478141cc406Sopenharmony_ci                       (qsortfunc)compare_func_16);
6479141cc406Sopenharmony_ci                value = *(sortbuf + ( lines - 1 ) / 2 );
6480141cc406Sopenharmony_ci                *((uint16_t *) *data
6481141cc406Sopenharmony_ci                 + color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6482141cc406Sopenharmony_ci#endif
6483141cc406Sopenharmony_ci              }
6484141cc406Sopenharmony_ci          }
6485141cc406Sopenharmony_ci        break;
6486141cc406Sopenharmony_ci
6487141cc406Sopenharmony_ci      case MI_DATAFMT_LPLSEGREG:
6488141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
6489141cc406Sopenharmony_ci          {
6490141cc406Sopenharmony_ci            for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++ )
6491141cc406Sopenharmony_ci              {
6492141cc406Sopenharmony_ci                value = 0;
6493141cc406Sopenharmony_ci                if ( ms->lut_entry_size == 1 )
6494141cc406Sopenharmony_ci		  {
6495141cc406Sopenharmony_ci                    for ( line = 0; line < lines; line++ )
6496141cc406Sopenharmony_ci			value += *((uint8_t *) ms->shading_image
6497141cc406Sopenharmony_ci				+ line * 3 * mi->geo_width / mi->calib_divisor
6498141cc406Sopenharmony_ci				+ 3 * i
6499141cc406Sopenharmony_ci				+ color);
6500141cc406Sopenharmony_ci
6501141cc406Sopenharmony_ci		    value /= lines;
6502141cc406Sopenharmony_ci                    *((uint8_t *) *data
6503141cc406Sopenharmony_ci			+ color * ( mi->geo_width / mi->calib_divisor ) + i) =
6504141cc406Sopenharmony_ci			(uint8_t) MIN(0xff, value);
6505141cc406Sopenharmony_ci
6506141cc406Sopenharmony_ci		  }
6507141cc406Sopenharmony_ci		else
6508141cc406Sopenharmony_ci		  {
6509141cc406Sopenharmony_ci		    for ( line = 0; line < lines; line++ )
6510141cc406Sopenharmony_ci			value += *((uint16_t *) ms->shading_image
6511141cc406Sopenharmony_ci				+ line * 3 * mi->geo_width / mi->calib_divisor
6512141cc406Sopenharmony_ci				+ 3 * i
6513141cc406Sopenharmony_ci				+ color);
6514141cc406Sopenharmony_ci
6515141cc406Sopenharmony_ci		    value /= lines;
6516141cc406Sopenharmony_ci#ifndef  MICROTEK2_CALIB_USE_MEDIAN
6517141cc406Sopenharmony_ci		    *((uint16_t *) *data
6518141cc406Sopenharmony_ci			+ color * ( mi->geo_width / mi->calib_divisor ) + i) =
6519141cc406Sopenharmony_ci			(uint16_t) MIN(0xffff, value);
6520141cc406Sopenharmony_ci#else
6521141cc406Sopenharmony_ci		    *((uint16_t *) *data
6522141cc406Sopenharmony_ci			+ color * ( mi->geo_width / mi->calib_divisor ) + i) = value;
6523141cc406Sopenharmony_ci#endif
6524141cc406Sopenharmony_ci		  }
6525141cc406Sopenharmony_ci
6526141cc406Sopenharmony_ci              }
6527141cc406Sopenharmony_ci          }
6528141cc406Sopenharmony_ci        break;
6529141cc406Sopenharmony_ci
6530141cc406Sopenharmony_ci      default:
6531141cc406Sopenharmony_ci        DBG(1, "prepare_shading_data: Unsupported data format 0x%02x\n",
6532141cc406Sopenharmony_ci                mi->data_format);
6533141cc406Sopenharmony_ci        status = SANE_STATUS_UNSUPPORTED;
6534141cc406Sopenharmony_ci    }
6535141cc406Sopenharmony_ci
6536141cc406Sopenharmony_ci#ifdef  MICROTEK2_CALIB_USE_MEDIAN
6537141cc406Sopenharmony_ci  DBG(100, "prepare_shading_data: free sortbuf at %p\n", (void *) sortbuf);
6538141cc406Sopenharmony_ci  free(sortbuf);
6539141cc406Sopenharmony_ci  sortbuf = NULL;
6540141cc406Sopenharmony_ci#endif
6541141cc406Sopenharmony_ci    return status;
6542141cc406Sopenharmony_ci}
6543141cc406Sopenharmony_ci
6544141cc406Sopenharmony_ci
6545141cc406Sopenharmony_ci/*---------- read_cx_shading() -----------------------------------------------*/
6546141cc406Sopenharmony_ci
6547141cc406Sopenharmony_cistatic SANE_Status
6548141cc406Sopenharmony_ciread_cx_shading(Microtek2_Scanner *ms)
6549141cc406Sopenharmony_ci{
6550141cc406Sopenharmony_ci    SANE_Status status;
6551141cc406Sopenharmony_ci    Microtek2_Device *md;
6552141cc406Sopenharmony_ci    md = ms->dev;
6553141cc406Sopenharmony_ci
6554141cc406Sopenharmony_ci    DBG(30, "read_cx_shading: ms=%p\n",(void *) ms);
6555141cc406Sopenharmony_ci
6556141cc406Sopenharmony_ci    md->shading_table_contents = ms->mode;
6557141cc406Sopenharmony_ci
6558141cc406Sopenharmony_ci    if ( ms->mode == MS_MODE_COLOR )
6559141cc406Sopenharmony_ci        ms->current_color = MS_COLOR_ALL;
6560141cc406Sopenharmony_ci    else
6561141cc406Sopenharmony_ci        ms->current_color = MS_COLOR_GREEN;  /* for grayscale */
6562141cc406Sopenharmony_ci
6563141cc406Sopenharmony_ci    ms->word = 1;
6564141cc406Sopenharmony_ci    ms->dark = 0;
6565141cc406Sopenharmony_ci
6566141cc406Sopenharmony_ci    status = read_cx_shading_image(ms);
6567141cc406Sopenharmony_ci    if ( status  != SANE_STATUS_GOOD )
6568141cc406Sopenharmony_ci        goto cleanup;
6569141cc406Sopenharmony_ci
6570141cc406Sopenharmony_ci    ms->word = 0;  /* the Windows driver reads dark shading with word=0 */
6571141cc406Sopenharmony_ci    ms->dark = 1;
6572141cc406Sopenharmony_ci    status = read_cx_shading_image(ms);
6573141cc406Sopenharmony_ci    if ( status  != SANE_STATUS_GOOD )
6574141cc406Sopenharmony_ci        goto cleanup;
6575141cc406Sopenharmony_ci
6576141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6577141cc406Sopenharmony_ci
6578141cc406Sopenharmony_cicleanup:
6579141cc406Sopenharmony_ci    cleanup_scanner(ms);
6580141cc406Sopenharmony_ci    return status;
6581141cc406Sopenharmony_ci}
6582141cc406Sopenharmony_ci
6583141cc406Sopenharmony_ci
6584141cc406Sopenharmony_ci/*---------- read_cx_shading_image() -----------------------------------------*/
6585141cc406Sopenharmony_ci
6586141cc406Sopenharmony_cistatic SANE_Status
6587141cc406Sopenharmony_ciread_cx_shading_image(Microtek2_Scanner *ms)
6588141cc406Sopenharmony_ci{
6589141cc406Sopenharmony_ci    SANE_Status status;
6590141cc406Sopenharmony_ci    Microtek2_Device *md;
6591141cc406Sopenharmony_ci    uint32_t shading_bytes, linesize, buffer_size;
6592141cc406Sopenharmony_ci    uint8_t *buf;
6593141cc406Sopenharmony_ci    int max_lines, lines_to_read, remaining_lines;
6594141cc406Sopenharmony_ci
6595141cc406Sopenharmony_ci    md = ms->dev;
6596141cc406Sopenharmony_ci
6597141cc406Sopenharmony_ci    shading_bytes = ms->n_control_bytes * 8 * md->shading_length;
6598141cc406Sopenharmony_ci    if ( ms->current_color == MS_COLOR_ALL )
6599141cc406Sopenharmony_ci        shading_bytes *= 3;
6600141cc406Sopenharmony_ci    if ( ms->word == 1 )
6601141cc406Sopenharmony_ci        shading_bytes *= 2;
6602141cc406Sopenharmony_ci
6603141cc406Sopenharmony_ci    if ( ms->shading_image )
6604141cc406Sopenharmony_ci      {
6605141cc406Sopenharmony_ci        free((void *) ms->shading_image);
6606141cc406Sopenharmony_ci        ms->shading_image = NULL;
6607141cc406Sopenharmony_ci      }
6608141cc406Sopenharmony_ci    ms->shading_image = malloc(shading_bytes);
6609141cc406Sopenharmony_ci    DBG(100, "read_cx_shading: ms->shading_image=%p, malloc'd %d bytes\n",
6610141cc406Sopenharmony_ci              (void *) ms->shading_image, shading_bytes);
6611141cc406Sopenharmony_ci    if ( ms->shading_image == NULL )
6612141cc406Sopenharmony_ci      {
6613141cc406Sopenharmony_ci        DBG(1, "read_cx_shading: malloc for cx_shading buffer failed\n");
6614141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
6615141cc406Sopenharmony_ci      }
6616141cc406Sopenharmony_ci
6617141cc406Sopenharmony_ci    buf = ms->shading_image;
6618141cc406Sopenharmony_ci
6619141cc406Sopenharmony_ci    DBG(30, "read_cx_shading_image: ms=%p, shading_bytes=%d\n",
6620141cc406Sopenharmony_ci                                       (void *) ms, shading_bytes);
6621141cc406Sopenharmony_ci
6622141cc406Sopenharmony_ci    linesize = shading_bytes / md->shading_length;
6623141cc406Sopenharmony_ci#ifdef TESTBACKEND
6624141cc406Sopenharmony_ci    max_lines = 5000000 / linesize;
6625141cc406Sopenharmony_ci#else
6626141cc406Sopenharmony_ci    max_lines = sanei_scsi_max_request_size / linesize;
6627141cc406Sopenharmony_ci#endif
6628141cc406Sopenharmony_ci    /* the following part is like in "read_shading_image"  */
6629141cc406Sopenharmony_ci    remaining_lines = md->shading_length;
6630141cc406Sopenharmony_ci    while ( remaining_lines > 0 )
6631141cc406Sopenharmony_ci      {
6632141cc406Sopenharmony_ci        lines_to_read = MIN(max_lines, remaining_lines);
6633141cc406Sopenharmony_ci        buffer_size = lines_to_read * linesize;
6634141cc406Sopenharmony_ci
6635141cc406Sopenharmony_ci        status = scsi_read_shading(ms, buf, buffer_size);
6636141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
6637141cc406Sopenharmony_ci          {
6638141cc406Sopenharmony_ci            DBG(1, "read_cx_shading: '%s'\n", sane_strstatus(status));
6639141cc406Sopenharmony_ci            return status;
6640141cc406Sopenharmony_ci          }
6641141cc406Sopenharmony_ci        remaining_lines -= lines_to_read;
6642141cc406Sopenharmony_ci        buf += buffer_size;
6643141cc406Sopenharmony_ci      }
6644141cc406Sopenharmony_ci
6645141cc406Sopenharmony_ci    status = calc_cx_shading_line(ms);
6646141cc406Sopenharmony_ci    if ( status != SANE_STATUS_GOOD )
6647141cc406Sopenharmony_ci      {
6648141cc406Sopenharmony_ci        DBG(1, "read_cx_shading: '%s'\n", sane_strstatus(status));
6649141cc406Sopenharmony_ci        return status;
6650141cc406Sopenharmony_ci      }
6651141cc406Sopenharmony_ci
6652141cc406Sopenharmony_ci    if ( ms->shading_image )
6653141cc406Sopenharmony_ci      {
6654141cc406Sopenharmony_ci        DBG(100, "free memory for ms->shading_image at %p\n",
6655141cc406Sopenharmony_ci                  (void *) ms->shading_image);
6656141cc406Sopenharmony_ci        free((void *) ms->shading_image);
6657141cc406Sopenharmony_ci        ms->shading_image = NULL;
6658141cc406Sopenharmony_ci      }
6659141cc406Sopenharmony_ci
6660141cc406Sopenharmony_ci    return status;
6661141cc406Sopenharmony_ci}
6662141cc406Sopenharmony_ci
6663141cc406Sopenharmony_ci/*---------- calc_cx_shading_line() ------------------------------------------*/
6664141cc406Sopenharmony_ci/* calculates the mean value of the shading lines and stores one line of      */
6665141cc406Sopenharmony_ci/* 8-bit shading data. Scanning direction + color sequence remain as they are */
6666141cc406Sopenharmony_ci/* ToDo: more than 8-bit data */
6667141cc406Sopenharmony_ci
6668141cc406Sopenharmony_cistatic SANE_Status
6669141cc406Sopenharmony_cicalc_cx_shading_line(Microtek2_Scanner *ms)
6670141cc406Sopenharmony_ci{
6671141cc406Sopenharmony_ci    Microtek2_Device *md;
6672141cc406Sopenharmony_ci    SANE_Status status;
6673141cc406Sopenharmony_ci    uint8_t *current_byte, *buf, *shading_table_pointer;
6674141cc406Sopenharmony_ci    uint8_t color, factor;
6675141cc406Sopenharmony_ci    uint32_t shading_line_pixels, shading_line_bytes,
6676141cc406Sopenharmony_ci              shading_data_bytes, line, i, accu, color_offset;
6677141cc406Sopenharmony_ci    uint16_t *sortbuf, value;
6678141cc406Sopenharmony_ci
6679141cc406Sopenharmony_ci    md = ms->dev;
6680141cc406Sopenharmony_ci    status = SANE_STATUS_GOOD;
6681141cc406Sopenharmony_ci
6682141cc406Sopenharmony_ci    sortbuf = malloc( md->shading_length * sizeof(float) );
6683141cc406Sopenharmony_ci    DBG(100, "calc_cx_shading: sortbuf= %p, malloc'd %lu Bytes\n",
6684141cc406Sopenharmony_ci	(void *) sortbuf, (u_long) (md->shading_length * sizeof(float)));
6685141cc406Sopenharmony_ci    if ( sortbuf == NULL )
6686141cc406Sopenharmony_ci      {
6687141cc406Sopenharmony_ci        DBG(1, "calc_cx_shading: malloc for sort buffer failed\n");
6688141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
6689141cc406Sopenharmony_ci      }
6690141cc406Sopenharmony_ci
6691141cc406Sopenharmony_ci    buf = ms->shading_image;
6692141cc406Sopenharmony_ci    shading_line_pixels = ms->n_control_bytes * 8; /* = 2560 for 330CX  */
6693141cc406Sopenharmony_ci    shading_line_bytes = shading_line_pixels;      /* grayscale         */
6694141cc406Sopenharmony_ci    if ( ms->mode == MS_MODE_COLOR )               /* color             */
6695141cc406Sopenharmony_ci        shading_line_bytes *= 3;
6696141cc406Sopenharmony_ci    shading_data_bytes = shading_line_bytes;      /*    8-bit color depth */
6697141cc406Sopenharmony_ci    if (ms->word == 1)                            /* >  8-bit color depth */
6698141cc406Sopenharmony_ci        shading_data_bytes *= 2;
6699141cc406Sopenharmony_ci    factor = 4; /* shading bit depth = 10bit; shading line bit depth = 8bit */
6700141cc406Sopenharmony_ci
6701141cc406Sopenharmony_ci    if (ms->dark == 0)  /* white shading data  */
6702141cc406Sopenharmony_ci      {
6703141cc406Sopenharmony_ci        if ( md->shading_table_w )
6704141cc406Sopenharmony_ci            free( (void *)md->shading_table_w );
6705141cc406Sopenharmony_ci        md->shading_table_w = (uint8_t *) malloc(shading_line_bytes);
6706141cc406Sopenharmony_ci        DBG(100, "calc_cx_shading: md->shading_table_w=%p, malloc'd %d bytes\n",
6707141cc406Sopenharmony_ci                  (void *) md->shading_table_w, shading_line_bytes);
6708141cc406Sopenharmony_ci        if ( md->shading_table_w == NULL )
6709141cc406Sopenharmony_ci          {
6710141cc406Sopenharmony_ci            DBG(100, "calc_cx_shading: malloc for white shadingtable failed\n");
6711141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
6712141cc406Sopenharmony_ci            cleanup_scanner(ms);
6713141cc406Sopenharmony_ci          }
6714141cc406Sopenharmony_ci
6715141cc406Sopenharmony_ci        shading_table_pointer = md->shading_table_w;
6716141cc406Sopenharmony_ci      }
6717141cc406Sopenharmony_ci
6718141cc406Sopenharmony_ci    else               /*  dark  shading data  */
6719141cc406Sopenharmony_ci      {
6720141cc406Sopenharmony_ci        if ( md->shading_table_d )
6721141cc406Sopenharmony_ci            free( (void *)md->shading_table_d);
6722141cc406Sopenharmony_ci        md->shading_table_d = (uint8_t *) malloc(shading_line_bytes);
6723141cc406Sopenharmony_ci        DBG(100, "calc_cx_shading: md->shading_table_d=%p, malloc'd %d bytes\n",
6724141cc406Sopenharmony_ci                  (void *) md->shading_table_d, shading_line_bytes);
6725141cc406Sopenharmony_ci
6726141cc406Sopenharmony_ci        if ( md->shading_table_d == NULL )
6727141cc406Sopenharmony_ci          {
6728141cc406Sopenharmony_ci            DBG(1, "calc_cx_shading: malloc for dark shading table failed\n");
6729141cc406Sopenharmony_ci            status = SANE_STATUS_NO_MEM;
6730141cc406Sopenharmony_ci            cleanup_scanner(ms);
6731141cc406Sopenharmony_ci          }
6732141cc406Sopenharmony_ci
6733141cc406Sopenharmony_ci        shading_table_pointer = md->shading_table_d;
6734141cc406Sopenharmony_ci      }
6735141cc406Sopenharmony_ci
6736141cc406Sopenharmony_ci    DBG(30, "calc_cx_shading_line: ms=%p\n"
6737141cc406Sopenharmony_ci            "md->shading_table_w=%p\n"
6738141cc406Sopenharmony_ci            "md->shading_table_d=%p\n"
6739141cc406Sopenharmony_ci            "shading_line_bytes=%d\n"
6740141cc406Sopenharmony_ci            "shading_line_pixels=%d\n"
6741141cc406Sopenharmony_ci            "shading_table_pointer=%p\n",
6742141cc406Sopenharmony_ci             (void *) ms, (void *) md->shading_table_w,
6743141cc406Sopenharmony_ci             (void *) md->shading_table_d, shading_line_bytes,
6744141cc406Sopenharmony_ci             shading_line_pixels, (void *) shading_table_pointer);
6745141cc406Sopenharmony_ci
6746141cc406Sopenharmony_ci    /*  calculating the median pixel values over the shading lines  */
6747141cc406Sopenharmony_ci    /*  and write them to the shading table                       */
6748141cc406Sopenharmony_ci    for (color = 0; color < 3; color++)
6749141cc406Sopenharmony_ci      {
6750141cc406Sopenharmony_ci        color_offset = color * shading_line_pixels;
6751141cc406Sopenharmony_ci        if ( ms->word == 1 )
6752141cc406Sopenharmony_ci          color_offset *=2;
6753141cc406Sopenharmony_ci
6754141cc406Sopenharmony_ci        for (i = 0; i < shading_line_pixels; i++)
6755141cc406Sopenharmony_ci          {
6756141cc406Sopenharmony_ci            value = 0;
6757141cc406Sopenharmony_ci            for (line = 0; line < md->shading_length; line++)
6758141cc406Sopenharmony_ci              {
6759141cc406Sopenharmony_ci                current_byte = buf + ( line * shading_data_bytes )
6760141cc406Sopenharmony_ci                               + color_offset + i;
6761141cc406Sopenharmony_ci                accu = *current_byte;
6762141cc406Sopenharmony_ci
6763141cc406Sopenharmony_ci                /* word shading data: the lower bytes per line and color are */
6764141cc406Sopenharmony_ci                /* transferred first in one block and then the high bytes */
6765141cc406Sopenharmony_ci                /* in one block  */
6766141cc406Sopenharmony_ci                /* the dark shading data is also 10 bit, but only the */
6767141cc406Sopenharmony_ci                /* low byte is transferred (ms->word = 0) */
6768141cc406Sopenharmony_ci                if ( ms->word == 1 )
6769141cc406Sopenharmony_ci                  {
6770141cc406Sopenharmony_ci                    current_byte = buf + ( line * shading_data_bytes )
6771141cc406Sopenharmony_ci                               + color_offset + shading_line_pixels + i;
6772141cc406Sopenharmony_ci                    accu += ( *current_byte * 256 );
6773141cc406Sopenharmony_ci                  }
6774141cc406Sopenharmony_ci                *( sortbuf + line ) = accu;
6775141cc406Sopenharmony_ci              }
6776141cc406Sopenharmony_ci/* this is the Median filter: sort the values ascending and take the middlest */
6777141cc406Sopenharmony_ci            qsort(sortbuf, md->shading_length, sizeof(float),
6778141cc406Sopenharmony_ci                     (qsortfunc)compare_func_16);
6779141cc406Sopenharmony_ci            value = *( sortbuf + ( md->shading_length - 1 ) / 2 );
6780141cc406Sopenharmony_ci            *shading_table_pointer = (uint8_t) (value / factor);
6781141cc406Sopenharmony_ci            shading_table_pointer++;
6782141cc406Sopenharmony_ci          }
6783141cc406Sopenharmony_ci        if ( ms->mode != MS_MODE_COLOR )
6784141cc406Sopenharmony_ci           break;
6785141cc406Sopenharmony_ci      }
6786141cc406Sopenharmony_ci    return status;
6787141cc406Sopenharmony_ci}
6788141cc406Sopenharmony_ci
6789141cc406Sopenharmony_ci
6790141cc406Sopenharmony_ci
6791141cc406Sopenharmony_ci/*---------- get_lut_size() --------------------------------------------------*/
6792141cc406Sopenharmony_ci
6793141cc406Sopenharmony_cistatic SANE_Status
6794141cc406Sopenharmony_ciget_lut_size(Microtek2_Info *mi, int *max_lut_size, int *lut_entry_size)
6795141cc406Sopenharmony_ci{
6796141cc406Sopenharmony_ci    /* returns the maximum lookup table size. A device might indicate */
6797141cc406Sopenharmony_ci    /* several lookup table sizes. */
6798141cc406Sopenharmony_ci
6799141cc406Sopenharmony_ci    DBG(30, "get_lut_size: mi=%p\n", (void *) mi);
6800141cc406Sopenharmony_ci
6801141cc406Sopenharmony_ci    *max_lut_size = 0;
6802141cc406Sopenharmony_ci    *lut_entry_size = 0;
6803141cc406Sopenharmony_ci
6804141cc406Sopenharmony_ci    /* Normally this function is used for both gamma and shading tables */
6805141cc406Sopenharmony_ci    /* If, however, the device indicates, that it does not support */
6806141cc406Sopenharmony_ci    /* lookup tables, we set these values as if the device has a maximum */
6807141cc406Sopenharmony_ci    /* bitdepth of 12, and these values are only used to determine the */
6808141cc406Sopenharmony_ci    /* size of the shading table */
6809141cc406Sopenharmony_ci    if ( MI_LUTCAP_NONE(mi->lut_cap) )
6810141cc406Sopenharmony_ci      {
6811141cc406Sopenharmony_ci        *max_lut_size = 4096;
6812141cc406Sopenharmony_ci        *lut_entry_size = 2;
6813141cc406Sopenharmony_ci      }
6814141cc406Sopenharmony_ci
6815141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_256B )
6816141cc406Sopenharmony_ci      {
6817141cc406Sopenharmony_ci        *max_lut_size = 256;
6818141cc406Sopenharmony_ci        *lut_entry_size = 1;
6819141cc406Sopenharmony_ci      }
6820141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_1024B )
6821141cc406Sopenharmony_ci      {
6822141cc406Sopenharmony_ci        *max_lut_size = 1024;
6823141cc406Sopenharmony_ci        *lut_entry_size = 1;
6824141cc406Sopenharmony_ci      }
6825141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_1024W )
6826141cc406Sopenharmony_ci      {
6827141cc406Sopenharmony_ci        *max_lut_size = 1024;
6828141cc406Sopenharmony_ci        *lut_entry_size = 2;
6829141cc406Sopenharmony_ci      }
6830141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_4096B )
6831141cc406Sopenharmony_ci      {
6832141cc406Sopenharmony_ci        *max_lut_size = 4096;
6833141cc406Sopenharmony_ci        *lut_entry_size = 1;
6834141cc406Sopenharmony_ci      }
6835141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_4096W )
6836141cc406Sopenharmony_ci      {
6837141cc406Sopenharmony_ci          *max_lut_size = 4096;
6838141cc406Sopenharmony_ci          *lut_entry_size = 2;
6839141cc406Sopenharmony_ci      }
6840141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_64k_W )
6841141cc406Sopenharmony_ci      {
6842141cc406Sopenharmony_ci          *max_lut_size = 65536;
6843141cc406Sopenharmony_ci          *lut_entry_size = 2;
6844141cc406Sopenharmony_ci      }
6845141cc406Sopenharmony_ci    if ( mi->lut_cap & MI_LUTCAP_16k_W )
6846141cc406Sopenharmony_ci      {
6847141cc406Sopenharmony_ci          *max_lut_size = 16384;
6848141cc406Sopenharmony_ci          *lut_entry_size = 2;
6849141cc406Sopenharmony_ci      }
6850141cc406Sopenharmony_ci    DBG(30, "get_lut_size:  mi=%p, lut_size=%d, lut_entry_size=%d\n",
6851141cc406Sopenharmony_ci             (void *) mi, *max_lut_size, *lut_entry_size);
6852141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6853141cc406Sopenharmony_ci}
6854141cc406Sopenharmony_ci
6855141cc406Sopenharmony_ci
6856141cc406Sopenharmony_ci/*---------- calculate_gamma() -----------------------------------------------*/
6857141cc406Sopenharmony_ci
6858141cc406Sopenharmony_cistatic SANE_Status
6859141cc406Sopenharmony_cicalculate_gamma(Microtek2_Scanner *ms, uint8_t *pos, int color, char *mode)
6860141cc406Sopenharmony_ci{
6861141cc406Sopenharmony_ci    Microtek2_Device *md;
6862141cc406Sopenharmony_ci    Microtek2_Info *mi;
6863141cc406Sopenharmony_ci    double exp;
6864141cc406Sopenharmony_ci    double mult;
6865141cc406Sopenharmony_ci    double steps;
6866141cc406Sopenharmony_ci    unsigned int val;
6867141cc406Sopenharmony_ci    int i;
6868141cc406Sopenharmony_ci    int factor;           /* take into account the differences between the */
6869141cc406Sopenharmony_ci                          /* possible values for the color and the number */
6870141cc406Sopenharmony_ci                          /* of bits the scanner works with internally. */
6871141cc406Sopenharmony_ci                          /* If depth == 1 handle this as if the maximum */
6872141cc406Sopenharmony_ci                          /* depth was chosen */
6873141cc406Sopenharmony_ci
6874141cc406Sopenharmony_ci
6875141cc406Sopenharmony_ci    DBG(30, "calculate_gamma: ms=%p, pos=%p, color=%d, mode=%s\n",
6876141cc406Sopenharmony_ci             (void *) ms, (void *) pos, color, mode);
6877141cc406Sopenharmony_ci
6878141cc406Sopenharmony_ci    md = ms->dev;
6879141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
6880141cc406Sopenharmony_ci
6881141cc406Sopenharmony_ci    /* does this work everywhere ? */
6882141cc406Sopenharmony_ci    if ( md->model_flags & MD_NO_GAMMA )
6883141cc406Sopenharmony_ci      {
6884141cc406Sopenharmony_ci        factor = 1;
6885141cc406Sopenharmony_ci        mult = (double) (ms->lut_size - 1);
6886141cc406Sopenharmony_ci      }
6887141cc406Sopenharmony_ci    else
6888141cc406Sopenharmony_ci      {
6889141cc406Sopenharmony_ci        if ( mi->depth & MI_HASDEPTH_16 )
6890141cc406Sopenharmony_ci          {
6891141cc406Sopenharmony_ci            factor = ms->lut_size / 65536;
6892141cc406Sopenharmony_ci            mult = 65535.0;
6893141cc406Sopenharmony_ci          }
6894141cc406Sopenharmony_ci        else if ( mi->depth & MI_HASDEPTH_14 )
6895141cc406Sopenharmony_ci          {
6896141cc406Sopenharmony_ci            factor = ms->lut_size / 16384;
6897141cc406Sopenharmony_ci            mult = 16383.0;
6898141cc406Sopenharmony_ci          }
6899141cc406Sopenharmony_ci        else if ( mi->depth & MI_HASDEPTH_12 )
6900141cc406Sopenharmony_ci          {
6901141cc406Sopenharmony_ci            factor = ms->lut_size / 4096;
6902141cc406Sopenharmony_ci            mult = 4095.0;
6903141cc406Sopenharmony_ci          }
6904141cc406Sopenharmony_ci        else if ( mi->depth & MI_HASDEPTH_10 )
6905141cc406Sopenharmony_ci          {
6906141cc406Sopenharmony_ci            factor = ms->lut_size / 1024;
6907141cc406Sopenharmony_ci            mult = 1023.0;
6908141cc406Sopenharmony_ci          }
6909141cc406Sopenharmony_ci        else
6910141cc406Sopenharmony_ci          {
6911141cc406Sopenharmony_ci            factor = ms->lut_size / 256;
6912141cc406Sopenharmony_ci            mult = 255.0;
6913141cc406Sopenharmony_ci          }
6914141cc406Sopenharmony_ci      }
6915141cc406Sopenharmony_ci
6916141cc406Sopenharmony_ci#if 0
6917141cc406Sopenharmony_ci    factor = ms->lut_size / (int) pow(2.0, (double) ms->depth);
6918141cc406Sopenharmony_ci    mult = pow(2.0, (double) ms->depth) - 1.0;  /* depending on output size */
6919141cc406Sopenharmony_ci#endif
6920141cc406Sopenharmony_ci
6921141cc406Sopenharmony_ci    steps = (double) (ms->lut_size - 1);      /* depending on input size */
6922141cc406Sopenharmony_ci
6923141cc406Sopenharmony_ci    DBG(30, "calculate_gamma: factor=%d, mult =%f, steps=%f, mode=%s\n",
6924141cc406Sopenharmony_ci             factor, mult, steps, ms->val[OPT_GAMMA_MODE].s);
6925141cc406Sopenharmony_ci
6926141cc406Sopenharmony_ci
6927141cc406Sopenharmony_ci    if ( strcmp(mode, MD_GAMMAMODE_SCALAR) == 0 )
6928141cc406Sopenharmony_ci      {
6929141cc406Sopenharmony_ci        int option;
6930141cc406Sopenharmony_ci
6931141cc406Sopenharmony_ci        option = OPT_GAMMA_SCALAR;
6932141cc406Sopenharmony_ci        /* OPT_GAMMA_SCALAR_R follows OPT_GAMMA_SCALAR directly */
6933141cc406Sopenharmony_ci        if ( ms->val[OPT_GAMMA_BIND].w == SANE_TRUE )
6934141cc406Sopenharmony_ci            exp = 1.0 / SANE_UNFIX(ms->val[option].w);
6935141cc406Sopenharmony_ci        else
6936141cc406Sopenharmony_ci            exp = 1.0 / SANE_UNFIX(ms->val[option + color + 1].w);
6937141cc406Sopenharmony_ci
6938141cc406Sopenharmony_ci        for ( i = 0; i < ms->lut_size; i++ )
6939141cc406Sopenharmony_ci          {
6940141cc406Sopenharmony_ci            val = (unsigned int) (mult * pow((double) i / steps, exp) + .5);
6941141cc406Sopenharmony_ci
6942141cc406Sopenharmony_ci            if ( ms->lut_entry_size == 2 )
6943141cc406Sopenharmony_ci                *((uint16_t *) pos + i) = (uint16_t) val;
6944141cc406Sopenharmony_ci            else
6945141cc406Sopenharmony_ci                *((uint8_t *) pos + i) = (uint8_t) val;
6946141cc406Sopenharmony_ci          }
6947141cc406Sopenharmony_ci      }
6948141cc406Sopenharmony_ci    else if ( strcmp(mode, MD_GAMMAMODE_CUSTOM) == 0 )
6949141cc406Sopenharmony_ci      {
6950141cc406Sopenharmony_ci        int option;
6951141cc406Sopenharmony_ci        SANE_Int *src;
6952141cc406Sopenharmony_ci
6953141cc406Sopenharmony_ci        option = OPT_GAMMA_CUSTOM;
6954141cc406Sopenharmony_ci        if ( ms->val[OPT_GAMMA_BIND].w == SANE_TRUE )
6955141cc406Sopenharmony_ci            src = ms->val[option].wa;
6956141cc406Sopenharmony_ci        else
6957141cc406Sopenharmony_ci            src = ms->val[option + color + 1].wa;
6958141cc406Sopenharmony_ci
6959141cc406Sopenharmony_ci        for ( i = 0; i < ms->lut_size; i++ )
6960141cc406Sopenharmony_ci          {
6961141cc406Sopenharmony_ci            if ( ms->lut_entry_size == 2 )
6962141cc406Sopenharmony_ci                *((uint16_t *) pos + i) = (uint16_t) (src[i] / factor);
6963141cc406Sopenharmony_ci            else
6964141cc406Sopenharmony_ci                *((uint8_t *) pos + i) = (uint8_t) (src[i] / factor);
6965141cc406Sopenharmony_ci          }
6966141cc406Sopenharmony_ci      }
6967141cc406Sopenharmony_ci    else if ( strcmp(mode, MD_GAMMAMODE_LINEAR) == 0 )
6968141cc406Sopenharmony_ci      {
6969141cc406Sopenharmony_ci        for ( i = 0; i < ms->lut_size; i++ )
6970141cc406Sopenharmony_ci          {
6971141cc406Sopenharmony_ci            if ( ms->lut_entry_size == 2 )
6972141cc406Sopenharmony_ci                *((uint16_t *) pos + i) = (uint16_t) (i / factor);
6973141cc406Sopenharmony_ci            else
6974141cc406Sopenharmony_ci                *((uint8_t *) pos + i) = (uint8_t) (i / factor);
6975141cc406Sopenharmony_ci          }
6976141cc406Sopenharmony_ci      }
6977141cc406Sopenharmony_ci
6978141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
6979141cc406Sopenharmony_ci}
6980141cc406Sopenharmony_ci
6981141cc406Sopenharmony_ci
6982141cc406Sopenharmony_ci/*---------- shading_function() ----------------------------------------------*/
6983141cc406Sopenharmony_ci
6984141cc406Sopenharmony_cistatic SANE_Status
6985141cc406Sopenharmony_cishading_function(Microtek2_Scanner *ms, uint8_t *data)
6986141cc406Sopenharmony_ci{
6987141cc406Sopenharmony_ci    Microtek2_Device *md;
6988141cc406Sopenharmony_ci    Microtek2_Info *mi;
6989141cc406Sopenharmony_ci    uint32_t value;
6990141cc406Sopenharmony_ci    int color;
6991141cc406Sopenharmony_ci    int i;
6992141cc406Sopenharmony_ci
6993141cc406Sopenharmony_ci
6994141cc406Sopenharmony_ci    DBG(40, "shading_function: ms=%p, data=%p\n", (void *) ms, (void *) data);
6995141cc406Sopenharmony_ci
6996141cc406Sopenharmony_ci    md = ms->dev;
6997141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
6998141cc406Sopenharmony_ci/*    mi = &md->info[MD_SOURCE_FLATBED]; */
6999141cc406Sopenharmony_ci
7000141cc406Sopenharmony_ci    if ( ms->lut_entry_size == 1 )
7001141cc406Sopenharmony_ci      {
7002141cc406Sopenharmony_ci        DBG(1, "shading_function: wordsize = 1 unsupported\n");
7003141cc406Sopenharmony_ci         return SANE_STATUS_IO_ERROR;
7004141cc406Sopenharmony_ci      }
7005141cc406Sopenharmony_ci
7006141cc406Sopenharmony_ci    for ( color = 0; color < 3; color++ )
7007141cc406Sopenharmony_ci      {
7008141cc406Sopenharmony_ci        for ( i = 0; i < ( mi->geo_width / mi->calib_divisor ); i++)
7009141cc406Sopenharmony_ci          {
7010141cc406Sopenharmony_ci            value = *((uint16_t *) data
7011141cc406Sopenharmony_ci                      + color * ( mi->geo_width / mi->calib_divisor ) + i);
7012141cc406Sopenharmony_ci            switch ( mi->shtrnsferequ )
7013141cc406Sopenharmony_ci              {
7014141cc406Sopenharmony_ci                case 0x00:
7015141cc406Sopenharmony_ci                  /* output == input */
7016141cc406Sopenharmony_ci                  break;
7017141cc406Sopenharmony_ci
7018141cc406Sopenharmony_ci                case 0x01:
7019141cc406Sopenharmony_ci                  value = (ms->lut_size * ms->lut_size) / value;
7020141cc406Sopenharmony_ci                  *((uint16_t *) data
7021141cc406Sopenharmony_ci                    + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7022141cc406Sopenharmony_ci                                               (uint16_t) MIN(0xffff, value);
7023141cc406Sopenharmony_ci                  break;
7024141cc406Sopenharmony_ci
7025141cc406Sopenharmony_ci                case 0x11:
7026141cc406Sopenharmony_ci                  value = (ms->lut_size * ms->lut_size)
7027141cc406Sopenharmony_ci                           / (uint32_t) ( (double) value
7028141cc406Sopenharmony_ci                                           * ((double) mi->balance[color]
7029141cc406Sopenharmony_ci                                             / 255.0));
7030141cc406Sopenharmony_ci                  *((uint16_t *) data
7031141cc406Sopenharmony_ci                    + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7032141cc406Sopenharmony_ci                                               (uint16_t) MIN(0xffff, value);
7033141cc406Sopenharmony_ci                  break;
7034141cc406Sopenharmony_ci                case 0x15:
7035141cc406Sopenharmony_ci                  value = (uint32_t) ( ( 1073741824 / (double) value )
7036141cc406Sopenharmony_ci                                           * ( (double) mi->balance[color]
7037141cc406Sopenharmony_ci                                            / 256.0) );
7038141cc406Sopenharmony_ci                  value = MIN(value, (uint32_t)65535);
7039141cc406Sopenharmony_ci                 *((uint16_t *) data
7040141cc406Sopenharmony_ci                    + color * ( mi->geo_width / mi->calib_divisor ) + i) =
7041141cc406Sopenharmony_ci                                               (uint16_t) MIN(0xffff, value);
7042141cc406Sopenharmony_ci                  break;
7043141cc406Sopenharmony_ci
7044141cc406Sopenharmony_ci                default:
7045141cc406Sopenharmony_ci                  DBG(1, "Unsupported shading transfer function 0x%02x\n",
7046141cc406Sopenharmony_ci                  mi->shtrnsferequ );
7047141cc406Sopenharmony_ci                  break;
7048141cc406Sopenharmony_ci              }
7049141cc406Sopenharmony_ci          }
7050141cc406Sopenharmony_ci      }
7051141cc406Sopenharmony_ci
7052141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7053141cc406Sopenharmony_ci}
7054141cc406Sopenharmony_ci
7055141cc406Sopenharmony_ci
7056141cc406Sopenharmony_ci/*---------- set_exposure() --------------------------------------------------*/
7057141cc406Sopenharmony_ci
7058141cc406Sopenharmony_cistatic void
7059141cc406Sopenharmony_ciset_exposure(Microtek2_Scanner *ms)
7060141cc406Sopenharmony_ci{
7061141cc406Sopenharmony_ci    /* This function manipulates the colors according to the exposure time */
7062141cc406Sopenharmony_ci    /* settings on models where they are ignored. Currently this seems to */
7063141cc406Sopenharmony_ci    /* be the case for all models with the data format chunky data. They */
7064141cc406Sopenharmony_ci    /* all have tables with two byte gamma output, so for now we ignore */
7065141cc406Sopenharmony_ci    /* gamma tables with one byte output */
7066141cc406Sopenharmony_ci
7067141cc406Sopenharmony_ci    Microtek2_Device *md;
7068141cc406Sopenharmony_ci    Microtek2_Info *mi;
7069141cc406Sopenharmony_ci    int color;
7070141cc406Sopenharmony_ci    int size;
7071141cc406Sopenharmony_ci    int depth;
7072141cc406Sopenharmony_ci    int maxval;
7073141cc406Sopenharmony_ci    int byte;
7074141cc406Sopenharmony_ci    uint32_t val32;
7075141cc406Sopenharmony_ci    uint8_t *from;
7076141cc406Sopenharmony_ci    uint8_t exposure;
7077141cc406Sopenharmony_ci    uint8_t exposure_rgb[3];
7078141cc406Sopenharmony_ci
7079141cc406Sopenharmony_ci
7080141cc406Sopenharmony_ci    DBG(30, "set_exposure: ms=%p\n", (void *) ms);
7081141cc406Sopenharmony_ci
7082141cc406Sopenharmony_ci    md = ms->dev;
7083141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7084141cc406Sopenharmony_ci
7085141cc406Sopenharmony_ci    if ( ms->lut_entry_size == 1 )
7086141cc406Sopenharmony_ci      {
7087141cc406Sopenharmony_ci        DBG(1, "set_exposure: 1 byte gamma output tables currently ignored\n");
7088141cc406Sopenharmony_ci        return;
7089141cc406Sopenharmony_ci      }
7090141cc406Sopenharmony_ci
7091141cc406Sopenharmony_ci    if ( mi->depth & MI_HASDEPTH_16 )
7092141cc406Sopenharmony_ci        depth = 16;
7093141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_14 )
7094141cc406Sopenharmony_ci        depth = 14;
7095141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_12 )
7096141cc406Sopenharmony_ci        depth = 12;
7097141cc406Sopenharmony_ci    else if ( mi->depth & MI_HASDEPTH_10 )
7098141cc406Sopenharmony_ci        depth = 10;
7099141cc406Sopenharmony_ci    else
7100141cc406Sopenharmony_ci        depth = 8;
7101141cc406Sopenharmony_ci
7102141cc406Sopenharmony_ci    maxval = ( 1 << depth ) - 1;
7103141cc406Sopenharmony_ci
7104141cc406Sopenharmony_ci    from = ms->gamma_table;
7105141cc406Sopenharmony_ci    size = ms->lut_size;
7106141cc406Sopenharmony_ci
7107141cc406Sopenharmony_ci    /* first master channel, apply transformation to all colors */
7108141cc406Sopenharmony_ci    exposure = ms->exposure_m;
7109141cc406Sopenharmony_ci    for ( byte = 0; byte < ms->lut_size; byte++ )
7110141cc406Sopenharmony_ci      {
7111141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++)
7112141cc406Sopenharmony_ci          {
7113141cc406Sopenharmony_ci            val32 = (uint32_t) *((uint16_t *) from + color * size + byte);
7114141cc406Sopenharmony_ci            val32 = MIN(val32 + val32
7115141cc406Sopenharmony_ci                     * (2 * (uint32_t) exposure / 100), (uint32_t) maxval);
7116141cc406Sopenharmony_ci            *((uint16_t *) from + color * size + byte) = (uint16_t) val32;
7117141cc406Sopenharmony_ci          }
7118141cc406Sopenharmony_ci      }
7119141cc406Sopenharmony_ci
7120141cc406Sopenharmony_ci    /* and now apply transformation to each channel */
7121141cc406Sopenharmony_ci
7122141cc406Sopenharmony_ci    exposure_rgb[0] = ms->exposure_r;
7123141cc406Sopenharmony_ci    exposure_rgb[1] = ms->exposure_g;
7124141cc406Sopenharmony_ci    exposure_rgb[2] = ms->exposure_b;
7125141cc406Sopenharmony_ci    for ( color = 0; color < 3; color++ )
7126141cc406Sopenharmony_ci      {
7127141cc406Sopenharmony_ci        for ( byte = 0; byte < size; byte++ )
7128141cc406Sopenharmony_ci          {
7129141cc406Sopenharmony_ci            val32 = (uint32_t) *((uint16_t *) from + color * size + byte);
7130141cc406Sopenharmony_ci            val32 = MIN(val32 + val32
7131141cc406Sopenharmony_ci                         * (2 * (uint32_t) exposure_rgb[color] / 100),
7132141cc406Sopenharmony_ci                         (uint32_t) maxval);
7133141cc406Sopenharmony_ci            *((uint16_t *) from + color * size + byte) = (uint16_t) val32;
7134141cc406Sopenharmony_ci          }
7135141cc406Sopenharmony_ci      }
7136141cc406Sopenharmony_ci
7137141cc406Sopenharmony_ci    return;
7138141cc406Sopenharmony_ci}
7139141cc406Sopenharmony_ci
7140141cc406Sopenharmony_ci
7141141cc406Sopenharmony_ci/*---------- reader_process() ------------------------------------------------*/
7142141cc406Sopenharmony_ci
7143141cc406Sopenharmony_cistatic int
7144141cc406Sopenharmony_cireader_process(void *data)
7145141cc406Sopenharmony_ci{
7146141cc406Sopenharmony_ci    Microtek2_Scanner *ms = (Microtek2_Scanner *) data;
7147141cc406Sopenharmony_ci
7148141cc406Sopenharmony_ci    SANE_Status status;
7149141cc406Sopenharmony_ci    Microtek2_Info *mi;
7150141cc406Sopenharmony_ci    Microtek2_Device *md;
7151141cc406Sopenharmony_ci    struct SIGACTION act;
7152141cc406Sopenharmony_ci    sigset_t sigterm_set;
7153141cc406Sopenharmony_ci    static uint8_t *temp_current = NULL;
7154141cc406Sopenharmony_ci
7155141cc406Sopenharmony_ci    DBG(30, "reader_process: ms=%p\n", (void *) ms);
7156141cc406Sopenharmony_ci
7157141cc406Sopenharmony_ci    md = ms->dev;
7158141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7159141cc406Sopenharmony_ci
7160141cc406Sopenharmony_ci    if (sanei_thread_is_forked()) close(ms->fd[0]);
7161141cc406Sopenharmony_ci
7162141cc406Sopenharmony_ci    sigemptyset (&sigterm_set);
7163141cc406Sopenharmony_ci    sigaddset (&sigterm_set, SIGTERM);
7164141cc406Sopenharmony_ci    memset (&act, 0, sizeof (act));
7165141cc406Sopenharmony_ci    act.sa_handler = signal_handler;
7166141cc406Sopenharmony_ci    sigaction (SIGTERM, &act, 0);
7167141cc406Sopenharmony_ci
7168141cc406Sopenharmony_ci    ms->fp = fdopen(ms->fd[1], "w");
7169141cc406Sopenharmony_ci    if ( ms->fp == NULL )
7170141cc406Sopenharmony_ci      {
7171141cc406Sopenharmony_ci        DBG(1, "reader_process: fdopen() failed, errno=%d\n", errno);
7172141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
7173141cc406Sopenharmony_ci      }
7174141cc406Sopenharmony_ci
7175141cc406Sopenharmony_ci    if ( ms->auto_adjust == 1 )
7176141cc406Sopenharmony_ci      {
7177141cc406Sopenharmony_ci        if ( temp_current == NULL )
7178141cc406Sopenharmony_ci            temp_current = ms->temporary_buffer;
7179141cc406Sopenharmony_ci      }
7180141cc406Sopenharmony_ci
7181141cc406Sopenharmony_ci    while ( ms->src_remaining_lines > 0 )
7182141cc406Sopenharmony_ci      {
7183141cc406Sopenharmony_ci
7184141cc406Sopenharmony_ci        ms->src_lines_to_read = MIN(ms->src_remaining_lines, ms->src_max_lines);
7185141cc406Sopenharmony_ci        ms->transfer_length = ms->src_lines_to_read * ms->bpl;
7186141cc406Sopenharmony_ci
7187141cc406Sopenharmony_ci        DBG(30, "reader_process: transferlength=%d, lines=%d, linelength=%d, "
7188141cc406Sopenharmony_ci                "real_bpl=%d, srcbuf=%p\n",
7189141cc406Sopenharmony_ci                 ms->transfer_length, ms->src_lines_to_read, ms->bpl,
7190141cc406Sopenharmony_ci                 ms->real_bpl, (void *) ms->buf.src_buf);
7191141cc406Sopenharmony_ci
7192141cc406Sopenharmony_ci        sigprocmask (SIG_BLOCK, &sigterm_set, 0);
7193141cc406Sopenharmony_ci        status = scsi_read_image(ms, ms->buf.src_buf, (ms->depth > 8) ? 2 : 1);
7194141cc406Sopenharmony_ci        sigprocmask (SIG_UNBLOCK, &sigterm_set, 0);
7195141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7196141cc406Sopenharmony_ci            return SANE_STATUS_IO_ERROR;
7197141cc406Sopenharmony_ci
7198141cc406Sopenharmony_ci        ms->src_remaining_lines -= ms->src_lines_to_read;
7199141cc406Sopenharmony_ci
7200141cc406Sopenharmony_ci        /* prepare data for frontend */
7201141cc406Sopenharmony_ci        switch (ms->mode)
7202141cc406Sopenharmony_ci          {
7203141cc406Sopenharmony_ci	    case MS_MODE_COLOR:
7204141cc406Sopenharmony_ci              if ( ! mi->onepass )
7205141cc406Sopenharmony_ci                /* TODO */
7206141cc406Sopenharmony_ci                {
7207141cc406Sopenharmony_ci                  DBG(1, "reader_process: 3 pass not yet supported\n");
7208141cc406Sopenharmony_ci                  return SANE_STATUS_IO_ERROR;
7209141cc406Sopenharmony_ci                }
7210141cc406Sopenharmony_ci              else
7211141cc406Sopenharmony_ci                {
7212141cc406Sopenharmony_ci                  switch ( mi->data_format )
7213141cc406Sopenharmony_ci                    {
7214141cc406Sopenharmony_ci		      case MI_DATAFMT_CHUNKY:
7215141cc406Sopenharmony_ci		      case MI_DATAFMT_9800:
7216141cc406Sopenharmony_ci                        status = chunky_proc_data(ms);
7217141cc406Sopenharmony_ci                        if ( status != SANE_STATUS_GOOD )
7218141cc406Sopenharmony_ci                            return status;
7219141cc406Sopenharmony_ci                        break;
7220141cc406Sopenharmony_ci		      case MI_DATAFMT_LPLCONCAT:
7221141cc406Sopenharmony_ci			status = lplconcat_proc_data(ms);
7222141cc406Sopenharmony_ci                        if ( status != SANE_STATUS_GOOD )
7223141cc406Sopenharmony_ci                            return status;
7224141cc406Sopenharmony_ci                        break;
7225141cc406Sopenharmony_ci		      case MI_DATAFMT_LPLSEGREG:
7226141cc406Sopenharmony_ci			status = segreg_proc_data(ms);
7227141cc406Sopenharmony_ci                        if ( status != SANE_STATUS_GOOD )
7228141cc406Sopenharmony_ci                            return status;
7229141cc406Sopenharmony_ci                        break;
7230141cc406Sopenharmony_ci		      case MI_DATAFMT_WORDCHUNKY:
7231141cc406Sopenharmony_ci                        status = wordchunky_proc_data(ms);
7232141cc406Sopenharmony_ci                        if ( status != SANE_STATUS_GOOD )
7233141cc406Sopenharmony_ci                            return status;
7234141cc406Sopenharmony_ci                        break;
7235141cc406Sopenharmony_ci                      default:
7236141cc406Sopenharmony_ci                        DBG(1, "reader_process: format %d\n", mi->data_format);
7237141cc406Sopenharmony_ci                        return SANE_STATUS_IO_ERROR;
7238141cc406Sopenharmony_ci                    }
7239141cc406Sopenharmony_ci                }
7240141cc406Sopenharmony_ci              break;
7241141cc406Sopenharmony_ci	    case MS_MODE_GRAY:
7242141cc406Sopenharmony_ci	      status = gray_proc_data(ms);
7243141cc406Sopenharmony_ci              if ( status != SANE_STATUS_GOOD )
7244141cc406Sopenharmony_ci                  return status;
7245141cc406Sopenharmony_ci              break;
7246141cc406Sopenharmony_ci	    case MS_MODE_HALFTONE:
7247141cc406Sopenharmony_ci	    case MS_MODE_LINEART:
7248141cc406Sopenharmony_ci              status = proc_onebit_data(ms);
7249141cc406Sopenharmony_ci              if ( status != SANE_STATUS_GOOD )
7250141cc406Sopenharmony_ci                  return status;
7251141cc406Sopenharmony_ci              break;
7252141cc406Sopenharmony_ci	    case MS_MODE_LINEARTFAKE:
7253141cc406Sopenharmony_ci              if ( ms->auto_adjust == 1 )
7254141cc406Sopenharmony_ci                  status = auto_adjust_proc_data(ms, &temp_current);
7255141cc406Sopenharmony_ci              else
7256141cc406Sopenharmony_ci                  status = lineartfake_proc_data(ms);
7257141cc406Sopenharmony_ci
7258141cc406Sopenharmony_ci              if ( status != SANE_STATUS_GOOD )
7259141cc406Sopenharmony_ci                  return status;
7260141cc406Sopenharmony_ci              break;
7261141cc406Sopenharmony_ci            default:
7262141cc406Sopenharmony_ci              DBG(1, "reader_process: Unknown scan mode %d\n", ms->mode);
7263141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
7264141cc406Sopenharmony_ci          }
7265141cc406Sopenharmony_ci      }
7266141cc406Sopenharmony_ci
7267141cc406Sopenharmony_ci    fclose(ms->fp);
7268141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7269141cc406Sopenharmony_ci}
7270141cc406Sopenharmony_ci
7271141cc406Sopenharmony_ci/*---------- chunky_proc_data() ----------------------------------------------*/
7272141cc406Sopenharmony_ci
7273141cc406Sopenharmony_cistatic SANE_Status
7274141cc406Sopenharmony_cichunky_proc_data(Microtek2_Scanner *ms)
7275141cc406Sopenharmony_ci{
7276141cc406Sopenharmony_ci    SANE_Status status;
7277141cc406Sopenharmony_ci    Microtek2_Device *md;
7278141cc406Sopenharmony_ci    uint32_t line;
7279141cc406Sopenharmony_ci    uint8_t *from;
7280141cc406Sopenharmony_ci    int pad;
7281141cc406Sopenharmony_ci    int bpp;                    /* bytes per pixel */
7282141cc406Sopenharmony_ci    int bits_pp_in;             /* bits per pixel input */
7283141cc406Sopenharmony_ci    int bits_pp_out;            /* bits per pixel output */
7284141cc406Sopenharmony_ci    int bpl_ppl_diff;
7285141cc406Sopenharmony_ci
7286141cc406Sopenharmony_ci
7287141cc406Sopenharmony_ci    DBG(30, "chunky_proc_data: ms=%p\n", (void *) ms);
7288141cc406Sopenharmony_ci
7289141cc406Sopenharmony_ci    md = ms->dev;
7290141cc406Sopenharmony_ci    bits_pp_in = ms->bits_per_pixel_in;
7291141cc406Sopenharmony_ci    bits_pp_out = ms->bits_per_pixel_out;
7292141cc406Sopenharmony_ci    pad = (int) ceil( (double) (ms->ppl * bits_pp_in) / 8.0 ) % 2;
7293141cc406Sopenharmony_ci    bpp = bits_pp_out / 8;
7294141cc406Sopenharmony_ci
7295141cc406Sopenharmony_ci    /* Some models have 3 * ppl + 6 bytes per line if the number of pixels */
7296141cc406Sopenharmony_ci    /* per line is even and 3 * ppl + 3 bytes per line if the number of */
7297141cc406Sopenharmony_ci    /* pixels per line is odd. According to the documentation it should be */
7298141cc406Sopenharmony_ci    /* bpl = 3*ppl (even number of pixels) or bpl=3*ppl+1 (odd number of */
7299141cc406Sopenharmony_ci    /* pixels. Even worse: On different models it is different at which */
7300141cc406Sopenharmony_ci    /* position in a scanline the image data starts. bpl_ppl_diff tries */
7301141cc406Sopenharmony_ci    /* to fix this. */
7302141cc406Sopenharmony_ci
7303141cc406Sopenharmony_ci    if ( (md->model_flags & MD_OFFSET_2) && pad == 1 )
7304141cc406Sopenharmony_ci        bpl_ppl_diff = 2;
7305141cc406Sopenharmony_ci    else
7306141cc406Sopenharmony_ci        bpl_ppl_diff = 0;
7307141cc406Sopenharmony_ci
7308141cc406Sopenharmony_ci#if 0
7309141cc406Sopenharmony_ci    if ( md->revision == 1.00 && mi->model_code != 0x81 )
7310141cc406Sopenharmony_ci        bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp ) - pad;
7311141cc406Sopenharmony_ci    else
7312141cc406Sopenharmony_ci        bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp );
7313141cc406Sopenharmony_ci
7314141cc406Sopenharmony_ci    if ( md->revision > 1.00 )
7315141cc406Sopenharmony_ci        bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp );
7316141cc406Sopenharmony_ci    else
7317141cc406Sopenharmony_ci        bpl_ppl_diff = ms->bpl - ( 3 * ms->ppl * bpp ) - pad;
7318141cc406Sopenharmony_ci#endif
7319141cc406Sopenharmony_ci
7320141cc406Sopenharmony_ci    from = ms->buf.src_buf;
7321141cc406Sopenharmony_ci    from += bpl_ppl_diff;
7322141cc406Sopenharmony_ci
7323141cc406Sopenharmony_ci    DBG(30, "chunky_proc_data: lines=%d, bpl=%d, ppl=%d, bpp=%d, depth=%d"
7324141cc406Sopenharmony_ci            " junk=%d\n", ms->src_lines_to_read, ms->bpl, ms->ppl,
7325141cc406Sopenharmony_ci             bpp, ms->depth, bpl_ppl_diff);
7326141cc406Sopenharmony_ci
7327141cc406Sopenharmony_ci    for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7328141cc406Sopenharmony_ci      {
7329141cc406Sopenharmony_ci        status = chunky_copy_pixels(ms, from);
7330141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7331141cc406Sopenharmony_ci            return status;
7332141cc406Sopenharmony_ci        from += ms->bpl;
7333141cc406Sopenharmony_ci      }
7334141cc406Sopenharmony_ci
7335141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7336141cc406Sopenharmony_ci}
7337141cc406Sopenharmony_ci
7338141cc406Sopenharmony_ci/*---------- chunky_copy_pixels() --------------------------------------------*/
7339141cc406Sopenharmony_ci
7340141cc406Sopenharmony_cistatic SANE_Status
7341141cc406Sopenharmony_cichunky_copy_pixels(Microtek2_Scanner *ms, uint8_t *from)
7342141cc406Sopenharmony_ci{
7343141cc406Sopenharmony_ci    Microtek2_Device *md;
7344141cc406Sopenharmony_ci    uint32_t pixel;
7345141cc406Sopenharmony_ci    int color;
7346141cc406Sopenharmony_ci
7347141cc406Sopenharmony_ci    DBG(30, "chunky_copy_pixels: from=%p, pixels=%d, fp=%p, depth=%d\n",
7348141cc406Sopenharmony_ci             (void *) from, ms->ppl, (void *) ms->fp, ms->depth);
7349141cc406Sopenharmony_ci
7350141cc406Sopenharmony_ci    md = ms->dev;
7351141cc406Sopenharmony_ci    if ( ms->depth > 8 )
7352141cc406Sopenharmony_ci      {
7353141cc406Sopenharmony_ci        if ( !( md->model_flags & MD_16BIT_TRANSFER ) )
7354141cc406Sopenharmony_ci          {
7355141cc406Sopenharmony_ci            int scale1;
7356141cc406Sopenharmony_ci            int scale2;
7357141cc406Sopenharmony_ci            uint16_t val16;
7358141cc406Sopenharmony_ci
7359141cc406Sopenharmony_ci            scale1 = 16 - ms->depth;
7360141cc406Sopenharmony_ci            scale2 = 2 * ms->depth - 16;
7361141cc406Sopenharmony_ci            for ( pixel = 0; pixel < ms->ppl; pixel++ )
7362141cc406Sopenharmony_ci              {
7363141cc406Sopenharmony_ci                for ( color = 0; color < 3; color++ )
7364141cc406Sopenharmony_ci                  {
7365141cc406Sopenharmony_ci                    val16 = *( (uint16_t *) from + 3 * pixel + color );
7366141cc406Sopenharmony_ci                    val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7367141cc406Sopenharmony_ci                    fwrite((void *) &val16, 2, 1, ms->fp);
7368141cc406Sopenharmony_ci                  }
7369141cc406Sopenharmony_ci              }
7370141cc406Sopenharmony_ci          }
7371141cc406Sopenharmony_ci        else
7372141cc406Sopenharmony_ci          {
7373141cc406Sopenharmony_ci            fwrite((void *) from, 2, 3 * ms->ppl, ms->fp);
7374141cc406Sopenharmony_ci          }
7375141cc406Sopenharmony_ci      }
7376141cc406Sopenharmony_ci    else if ( ms->depth == 8 )
7377141cc406Sopenharmony_ci      {
7378141cc406Sopenharmony_ci        fwrite((void *) from, 1, 3 * ms->ppl, ms->fp);
7379141cc406Sopenharmony_ci      }
7380141cc406Sopenharmony_ci    else
7381141cc406Sopenharmony_ci      {
7382141cc406Sopenharmony_ci        DBG(1, "chunky_copy_pixels: Unknown depth %d\n", ms->depth);
7383141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
7384141cc406Sopenharmony_ci      }
7385141cc406Sopenharmony_ci
7386141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7387141cc406Sopenharmony_ci}
7388141cc406Sopenharmony_ci
7389141cc406Sopenharmony_ci/*---------- segreg_proc_data() ----------------------------------------------*/
7390141cc406Sopenharmony_ci
7391141cc406Sopenharmony_cistatic SANE_Status
7392141cc406Sopenharmony_cisegreg_proc_data(Microtek2_Scanner *ms)
7393141cc406Sopenharmony_ci{
7394141cc406Sopenharmony_ci    SANE_Status status;
7395141cc406Sopenharmony_ci    Microtek2_Device *md;
7396141cc406Sopenharmony_ci    Microtek2_Info *mi;
7397141cc406Sopenharmony_ci    char colormap[] = "RGB";
7398141cc406Sopenharmony_ci    uint8_t *from;
7399141cc406Sopenharmony_ci    uint32_t lines_to_deliver;
7400141cc406Sopenharmony_ci    int bpp;                    /* bytes per pixel */
7401141cc406Sopenharmony_ci    int bpf;                    /* bytes per frame including color indicator */
7402141cc406Sopenharmony_ci    int pad;
7403141cc406Sopenharmony_ci    int colseq2;
7404141cc406Sopenharmony_ci    int color;
7405141cc406Sopenharmony_ci    int save_current_src;
7406141cc406Sopenharmony_ci    int frame;
7407141cc406Sopenharmony_ci
7408141cc406Sopenharmony_ci    DBG(30, "segreg_proc_data: ms=%p\n", (void *) ms);
7409141cc406Sopenharmony_ci
7410141cc406Sopenharmony_ci    md = ms->dev;
7411141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7412141cc406Sopenharmony_ci    /* take a trailing junk byte into account */
7413141cc406Sopenharmony_ci    pad = (int) ceil( (double) (ms->ppl * ms->bits_per_pixel_in) / 8.0 ) % 2;
7414141cc406Sopenharmony_ci    bpp = ms->bits_per_pixel_out / 8; /* bits_per_pixel_out is either 8 or 16 */
7415141cc406Sopenharmony_ci    bpf = ms->bpl / 3;
7416141cc406Sopenharmony_ci
7417141cc406Sopenharmony_ci    DBG(30, "segreg_proc_data: lines=%d, bpl=%d, ppl=%d, bpf=%d, bpp=%d,\n"
7418141cc406Sopenharmony_ci            "depth=%d, pad=%d, freelines=%d, calib_backend=%d\n",
7419141cc406Sopenharmony_ci             ms->src_lines_to_read, ms->bpl, ms->ppl, bpf, bpp,
7420141cc406Sopenharmony_ci             ms->depth, pad, ms->buf.free_lines, ms->calib_backend);
7421141cc406Sopenharmony_ci
7422141cc406Sopenharmony_ci    /* determine how many planes of each color are in the source buffer */
7423141cc406Sopenharmony_ci    from = ms->buf.src_buf;
7424141cc406Sopenharmony_ci    for ( frame = 0; frame < 3 * ms->src_lines_to_read; frame++, from += bpf )
7425141cc406Sopenharmony_ci      {
7426141cc406Sopenharmony_ci        switch ( *from )
7427141cc406Sopenharmony_ci          {
7428141cc406Sopenharmony_ci            case 'R':
7429141cc406Sopenharmony_ci              ++ms->buf.planes[0][MS_COLOR_RED];
7430141cc406Sopenharmony_ci              break;
7431141cc406Sopenharmony_ci            case 'G':
7432141cc406Sopenharmony_ci              ++ms->buf.planes[0][MS_COLOR_GREEN];
7433141cc406Sopenharmony_ci              break;
7434141cc406Sopenharmony_ci            case 'B':
7435141cc406Sopenharmony_ci              ++ms->buf.planes[0][MS_COLOR_BLUE];
7436141cc406Sopenharmony_ci              break;
7437141cc406Sopenharmony_ci            default:
7438141cc406Sopenharmony_ci              DBG(1, "segreg_proc_data: unknown color indicator (1) "
7439141cc406Sopenharmony_ci                     "0x%02x\n", *from);
7440141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
7441141cc406Sopenharmony_ci          }
7442141cc406Sopenharmony_ci      }
7443141cc406Sopenharmony_ci
7444141cc406Sopenharmony_ci    ms->buf.free_lines -= ms->src_lines_to_read;
7445141cc406Sopenharmony_ci    save_current_src = ms->buf.current_src;
7446141cc406Sopenharmony_ci    if ( ms->buf.free_lines < ms->src_max_lines )
7447141cc406Sopenharmony_ci      {
7448141cc406Sopenharmony_ci        ms->buf.current_src = !ms->buf.current_src;
7449141cc406Sopenharmony_ci        ms->buf.src_buf = ms->buf.src_buffer[ms->buf.current_src];
7450141cc406Sopenharmony_ci        ms->buf.free_lines = ms->buf.free_max_lines;
7451141cc406Sopenharmony_ci      }
7452141cc406Sopenharmony_ci    else
7453141cc406Sopenharmony_ci        ms->buf.src_buf += ms->src_lines_to_read * ms->bpl;
7454141cc406Sopenharmony_ci
7455141cc406Sopenharmony_ci    colseq2 = mi->color_sequence[2];
7456141cc406Sopenharmony_ci    lines_to_deliver = ms->buf.planes[0][colseq2] + ms->buf.planes[1][colseq2];
7457141cc406Sopenharmony_ci    if ( lines_to_deliver == 0 )
7458141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
7459141cc406Sopenharmony_ci
7460141cc406Sopenharmony_ci    DBG(30, "segreg_proc_data: planes[0][0]=%d, planes[0][1]=%d, "
7461141cc406Sopenharmony_ci            "planes[0][2]=%d\n", ms->buf.planes[0][0], ms->buf.planes[0][1],
7462141cc406Sopenharmony_ci             ms->buf.planes[0][2] );
7463141cc406Sopenharmony_ci    DBG(30, "segreg_proc_data: planes[1][0]=%d, planes[1][1]=%d, "
7464141cc406Sopenharmony_ci            "planes[1][2]=%d\n", ms->buf.planes[1][0], ms->buf.planes[1][1],
7465141cc406Sopenharmony_ci             ms->buf.planes[1][2] );
7466141cc406Sopenharmony_ci
7467141cc406Sopenharmony_ci    while ( lines_to_deliver > 0 )
7468141cc406Sopenharmony_ci      {
7469141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7470141cc406Sopenharmony_ci          {
7471141cc406Sopenharmony_ci            /* get the position of the next plane for each color */
7472141cc406Sopenharmony_ci            do
7473141cc406Sopenharmony_ci              {
7474141cc406Sopenharmony_ci                if ( *ms->buf.current_pos[color] == colormap[color] )
7475141cc406Sopenharmony_ci                    break;
7476141cc406Sopenharmony_ci                ms->buf.current_pos[color] += bpf;
7477141cc406Sopenharmony_ci              } while ( 1 );
7478141cc406Sopenharmony_ci
7479141cc406Sopenharmony_ci            ms->buf.current_pos[color] += 2;    /* skip color indicator */
7480141cc406Sopenharmony_ci          }
7481141cc406Sopenharmony_ci
7482141cc406Sopenharmony_ci        status = segreg_copy_pixels(ms);
7483141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7484141cc406Sopenharmony_ci          {
7485141cc406Sopenharmony_ci            DBG(1, "segreg_copy_pixels:status %d\n", status);
7486141cc406Sopenharmony_ci            return status;
7487141cc406Sopenharmony_ci          }
7488141cc406Sopenharmony_ci
7489141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7490141cc406Sopenharmony_ci          {
7491141cc406Sopenharmony_ci            /* skip a padding byte at the end, if present */
7492141cc406Sopenharmony_ci            ms->buf.current_pos[color] += pad;
7493141cc406Sopenharmony_ci
7494141cc406Sopenharmony_ci            if ( ms->buf.planes[1][color] > 0 )
7495141cc406Sopenharmony_ci              {
7496141cc406Sopenharmony_ci                --ms->buf.planes[1][color];
7497141cc406Sopenharmony_ci                if ( ms->buf.planes[1][color] == 0 )
7498141cc406Sopenharmony_ci                    /* we have copied from the prehold buffer and are */
7499141cc406Sopenharmony_ci                    /* done now, we continue with the source buffer */
7500141cc406Sopenharmony_ci                    ms->buf.current_pos[color] =
7501141cc406Sopenharmony_ci                                        ms->buf.src_buffer[save_current_src];
7502141cc406Sopenharmony_ci              }
7503141cc406Sopenharmony_ci            else
7504141cc406Sopenharmony_ci              {
7505141cc406Sopenharmony_ci                --ms->buf.planes[0][color];
7506141cc406Sopenharmony_ci                if ( ms->buf.planes[0][color] == 0
7507141cc406Sopenharmony_ci                     && ms->buf.current_src != save_current_src )
7508141cc406Sopenharmony_ci
7509141cc406Sopenharmony_ci                    ms->buf.current_pos[color] =
7510141cc406Sopenharmony_ci                                    ms->buf.src_buffer[ms->buf.current_src];
7511141cc406Sopenharmony_ci              }
7512141cc406Sopenharmony_ci          }
7513141cc406Sopenharmony_ci        DBG(100, "planes_to_deliver=%d\n", lines_to_deliver);
7514141cc406Sopenharmony_ci        --lines_to_deliver;
7515141cc406Sopenharmony_ci      }
7516141cc406Sopenharmony_ci
7517141cc406Sopenharmony_ci    if ( ms->buf.current_src != save_current_src )
7518141cc406Sopenharmony_ci      {
7519141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7520141cc406Sopenharmony_ci          {
7521141cc406Sopenharmony_ci            ms->buf.planes[1][color] += ms->buf.planes[0][color];
7522141cc406Sopenharmony_ci            ms->buf.planes[0][color] = 0;
7523141cc406Sopenharmony_ci          }
7524141cc406Sopenharmony_ci      }
7525141cc406Sopenharmony_ci
7526141cc406Sopenharmony_ci    DBG(30, "segreg_proc_data: src_buf=%p, free_lines=%d\n",
7527141cc406Sopenharmony_ci             (void *) ms->buf.src_buf, ms->buf.free_lines);
7528141cc406Sopenharmony_ci
7529141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7530141cc406Sopenharmony_ci}
7531141cc406Sopenharmony_ci
7532141cc406Sopenharmony_ci/*---------- segreg_copy_pixels() --------------------------------------------*/
7533141cc406Sopenharmony_ci
7534141cc406Sopenharmony_cistatic SANE_Status
7535141cc406Sopenharmony_cisegreg_copy_pixels(Microtek2_Scanner *ms)
7536141cc406Sopenharmony_ci{
7537141cc406Sopenharmony_ci    Microtek2_Device *md;
7538141cc406Sopenharmony_ci    Microtek2_Info *mi;
7539141cc406Sopenharmony_ci    uint32_t pixel;
7540141cc406Sopenharmony_ci    int color, i, gamma_by_backend, right_to_left, scale1, scale2, bpp_in;
7541141cc406Sopenharmony_ci    float s_w, s_d;          /* shading byte from condensed_shading */
7542141cc406Sopenharmony_ci    float val, maxval = 0, shading_factor = 0;
7543141cc406Sopenharmony_ci    uint16_t val16 = 0;
7544141cc406Sopenharmony_ci    uint8_t val8 = 0;
7545141cc406Sopenharmony_ci    uint8_t *from_effective;
7546141cc406Sopenharmony_ci    uint8_t *gamma[3];
7547141cc406Sopenharmony_ci    float f[3];                            /* color balance factor */
7548141cc406Sopenharmony_ci
7549141cc406Sopenharmony_ci    md = ms->dev;
7550141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7551141cc406Sopenharmony_ci    gamma_by_backend =  md->model_flags & MD_NO_GAMMA ? 1 : 0;
7552141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
7553141cc406Sopenharmony_ci    scale1 = 16 - ms->depth;
7554141cc406Sopenharmony_ci    scale2 = 2 * ms->depth - 16;
7555141cc406Sopenharmony_ci    bpp_in = ( ms->bits_per_pixel_in + 7 ) / 8; /*Bytes per pixel from scanner*/
7556141cc406Sopenharmony_ci
7557141cc406Sopenharmony_ci    if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
7558141cc406Sopenharmony_ci      {
7559141cc406Sopenharmony_ci        maxval = (float) pow(2.0, (float) ms->depth) - 1.0;
7560141cc406Sopenharmony_ci        s_w = maxval;
7561141cc406Sopenharmony_ci        s_d = 0.0;
7562141cc406Sopenharmony_ci        shading_factor = (float) pow(2.0, (double) (md->shading_depth
7563141cc406Sopenharmony_ci							 - ms->depth) );
7564141cc406Sopenharmony_ci      }
7565141cc406Sopenharmony_ci
7566141cc406Sopenharmony_ci    if ( gamma_by_backend )
7567141cc406Sopenharmony_ci      {
7568141cc406Sopenharmony_ci        i = (ms->depth > 8) ? 2 : 1;
7569141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++)
7570141cc406Sopenharmony_ci           gamma[color] = ms->gamma_table
7571141cc406Sopenharmony_ci                          + i * (int) pow(2.0, (double)ms->depth);
7572141cc406Sopenharmony_ci      }
7573141cc406Sopenharmony_ci
7574141cc406Sopenharmony_ci    DBG(30, "segreg_copy_pixels: pixels=%d\n", ms->ppl);
7575141cc406Sopenharmony_ci    DBG(100, "segreg_copy_pixels: buffer 0x%p, right_to_left=%d, depth=%d\n",
7576141cc406Sopenharmony_ci	(void *) ms->buf.current_pos, right_to_left, ms->depth);
7577141cc406Sopenharmony_ci
7578141cc406Sopenharmony_ci    for (color = 0; color < 3; color++ )
7579141cc406Sopenharmony_ci        f[color] = (float) ms->balance[color] / 100.0;
7580141cc406Sopenharmony_ci
7581141cc406Sopenharmony_ci    DBG(100, "segreg_copy_pixels: color balance:\n"
7582141cc406Sopenharmony_ci             " ms->balance[R]=%d, ms->balance[G]=%d, ms->balance[B]=%d\n",
7583141cc406Sopenharmony_ci             ms->balance[0], ms->balance[1], ms->balance[2]);
7584141cc406Sopenharmony_ci
7585141cc406Sopenharmony_ci    for ( pixel = 0; pixel < ms->ppl; pixel++ )
7586141cc406Sopenharmony_ci      {
7587141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7588141cc406Sopenharmony_ci          {
7589141cc406Sopenharmony_ci            if ( right_to_left )
7590141cc406Sopenharmony_ci               from_effective = ms->buf.current_pos[color]
7591141cc406Sopenharmony_ci                                + ( ms->ppl - 1 - pixel ) * bpp_in;
7592141cc406Sopenharmony_ci            else
7593141cc406Sopenharmony_ci               from_effective = ms->buf.current_pos[color]  +  pixel * bpp_in;
7594141cc406Sopenharmony_ci
7595141cc406Sopenharmony_ci            if ( ms->depth > 8 )
7596141cc406Sopenharmony_ci                val = (float) *(uint16_t *)from_effective;
7597141cc406Sopenharmony_ci            else if ( ms->depth == 8 )
7598141cc406Sopenharmony_ci                val = (float) *from_effective;
7599141cc406Sopenharmony_ci            else
7600141cc406Sopenharmony_ci            {
7601141cc406Sopenharmony_ci              DBG(1, "segreg_copy_pixels: Unknown depth %d\n", ms->depth);
7602141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
7603141cc406Sopenharmony_ci            }
7604141cc406Sopenharmony_ci
7605141cc406Sopenharmony_ci	    if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
7606141cc406Sopenharmony_ci                 && ( ms->condensed_shading_w != NULL ))
7607141cc406Sopenharmony_ci                 /* apply shading by backend */
7608141cc406Sopenharmony_ci              {
7609141cc406Sopenharmony_ci                get_cshading_values(ms,
7610141cc406Sopenharmony_ci                                    color,
7611141cc406Sopenharmony_ci                                    pixel,
7612141cc406Sopenharmony_ci                                    shading_factor,
7613141cc406Sopenharmony_ci                                    right_to_left,
7614141cc406Sopenharmony_ci                                    &s_d,
7615141cc406Sopenharmony_ci                                    &s_w);
7616141cc406Sopenharmony_ci
7617141cc406Sopenharmony_ci
7618141cc406Sopenharmony_ci                if ( s_w == s_d ) s_w = s_d + 1;
7619141cc406Sopenharmony_ci                if ( val < s_d ) val = s_d;
7620141cc406Sopenharmony_ci                val = maxval *( val - s_d ) / ( s_w - s_d );
7621141cc406Sopenharmony_ci
7622141cc406Sopenharmony_ci                val *= f[color];
7623141cc406Sopenharmony_ci
7624141cc406Sopenharmony_ci                /* if scanner doesn't support brightness, contrast */
7625141cc406Sopenharmony_ci                if ( md->model_flags & MD_NO_ENHANCEMENTS )
7626141cc406Sopenharmony_ci                  {
7627141cc406Sopenharmony_ci                     val += ( ( ms->brightness_m - 128 ) * 2 );
7628141cc406Sopenharmony_ci                     val = ( val - 128 ) * ( ms->contrast_m / 128 ) + 128;
7629141cc406Sopenharmony_ci                  }
7630141cc406Sopenharmony_ci
7631141cc406Sopenharmony_ci                val = MAX( 0.0, val);
7632141cc406Sopenharmony_ci                val = MIN( maxval, val );
7633141cc406Sopenharmony_ci              }
7634141cc406Sopenharmony_ci
7635141cc406Sopenharmony_ci	    val16 = (uint16_t) val;
7636141cc406Sopenharmony_ci            val8  = (uint8_t)  val;
7637141cc406Sopenharmony_ci
7638141cc406Sopenharmony_ci            /* apply gamma correction if needed */
7639141cc406Sopenharmony_ci            if ( gamma_by_backend )
7640141cc406Sopenharmony_ci              {
7641141cc406Sopenharmony_ci                if ( ms->depth > 8 )
7642141cc406Sopenharmony_ci                  val16 = *((uint16_t *) gamma[color] + val16);
7643141cc406Sopenharmony_ci                else
7644141cc406Sopenharmony_ci                  val8 = gamma[color][val8];
7645141cc406Sopenharmony_ci              }
7646141cc406Sopenharmony_ci
7647141cc406Sopenharmony_ci            if ( ms->depth > 8 )
7648141cc406Sopenharmony_ci              {
7649141cc406Sopenharmony_ci                val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7650141cc406Sopenharmony_ci                fwrite((void *) &val16, 2, 1, ms->fp);
7651141cc406Sopenharmony_ci              }
7652141cc406Sopenharmony_ci            else
7653141cc406Sopenharmony_ci              {
7654141cc406Sopenharmony_ci                fputc((unsigned char) val8, ms->fp);
7655141cc406Sopenharmony_ci              }
7656141cc406Sopenharmony_ci
7657141cc406Sopenharmony_ci          }
7658141cc406Sopenharmony_ci      }
7659141cc406Sopenharmony_ci    for ( color = 0; color < 3; color++ )
7660141cc406Sopenharmony_ci      {
7661141cc406Sopenharmony_ci        ms->buf.current_pos[color] += ms->ppl;
7662141cc406Sopenharmony_ci        if ( ms->depth > 8 )
7663141cc406Sopenharmony_ci            ms->buf.current_pos[color] += ms->ppl;
7664141cc406Sopenharmony_ci      }
7665141cc406Sopenharmony_ci
7666141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7667141cc406Sopenharmony_ci
7668141cc406Sopenharmony_ci}
7669141cc406Sopenharmony_ci
7670141cc406Sopenharmony_ci
7671141cc406Sopenharmony_ci/*---------- lplconcat_proc_data() -------------------------------------------*/
7672141cc406Sopenharmony_cistatic SANE_Status
7673141cc406Sopenharmony_cilplconcat_proc_data(Microtek2_Scanner *ms)
7674141cc406Sopenharmony_ci{
7675141cc406Sopenharmony_ci    SANE_Status status;
7676141cc406Sopenharmony_ci    Microtek2_Device *md;
7677141cc406Sopenharmony_ci    Microtek2_Info *mi;
7678141cc406Sopenharmony_ci    uint32_t line;
7679141cc406Sopenharmony_ci    uint8_t *from[3];
7680141cc406Sopenharmony_ci    uint8_t *save_from[3];
7681141cc406Sopenharmony_ci    int color;
7682141cc406Sopenharmony_ci    int bpp;
7683141cc406Sopenharmony_ci    int gamma_by_backend;
7684141cc406Sopenharmony_ci    int right_to_left;       /* 0=left to right, 1=right to left */
7685141cc406Sopenharmony_ci
7686141cc406Sopenharmony_ci
7687141cc406Sopenharmony_ci    DBG(30, "lplconcat_proc_data: ms=%p\n", (void *) ms);
7688141cc406Sopenharmony_ci
7689141cc406Sopenharmony_ci    /* This data format seems to honour the color sequence indicator */
7690141cc406Sopenharmony_ci
7691141cc406Sopenharmony_ci    md = ms->dev;
7692141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7693141cc406Sopenharmony_ci
7694141cc406Sopenharmony_ci    bpp = ms->bits_per_pixel_out / 8; /* ms->bits_per_pixel_out is 8 or 16 */
7695141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
7696141cc406Sopenharmony_ci    gamma_by_backend =  md->model_flags & MD_NO_GAMMA ? 1 : 0;
7697141cc406Sopenharmony_ci
7698141cc406Sopenharmony_ci    if ( right_to_left == 1 )
7699141cc406Sopenharmony_ci      {
7700141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7701141cc406Sopenharmony_ci          {
7702141cc406Sopenharmony_ci            from[color] = ms->buf.src_buf
7703141cc406Sopenharmony_ci                          + ( mi->color_sequence[color] + 1 ) * ( ms->bpl / 3 )
7704141cc406Sopenharmony_ci                          - bpp - (ms->bpl - 3 * ms->ppl * bpp) / 3;
7705141cc406Sopenharmony_ci          }
7706141cc406Sopenharmony_ci      }
7707141cc406Sopenharmony_ci    else
7708141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7709141cc406Sopenharmony_ci            from[color] = ms->buf.src_buf
7710141cc406Sopenharmony_ci                          + mi->color_sequence[color] * ( ms->bpl / 3 );
7711141cc406Sopenharmony_ci
7712141cc406Sopenharmony_ci    for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7713141cc406Sopenharmony_ci      {
7714141cc406Sopenharmony_ci        for ( color = 0 ; color < 3; color++ )
7715141cc406Sopenharmony_ci            save_from[color] = from[color];
7716141cc406Sopenharmony_ci
7717141cc406Sopenharmony_ci        status = lplconcat_copy_pixels(ms,
7718141cc406Sopenharmony_ci                                       from,
7719141cc406Sopenharmony_ci                                       right_to_left,
7720141cc406Sopenharmony_ci                                       gamma_by_backend);
7721141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7722141cc406Sopenharmony_ci            return status;
7723141cc406Sopenharmony_ci
7724141cc406Sopenharmony_ci        for ( color = 0; color < 3; color++ )
7725141cc406Sopenharmony_ci            from[color] = save_from[color] + ms->bpl;
7726141cc406Sopenharmony_ci      }
7727141cc406Sopenharmony_ci
7728141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7729141cc406Sopenharmony_ci}
7730141cc406Sopenharmony_ci
7731141cc406Sopenharmony_ci
7732141cc406Sopenharmony_ci/*---------- lplconcat_copy_pixels() -----------------------------------------*/
7733141cc406Sopenharmony_ci
7734141cc406Sopenharmony_cistatic SANE_Status
7735141cc406Sopenharmony_cilplconcat_copy_pixels(Microtek2_Scanner *ms,
7736141cc406Sopenharmony_ci                      uint8_t **from,
7737141cc406Sopenharmony_ci                      int right_to_left,
7738141cc406Sopenharmony_ci                      int gamma_by_backend)
7739141cc406Sopenharmony_ci{
7740141cc406Sopenharmony_ci  Microtek2_Device *md;
7741141cc406Sopenharmony_ci  Microtek2_Info *mi;
7742141cc406Sopenharmony_ci  uint32_t pixel;
7743141cc406Sopenharmony_ci  uint16_t val16 = 0;
7744141cc406Sopenharmony_ci  uint8_t val8 = 0;
7745141cc406Sopenharmony_ci  uint8_t *gamma[3];
7746141cc406Sopenharmony_ci  float s_d;                             /* dark shading pixel */
7747141cc406Sopenharmony_ci  float s_w;                             /* white shading pixel */
7748141cc406Sopenharmony_ci  float shading_factor = 0;
7749141cc406Sopenharmony_ci  float f[3];                            /* color balance factor */
7750141cc406Sopenharmony_ci  float val, maxval = 0;
7751141cc406Sopenharmony_ci  int color;
7752141cc406Sopenharmony_ci  int step, scale1, scale2;
7753141cc406Sopenharmony_ci  int i;
7754141cc406Sopenharmony_ci
7755141cc406Sopenharmony_ci
7756141cc406Sopenharmony_ci  DBG(30, "lplconcat_copy_pixels: ms=%p, righttoleft=%d, gamma=%d,\n",
7757141cc406Sopenharmony_ci           (void *) ms, right_to_left, gamma_by_backend);
7758141cc406Sopenharmony_ci
7759141cc406Sopenharmony_ci  md = ms->dev;
7760141cc406Sopenharmony_ci  mi = &md->info[md->scan_source];
7761141cc406Sopenharmony_ci
7762141cc406Sopenharmony_ci  if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
7763141cc406Sopenharmony_ci    {
7764141cc406Sopenharmony_ci      shading_factor = (float) pow(2.0,(double)(md->shading_depth - ms->depth));
7765141cc406Sopenharmony_ci      maxval = (float) pow(2.0, (double) ms->depth) - 1.0;
7766141cc406Sopenharmony_ci      s_w = maxval;
7767141cc406Sopenharmony_ci      s_d = 0.0;
7768141cc406Sopenharmony_ci    }
7769141cc406Sopenharmony_ci
7770141cc406Sopenharmony_ci  step = ( right_to_left == 1 ) ? -1 : 1;
7771141cc406Sopenharmony_ci  if ( ms->depth > 8 ) step *= 2;
7772141cc406Sopenharmony_ci  scale1 = 16 - ms->depth;
7773141cc406Sopenharmony_ci  scale2 = 2 * ms->depth - 16;
7774141cc406Sopenharmony_ci
7775141cc406Sopenharmony_ci  if ( gamma_by_backend )
7776141cc406Sopenharmony_ci    {
7777141cc406Sopenharmony_ci      i =  ( ms->depth > 8 ) ? 2 : 1;
7778141cc406Sopenharmony_ci      for ( color = 0; color < 3; color++ )
7779141cc406Sopenharmony_ci          gamma[color] = ms->gamma_table + i * (int) pow(2.0,(double)ms->depth);
7780141cc406Sopenharmony_ci    }
7781141cc406Sopenharmony_ci
7782141cc406Sopenharmony_ci  for (color = 0; color < 3; color++ )
7783141cc406Sopenharmony_ci      f[color] = (float)ms->balance[color] / 100.0;
7784141cc406Sopenharmony_ci
7785141cc406Sopenharmony_ci  DBG(100, "lplconcat_copy_pixels: color balance:\n"
7786141cc406Sopenharmony_ci             " ms->balance[R]=%d, ms->balance[G]=%d, ms->balance[B]=%d\n",
7787141cc406Sopenharmony_ci             ms->balance[0], ms->balance[1], ms->balance[2]);
7788141cc406Sopenharmony_ci
7789141cc406Sopenharmony_ci  for ( pixel = 0; pixel < ms->ppl; pixel++ )
7790141cc406Sopenharmony_ci    {
7791141cc406Sopenharmony_ci      for ( color = 0; color < 3; color++ )
7792141cc406Sopenharmony_ci        {
7793141cc406Sopenharmony_ci          if ( ms->depth > 8 )
7794141cc406Sopenharmony_ci              val = (float) *(uint16_t *) from[color];
7795141cc406Sopenharmony_ci          else if ( ms->depth == 8 )
7796141cc406Sopenharmony_ci              val = (float) *from[color];
7797141cc406Sopenharmony_ci          else
7798141cc406Sopenharmony_ci            {
7799141cc406Sopenharmony_ci              DBG(1, "lplconcat_copy_pixels: Unknown depth %d\n", ms->depth);
7800141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
7801141cc406Sopenharmony_ci            }
7802141cc406Sopenharmony_ci
7803141cc406Sopenharmony_ci	  if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
7804141cc406Sopenharmony_ci               && ( ms->condensed_shading_w != NULL ))
7805141cc406Sopenharmony_ci               /* apply shading by backend */
7806141cc406Sopenharmony_ci            {
7807141cc406Sopenharmony_ci              get_cshading_values(ms,
7808141cc406Sopenharmony_ci                                  mi->color_sequence[color],
7809141cc406Sopenharmony_ci                                  pixel,
7810141cc406Sopenharmony_ci                                  shading_factor,
7811141cc406Sopenharmony_ci                                  right_to_left,
7812141cc406Sopenharmony_ci                                  &s_d,
7813141cc406Sopenharmony_ci                                  &s_w);
7814141cc406Sopenharmony_ci
7815141cc406Sopenharmony_ci              if ( val < s_d ) val = s_d;
7816141cc406Sopenharmony_ci              if ( s_w == s_d ) s_w = s_d + 1;
7817141cc406Sopenharmony_ci              val = ( maxval * ( val - s_d ) ) / (s_w - s_d);
7818141cc406Sopenharmony_ci
7819141cc406Sopenharmony_ci              val *= f[color]; /* apply color balance */
7820141cc406Sopenharmony_ci
7821141cc406Sopenharmony_ci              /* if scanner doesn't support brightness, contrast ... */
7822141cc406Sopenharmony_ci              if ( md->model_flags & MD_NO_ENHANCEMENTS )
7823141cc406Sopenharmony_ci                {
7824141cc406Sopenharmony_ci                   val += ( ( ms->brightness_m - 128 ) * 2 );
7825141cc406Sopenharmony_ci                   val = ( val - 128 ) * ( ms->contrast_m / 128 ) + 128;
7826141cc406Sopenharmony_ci                }
7827141cc406Sopenharmony_ci
7828141cc406Sopenharmony_ci              if ( val > maxval ) val = maxval;
7829141cc406Sopenharmony_ci              if ( val < 0.0 ) val = 0.0;
7830141cc406Sopenharmony_ci            }
7831141cc406Sopenharmony_ci
7832141cc406Sopenharmony_ci          val16 = (uint16_t) val;
7833141cc406Sopenharmony_ci          val8  = (uint8_t)  val;
7834141cc406Sopenharmony_ci
7835141cc406Sopenharmony_ci          /* apply gamma correction if needed */
7836141cc406Sopenharmony_ci          if ( gamma_by_backend )
7837141cc406Sopenharmony_ci            {
7838141cc406Sopenharmony_ci              if ( ms->depth > 8 )
7839141cc406Sopenharmony_ci                val16 = *((uint16_t *) gamma[color] + val16);
7840141cc406Sopenharmony_ci              else
7841141cc406Sopenharmony_ci                val8 = gamma[color][val8];
7842141cc406Sopenharmony_ci            }
7843141cc406Sopenharmony_ci
7844141cc406Sopenharmony_ci          if ( ms->depth > 8 )
7845141cc406Sopenharmony_ci            {
7846141cc406Sopenharmony_ci              val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7847141cc406Sopenharmony_ci              fwrite((void *) &val16, 2, 1, ms->fp);
7848141cc406Sopenharmony_ci            }
7849141cc406Sopenharmony_ci          else
7850141cc406Sopenharmony_ci            {
7851141cc406Sopenharmony_ci              fputc((unsigned char) val8, ms->fp);
7852141cc406Sopenharmony_ci            }
7853141cc406Sopenharmony_ci          from[color] += step;
7854141cc406Sopenharmony_ci        }
7855141cc406Sopenharmony_ci    }
7856141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
7857141cc406Sopenharmony_ci}
7858141cc406Sopenharmony_ci
7859141cc406Sopenharmony_ci
7860141cc406Sopenharmony_ci
7861141cc406Sopenharmony_ci
7862141cc406Sopenharmony_ci/*---------- wordchunky_proc_data() ------------------------------------------*/
7863141cc406Sopenharmony_ci
7864141cc406Sopenharmony_cistatic SANE_Status
7865141cc406Sopenharmony_ciwordchunky_proc_data(Microtek2_Scanner *ms)
7866141cc406Sopenharmony_ci{
7867141cc406Sopenharmony_ci    SANE_Status status;
7868141cc406Sopenharmony_ci    uint8_t *from;
7869141cc406Sopenharmony_ci    uint32_t line;
7870141cc406Sopenharmony_ci
7871141cc406Sopenharmony_ci
7872141cc406Sopenharmony_ci    DBG(30, "wordchunky_proc_data: ms=%p\n", (void *) ms);
7873141cc406Sopenharmony_ci
7874141cc406Sopenharmony_ci    from = ms->buf.src_buf;
7875141cc406Sopenharmony_ci    for ( line = 0; line < (uint32_t) ms->src_lines_to_read; line++ )
7876141cc406Sopenharmony_ci      {
7877141cc406Sopenharmony_ci        status = wordchunky_copy_pixels(from, ms->ppl, ms->depth, ms->fp);
7878141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7879141cc406Sopenharmony_ci            return status;
7880141cc406Sopenharmony_ci        from += ms->bpl;
7881141cc406Sopenharmony_ci      }
7882141cc406Sopenharmony_ci
7883141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7884141cc406Sopenharmony_ci}
7885141cc406Sopenharmony_ci
7886141cc406Sopenharmony_ci
7887141cc406Sopenharmony_ci/*---------- wordchunky_copy_pixels() ----------------------------------------*/
7888141cc406Sopenharmony_ci
7889141cc406Sopenharmony_cistatic SANE_Status
7890141cc406Sopenharmony_ciwordchunky_copy_pixels(uint8_t *from, uint32_t pixels, int depth, FILE *fp)
7891141cc406Sopenharmony_ci{
7892141cc406Sopenharmony_ci    uint32_t pixel;
7893141cc406Sopenharmony_ci    int color;
7894141cc406Sopenharmony_ci
7895141cc406Sopenharmony_ci    DBG(30, "wordchunky_copy_pixels: from=%p, pixels=%d, depth=%d\n",
7896141cc406Sopenharmony_ci             (void *) from, pixels, depth);
7897141cc406Sopenharmony_ci
7898141cc406Sopenharmony_ci    if ( depth > 8 )
7899141cc406Sopenharmony_ci      {
7900141cc406Sopenharmony_ci        int scale1;
7901141cc406Sopenharmony_ci        int scale2;
7902141cc406Sopenharmony_ci        uint16_t val16;
7903141cc406Sopenharmony_ci
7904141cc406Sopenharmony_ci        scale1 = 16 - depth;
7905141cc406Sopenharmony_ci        scale2 = 2 * depth - 16;
7906141cc406Sopenharmony_ci        for ( pixel = 0; pixel < pixels; pixel++ )
7907141cc406Sopenharmony_ci          {
7908141cc406Sopenharmony_ci            for ( color = 0; color < 3; color++ )
7909141cc406Sopenharmony_ci              {
7910141cc406Sopenharmony_ci                val16 = *(uint16_t *) from;
7911141cc406Sopenharmony_ci                val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
7912141cc406Sopenharmony_ci                fwrite((void *) &val16, 2, 1, fp);
7913141cc406Sopenharmony_ci                from += 2;
7914141cc406Sopenharmony_ci              }
7915141cc406Sopenharmony_ci          }
7916141cc406Sopenharmony_ci      }
7917141cc406Sopenharmony_ci    else if ( depth == 8 )
7918141cc406Sopenharmony_ci      {
7919141cc406Sopenharmony_ci        pixel = 0;
7920141cc406Sopenharmony_ci        do
7921141cc406Sopenharmony_ci          {
7922141cc406Sopenharmony_ci            fputc((char ) *from, fp);
7923141cc406Sopenharmony_ci            fputc((char) *(from + 2), fp);
7924141cc406Sopenharmony_ci            fputc((char) *(from + 4), fp);
7925141cc406Sopenharmony_ci            ++pixel;
7926141cc406Sopenharmony_ci            if ( pixel < pixels )
7927141cc406Sopenharmony_ci              {
7928141cc406Sopenharmony_ci                fputc((char) *(from + 1), fp);
7929141cc406Sopenharmony_ci                fputc((char) *(from + 3), fp);
7930141cc406Sopenharmony_ci                fputc((char) *(from + 5), fp);
7931141cc406Sopenharmony_ci                ++pixel;
7932141cc406Sopenharmony_ci              }
7933141cc406Sopenharmony_ci            from += 6;
7934141cc406Sopenharmony_ci          } while ( pixel < pixels );
7935141cc406Sopenharmony_ci      }
7936141cc406Sopenharmony_ci    else
7937141cc406Sopenharmony_ci      {
7938141cc406Sopenharmony_ci        DBG(1, "wordchunky_copy_pixels: Unknown depth %d\n", depth);
7939141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
7940141cc406Sopenharmony_ci      }
7941141cc406Sopenharmony_ci
7942141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7943141cc406Sopenharmony_ci}
7944141cc406Sopenharmony_ci
7945141cc406Sopenharmony_ci
7946141cc406Sopenharmony_ci/*---------- gray_proc_data() ------------------------------------------------*/
7947141cc406Sopenharmony_ci
7948141cc406Sopenharmony_cistatic SANE_Status
7949141cc406Sopenharmony_cigray_proc_data(Microtek2_Scanner *ms)
7950141cc406Sopenharmony_ci{
7951141cc406Sopenharmony_ci    SANE_Status status;
7952141cc406Sopenharmony_ci    Microtek2_Device *md;
7953141cc406Sopenharmony_ci    Microtek2_Info *mi;
7954141cc406Sopenharmony_ci    uint8_t *from;
7955141cc406Sopenharmony_ci    int gamma_by_backend, bpp;
7956141cc406Sopenharmony_ci    int right_to_left;   /* for scanning direction */
7957141cc406Sopenharmony_ci
7958141cc406Sopenharmony_ci
7959141cc406Sopenharmony_ci    DBG(30, "gray_proc_data: lines=%d, bpl=%d, ppl=%d, depth=%d\n",
7960141cc406Sopenharmony_ci             ms->src_lines_to_read, ms->bpl, ms->ppl, ms->depth);
7961141cc406Sopenharmony_ci
7962141cc406Sopenharmony_ci    md = ms->dev;
7963141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
7964141cc406Sopenharmony_ci
7965141cc406Sopenharmony_ci    gamma_by_backend =  md->model_flags & MD_NO_GAMMA ? 1 : 0;
7966141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
7967141cc406Sopenharmony_ci    bpp = ( ms->bits_per_pixel_in + 7 ) / 8;
7968141cc406Sopenharmony_ci
7969141cc406Sopenharmony_ci    if ( right_to_left == 1 )
7970141cc406Sopenharmony_ci      from = ms->buf.src_buf + ms->ppl * bpp - bpp;
7971141cc406Sopenharmony_ci    else
7972141cc406Sopenharmony_ci      from = ms->buf.src_buf;
7973141cc406Sopenharmony_ci
7974141cc406Sopenharmony_ci    do
7975141cc406Sopenharmony_ci      {
7976141cc406Sopenharmony_ci        status = gray_copy_pixels(ms,
7977141cc406Sopenharmony_ci                                  from,
7978141cc406Sopenharmony_ci                                  right_to_left,
7979141cc406Sopenharmony_ci                                  gamma_by_backend);
7980141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
7981141cc406Sopenharmony_ci            return status;
7982141cc406Sopenharmony_ci
7983141cc406Sopenharmony_ci        from += ms->bpl;
7984141cc406Sopenharmony_ci        --ms->src_lines_to_read;
7985141cc406Sopenharmony_ci      } while ( ms->src_lines_to_read > 0 );
7986141cc406Sopenharmony_ci
7987141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
7988141cc406Sopenharmony_ci}
7989141cc406Sopenharmony_ci
7990141cc406Sopenharmony_ci
7991141cc406Sopenharmony_ci/*---------- gray_copy_pixels() ----------------------------------------------*/
7992141cc406Sopenharmony_ci
7993141cc406Sopenharmony_cistatic SANE_Status
7994141cc406Sopenharmony_cigray_copy_pixels(Microtek2_Scanner *ms,
7995141cc406Sopenharmony_ci                 uint8_t *from,
7996141cc406Sopenharmony_ci                 int right_to_left,
7997141cc406Sopenharmony_ci                 int gamma_by_backend)
7998141cc406Sopenharmony_ci{
7999141cc406Sopenharmony_ci    Microtek2_Device *md;
8000141cc406Sopenharmony_ci    uint32_t pixel;
8001141cc406Sopenharmony_ci    uint16_t val16;
8002141cc406Sopenharmony_ci    uint8_t val8;
8003141cc406Sopenharmony_ci    int step, scale1, scale2;
8004141cc406Sopenharmony_ci    float val, maxval = 0;
8005141cc406Sopenharmony_ci    float s_w, s_d, shading_factor = 0;
8006141cc406Sopenharmony_ci
8007141cc406Sopenharmony_ci    DBG(30, "gray_copy_pixels: pixels=%d, from=%p, fp=%p, depth=%d\n",
8008141cc406Sopenharmony_ci             ms->ppl, (void *) from, (void *) ms->fp, ms->depth);
8009141cc406Sopenharmony_ci
8010141cc406Sopenharmony_ci    md = ms->dev;
8011141cc406Sopenharmony_ci    step = right_to_left == 1 ? -1 : 1;
8012141cc406Sopenharmony_ci    if ( ms->depth > 8 ) step *= 2;
8013141cc406Sopenharmony_ci    val = 0;
8014141cc406Sopenharmony_ci    scale1 = 16 - ms->depth;
8015141cc406Sopenharmony_ci    scale2 = 2 * ms->depth - 16;
8016141cc406Sopenharmony_ci
8017141cc406Sopenharmony_ci    if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend)
8018141cc406Sopenharmony_ci      {
8019141cc406Sopenharmony_ci        maxval = (float) pow(2.0, (float) ms->depth) - 1.0;
8020141cc406Sopenharmony_ci        s_w = maxval;
8021141cc406Sopenharmony_ci        s_d = 0.0;
8022141cc406Sopenharmony_ci        shading_factor = (float) pow(2.0, (double) (md->shading_depth - ms->depth) );
8023141cc406Sopenharmony_ci      }
8024141cc406Sopenharmony_ci
8025141cc406Sopenharmony_ci    if ( ms->depth >= 8 )
8026141cc406Sopenharmony_ci      {
8027141cc406Sopenharmony_ci        for ( pixel = 0; pixel < ms->ppl; pixel++ )
8028141cc406Sopenharmony_ci          {
8029141cc406Sopenharmony_ci            if ( ms->depth > 8 )
8030141cc406Sopenharmony_ci                val = (float) *(uint16_t *) from;
8031141cc406Sopenharmony_ci            if ( ms->depth == 8 )
8032141cc406Sopenharmony_ci                val = (float) *from;
8033141cc406Sopenharmony_ci
8034141cc406Sopenharmony_ci            if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
8035141cc406Sopenharmony_ci                 && ( ms->condensed_shading_w != NULL ))
8036141cc406Sopenharmony_ci                 /* apply shading by backend */
8037141cc406Sopenharmony_ci              {
8038141cc406Sopenharmony_ci                get_cshading_values(ms,
8039141cc406Sopenharmony_ci                                    0,
8040141cc406Sopenharmony_ci                                    pixel,
8041141cc406Sopenharmony_ci                                    shading_factor,
8042141cc406Sopenharmony_ci                                    right_to_left,
8043141cc406Sopenharmony_ci                                    &s_d,
8044141cc406Sopenharmony_ci                                    &s_w);
8045141cc406Sopenharmony_ci
8046141cc406Sopenharmony_ci                if ( val < s_d ) val = s_d;
8047141cc406Sopenharmony_ci                val = ( val - s_d ) * maxval / (s_w - s_d );
8048141cc406Sopenharmony_ci                val = MAX( 0.0, val );
8049141cc406Sopenharmony_ci                val = MIN( maxval, val );
8050141cc406Sopenharmony_ci              }
8051141cc406Sopenharmony_ci
8052141cc406Sopenharmony_ci            if ( ms->depth > 8 )
8053141cc406Sopenharmony_ci              {
8054141cc406Sopenharmony_ci                val16 = (uint16_t) val;
8055141cc406Sopenharmony_ci                if ( gamma_by_backend )
8056141cc406Sopenharmony_ci                    val16 = *((uint16_t *) ms->gamma_table + val16);
8057141cc406Sopenharmony_ci                if ( !( md->model_flags & MD_16BIT_TRANSFER ) )
8058141cc406Sopenharmony_ci                    val16 = ( val16 << scale1 ) | ( val16 >> scale2 );
8059141cc406Sopenharmony_ci                fwrite((void *) &val16, 2, 1, ms->fp);
8060141cc406Sopenharmony_ci              }
8061141cc406Sopenharmony_ci
8062141cc406Sopenharmony_ci            if ( ms->depth == 8 )
8063141cc406Sopenharmony_ci              {
8064141cc406Sopenharmony_ci                val8  = (uint8_t)  val;
8065141cc406Sopenharmony_ci                if ( gamma_by_backend )
8066141cc406Sopenharmony_ci                    val8 =  ms->gamma_table[(int)val8];
8067141cc406Sopenharmony_ci                fputc((char)val8, ms->fp);
8068141cc406Sopenharmony_ci              }
8069141cc406Sopenharmony_ci            from += step;
8070141cc406Sopenharmony_ci          }
8071141cc406Sopenharmony_ci      }
8072141cc406Sopenharmony_ci    else if ( ms->depth == 4 )
8073141cc406Sopenharmony_ci      {
8074141cc406Sopenharmony_ci        pixel = 0;
8075141cc406Sopenharmony_ci        while ( pixel < ms->ppl )
8076141cc406Sopenharmony_ci          {
8077141cc406Sopenharmony_ci            fputc((char) ( ((*from >> 4) & 0x0f) | (*from & 0xf0) ), ms->fp);
8078141cc406Sopenharmony_ci            ++pixel;
8079141cc406Sopenharmony_ci            if ( pixel < ms->ppl )
8080141cc406Sopenharmony_ci                fputc((char) ((*from & 0x0f) | ((*from << 4) & 0xf0)), ms->fp);
8081141cc406Sopenharmony_ci            from += step;
8082141cc406Sopenharmony_ci            ++pixel;
8083141cc406Sopenharmony_ci          }
8084141cc406Sopenharmony_ci      }
8085141cc406Sopenharmony_ci    else
8086141cc406Sopenharmony_ci      {
8087141cc406Sopenharmony_ci        DBG(1, "gray_copy_pixels: Unknown depth %d\n", ms->depth);
8088141cc406Sopenharmony_ci        return SANE_STATUS_IO_ERROR;
8089141cc406Sopenharmony_ci      }
8090141cc406Sopenharmony_ci
8091141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
8092141cc406Sopenharmony_ci}
8093141cc406Sopenharmony_ci
8094141cc406Sopenharmony_ci/*---------- proc_onebit_data() ----------------------------------------------*/
8095141cc406Sopenharmony_ci
8096141cc406Sopenharmony_cistatic SANE_Status
8097141cc406Sopenharmony_ciproc_onebit_data(Microtek2_Scanner *ms)
8098141cc406Sopenharmony_ci{
8099141cc406Sopenharmony_ci    Microtek2_Device *md;
8100141cc406Sopenharmony_ci    Microtek2_Info *mi;
8101141cc406Sopenharmony_ci    uint32_t bytes_to_copy;     /* bytes per line to copy */
8102141cc406Sopenharmony_ci    uint32_t line;
8103141cc406Sopenharmony_ci    uint32_t byte;
8104141cc406Sopenharmony_ci    uint32_t ppl;
8105141cc406Sopenharmony_ci    uint8_t *from;
8106141cc406Sopenharmony_ci    uint8_t to;
8107141cc406Sopenharmony_ci    int right_to_left;
8108141cc406Sopenharmony_ci    int bit;
8109141cc406Sopenharmony_ci    int toindex;
8110141cc406Sopenharmony_ci
8111141cc406Sopenharmony_ci
8112141cc406Sopenharmony_ci    DBG(30, "proc_onebit_data: ms=%p\n", (void *) ms);
8113141cc406Sopenharmony_ci
8114141cc406Sopenharmony_ci    md = ms->dev;
8115141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
8116141cc406Sopenharmony_ci    from = ms->buf.src_buf;
8117141cc406Sopenharmony_ci    bytes_to_copy = ( ms->ppl + 7 ) / 8 ;
8118141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
8119141cc406Sopenharmony_ci
8120141cc406Sopenharmony_ci    DBG(30, "proc_onebit_data: bytes_to_copy=%d, lines=%d\n",
8121141cc406Sopenharmony_ci             bytes_to_copy, ms->src_lines_to_read);
8122141cc406Sopenharmony_ci
8123141cc406Sopenharmony_ci    line = 0;
8124141cc406Sopenharmony_ci    to = 0;
8125141cc406Sopenharmony_ci    do
8126141cc406Sopenharmony_ci      {
8127141cc406Sopenharmony_ci        /* in onebit mode black and white colors are inverted */
8128141cc406Sopenharmony_ci        if ( right_to_left )
8129141cc406Sopenharmony_ci          {
8130141cc406Sopenharmony_ci            /* If the direction is right_to_left, we must skip some */
8131141cc406Sopenharmony_ci            /* trailing bits at the end of the scan line and invert the */
8132141cc406Sopenharmony_ci            /* bit sequence. We copy 8 bits into a byte, but these bits */
8133141cc406Sopenharmony_ci            /* are normally not byte aligned. */
8134141cc406Sopenharmony_ci
8135141cc406Sopenharmony_ci            /* Determine the position of the first bit to copy */
8136141cc406Sopenharmony_ci            ppl = ms->ppl;
8137141cc406Sopenharmony_ci            byte = ( ppl + 7 ) / 8 - 1;
8138141cc406Sopenharmony_ci            bit = ppl % 8 - 1;
8139141cc406Sopenharmony_ci            to = 0;
8140141cc406Sopenharmony_ci            toindex = 8;
8141141cc406Sopenharmony_ci
8142141cc406Sopenharmony_ci            while ( ppl > 0 )
8143141cc406Sopenharmony_ci              {
8144141cc406Sopenharmony_ci                to |= ( ( from[byte] >> (7 - bit) ) & 0x01);
8145141cc406Sopenharmony_ci                --toindex;
8146141cc406Sopenharmony_ci                if ( toindex == 0 )
8147141cc406Sopenharmony_ci                  {
8148141cc406Sopenharmony_ci                    fputc( (char) ~to, ms->fp);
8149141cc406Sopenharmony_ci                    toindex = 8;
8150141cc406Sopenharmony_ci                    to = 0;
8151141cc406Sopenharmony_ci                  }
8152141cc406Sopenharmony_ci                else
8153141cc406Sopenharmony_ci                    to <<= 1;
8154141cc406Sopenharmony_ci
8155141cc406Sopenharmony_ci                --bit;
8156141cc406Sopenharmony_ci                if ( bit < 0 )
8157141cc406Sopenharmony_ci                  {
8158141cc406Sopenharmony_ci                    bit = 7;
8159141cc406Sopenharmony_ci                    --byte;
8160141cc406Sopenharmony_ci                  }
8161141cc406Sopenharmony_ci                --ppl;
8162141cc406Sopenharmony_ci              }
8163141cc406Sopenharmony_ci            /* print the last byte of the line, if it was not */
8164141cc406Sopenharmony_ci            /*  completely filled */
8165141cc406Sopenharmony_ci            bit = ms->ppl % 8;
8166141cc406Sopenharmony_ci            if ( bit != 0 )
8167141cc406Sopenharmony_ci                fputc( (char) ~(to << (7 - bit)), ms->fp);
8168141cc406Sopenharmony_ci          }
8169141cc406Sopenharmony_ci        else
8170141cc406Sopenharmony_ci            for ( byte = 0; byte < bytes_to_copy; byte++ )
8171141cc406Sopenharmony_ci                fputc( (char) ~from[byte], ms->fp);
8172141cc406Sopenharmony_ci
8173141cc406Sopenharmony_ci        from += ms->bpl;
8174141cc406Sopenharmony_ci
8175141cc406Sopenharmony_ci      } while ( ++line < (uint32_t) ms->src_lines_to_read );
8176141cc406Sopenharmony_ci
8177141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
8178141cc406Sopenharmony_ci}
8179141cc406Sopenharmony_ci
8180141cc406Sopenharmony_ci
8181141cc406Sopenharmony_ci/*---------- lineartfake_proc_data() -----------------------------------------*/
8182141cc406Sopenharmony_ci
8183141cc406Sopenharmony_cistatic SANE_Status
8184141cc406Sopenharmony_cilineartfake_proc_data(Microtek2_Scanner *ms)
8185141cc406Sopenharmony_ci{
8186141cc406Sopenharmony_ci    Microtek2_Device *md;
8187141cc406Sopenharmony_ci    Microtek2_Info *mi;
8188141cc406Sopenharmony_ci    SANE_Status status;
8189141cc406Sopenharmony_ci    uint8_t *from;
8190141cc406Sopenharmony_ci    int right_to_left;
8191141cc406Sopenharmony_ci
8192141cc406Sopenharmony_ci
8193141cc406Sopenharmony_ci    DBG(30, "lineartfake_proc_data: lines=%d, bpl=%d, ppl=%d, depth=%d\n",
8194141cc406Sopenharmony_ci             ms->src_lines_to_read, ms->bpl, ms->ppl, ms->depth);
8195141cc406Sopenharmony_ci
8196141cc406Sopenharmony_ci    md = ms->dev;
8197141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
8198141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
8199141cc406Sopenharmony_ci
8200141cc406Sopenharmony_ci    if ( right_to_left == 1 )
8201141cc406Sopenharmony_ci        from = ms->buf.src_buf + ms->ppl - 1;
8202141cc406Sopenharmony_ci    else
8203141cc406Sopenharmony_ci        from = ms->buf.src_buf;
8204141cc406Sopenharmony_ci
8205141cc406Sopenharmony_ci    do
8206141cc406Sopenharmony_ci      {
8207141cc406Sopenharmony_ci        status = lineartfake_copy_pixels(ms,
8208141cc406Sopenharmony_ci                                         from,
8209141cc406Sopenharmony_ci                                         ms->ppl,
8210141cc406Sopenharmony_ci                                         ms->threshold,
8211141cc406Sopenharmony_ci                                         right_to_left,
8212141cc406Sopenharmony_ci                                         ms->fp);
8213141cc406Sopenharmony_ci        if ( status != SANE_STATUS_GOOD )
8214141cc406Sopenharmony_ci            return status;
8215141cc406Sopenharmony_ci
8216141cc406Sopenharmony_ci        from += ms->bpl;
8217141cc406Sopenharmony_ci        --ms->src_lines_to_read;
8218141cc406Sopenharmony_ci      } while ( ms->src_lines_to_read > 0 );
8219141cc406Sopenharmony_ci
8220141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
8221141cc406Sopenharmony_ci}
8222141cc406Sopenharmony_ci
8223141cc406Sopenharmony_ci/*---------- lineartfake_copy_pixels() ---------------------------------------*/
8224141cc406Sopenharmony_ci
8225141cc406Sopenharmony_cistatic SANE_Status
8226141cc406Sopenharmony_cilineartfake_copy_pixels(Microtek2_Scanner *ms,
8227141cc406Sopenharmony_ci                        uint8_t *from,
8228141cc406Sopenharmony_ci                        uint32_t pixels,
8229141cc406Sopenharmony_ci                        uint8_t threshold,
8230141cc406Sopenharmony_ci                        int right_to_left,
8231141cc406Sopenharmony_ci                        FILE *fp)
8232141cc406Sopenharmony_ci{
8233141cc406Sopenharmony_ci    Microtek2_Device *md;
8234141cc406Sopenharmony_ci    uint32_t pixel;
8235141cc406Sopenharmony_ci    uint32_t bit;
8236141cc406Sopenharmony_ci    uint8_t dest;
8237141cc406Sopenharmony_ci    uint8_t val;
8238141cc406Sopenharmony_ci    float s_d, s_w, maxval, shading_factor, grayval;
8239141cc406Sopenharmony_ci    int step;
8240141cc406Sopenharmony_ci
8241141cc406Sopenharmony_ci
8242141cc406Sopenharmony_ci    DBG(30, "lineartfake_copy_pixels: from=%p,pixels=%d,threshold=%d,file=%p\n",
8243141cc406Sopenharmony_ci             (void *) from, pixels, threshold, (void *) fp);
8244141cc406Sopenharmony_ci    md = ms->dev;
8245141cc406Sopenharmony_ci    bit = 0;
8246141cc406Sopenharmony_ci    dest = 0;
8247141cc406Sopenharmony_ci    step = right_to_left == 1 ? -1 : 1;
8248141cc406Sopenharmony_ci    maxval = 255.0;
8249141cc406Sopenharmony_ci    s_w = maxval;
8250141cc406Sopenharmony_ci    s_d = 0.0;
8251141cc406Sopenharmony_ci    shading_factor = (float) pow(2.0, (double) (md->shading_depth - 8) );
8252141cc406Sopenharmony_ci
8253141cc406Sopenharmony_ci    for ( pixel = 0; pixel < pixels; pixel++ )
8254141cc406Sopenharmony_ci      {
8255141cc406Sopenharmony_ci        if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend
8256141cc406Sopenharmony_ci             && ( ms->condensed_shading_w != NULL ))
8257141cc406Sopenharmony_ci             /* apply shading by backend */
8258141cc406Sopenharmony_ci          {
8259141cc406Sopenharmony_ci            get_cshading_values(ms,
8260141cc406Sopenharmony_ci                                0,
8261141cc406Sopenharmony_ci                                pixel,
8262141cc406Sopenharmony_ci                                shading_factor,
8263141cc406Sopenharmony_ci                                right_to_left,
8264141cc406Sopenharmony_ci                                &s_d,
8265141cc406Sopenharmony_ci                                &s_w);
8266141cc406Sopenharmony_ci          }
8267141cc406Sopenharmony_ci        else    /* no shading */
8268141cc406Sopenharmony_ci          {
8269141cc406Sopenharmony_ci            s_w = maxval;
8270141cc406Sopenharmony_ci            s_d = 0.0;
8271141cc406Sopenharmony_ci          }
8272141cc406Sopenharmony_ci
8273141cc406Sopenharmony_ci        grayval = (float) *from;
8274141cc406Sopenharmony_ci
8275141cc406Sopenharmony_ci        if ( grayval < s_d ) grayval = s_d;
8276141cc406Sopenharmony_ci        grayval = ( grayval - s_d ) * maxval / (s_w - s_d );
8277141cc406Sopenharmony_ci        grayval = MAX( 0.0, grayval );
8278141cc406Sopenharmony_ci        grayval = MIN( maxval, grayval );
8279141cc406Sopenharmony_ci
8280141cc406Sopenharmony_ci        if ( (uint8_t)grayval < threshold ) val = 1; else val = 0;
8281141cc406Sopenharmony_ci        dest = ( dest << 1 ) | val;
8282141cc406Sopenharmony_ci        bit = ( bit + 1 ) % 8;
8283141cc406Sopenharmony_ci        if ( bit == 0 )                   /* 8 input bytes processed */
8284141cc406Sopenharmony_ci          {
8285141cc406Sopenharmony_ci            fputc((char) dest, fp);
8286141cc406Sopenharmony_ci            dest = 0;
8287141cc406Sopenharmony_ci          }
8288141cc406Sopenharmony_ci        from += step;
8289141cc406Sopenharmony_ci      }
8290141cc406Sopenharmony_ci
8291141cc406Sopenharmony_ci    if ( bit != 0 )
8292141cc406Sopenharmony_ci      {
8293141cc406Sopenharmony_ci        dest <<= 7 - bit;
8294141cc406Sopenharmony_ci        fputc((char) dest, fp);
8295141cc406Sopenharmony_ci      }
8296141cc406Sopenharmony_ci
8297141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
8298141cc406Sopenharmony_ci}
8299141cc406Sopenharmony_ci
8300141cc406Sopenharmony_ci/*---------- auto_adjust_proc_data() -----------------------------------------*/
8301141cc406Sopenharmony_ci
8302141cc406Sopenharmony_cistatic SANE_Status
8303141cc406Sopenharmony_ciauto_adjust_proc_data(Microtek2_Scanner *ms, uint8_t **temp_current)
8304141cc406Sopenharmony_ci{
8305141cc406Sopenharmony_ci    Microtek2_Device *md;
8306141cc406Sopenharmony_ci    Microtek2_Info *mi;
8307141cc406Sopenharmony_ci    SANE_Status status;
8308141cc406Sopenharmony_ci    uint8_t *from;
8309141cc406Sopenharmony_ci    uint32_t line;
8310141cc406Sopenharmony_ci    uint32_t lines;
8311141cc406Sopenharmony_ci    uint32_t pixel;
8312141cc406Sopenharmony_ci    uint32_t threshold;
8313141cc406Sopenharmony_ci    int right_to_left;
8314141cc406Sopenharmony_ci
8315141cc406Sopenharmony_ci
8316141cc406Sopenharmony_ci    DBG(30, "auto_adjust_proc_data: ms=%p, temp_current=%p\n",
8317141cc406Sopenharmony_ci             (void *) ms, (void *) *temp_current);
8318141cc406Sopenharmony_ci
8319141cc406Sopenharmony_ci    md = ms->dev;
8320141cc406Sopenharmony_ci    mi = &md->info[md->scan_source];
8321141cc406Sopenharmony_ci    right_to_left = mi->direction & MI_DATSEQ_RTOL;
8322141cc406Sopenharmony_ci
8323141cc406Sopenharmony_ci    memcpy(*temp_current, ms->buf.src_buf, ms->transfer_length);
8324141cc406Sopenharmony_ci    *temp_current += ms->transfer_length;
8325141cc406Sopenharmony_ci    threshold = 0;
8326141cc406Sopenharmony_ci    status = SANE_STATUS_GOOD;
8327141cc406Sopenharmony_ci
8328141cc406Sopenharmony_ci    if ( ms->src_remaining_lines == 0 ) /* we have read all the image data, */
8329141cc406Sopenharmony_ci      {                                 /* calculate threshold value */
8330141cc406Sopenharmony_ci        for ( pixel = 0; pixel < ms->remaining_bytes; pixel++ )
8331141cc406Sopenharmony_ci            threshold += *(ms->temporary_buffer + pixel);
8332141cc406Sopenharmony_ci
8333141cc406Sopenharmony_ci        threshold /= ms->remaining_bytes;
8334141cc406Sopenharmony_ci        lines = ms->remaining_bytes / ms->bpl;
8335141cc406Sopenharmony_ci        for ( line = 0; line < lines; line++ )
8336141cc406Sopenharmony_ci          {
8337141cc406Sopenharmony_ci            from = ms->temporary_buffer + line * ms->bpl;
8338141cc406Sopenharmony_ci            if ( right_to_left == 1 )
8339141cc406Sopenharmony_ci                from += ms->ppl - 1;
8340141cc406Sopenharmony_ci            status = lineartfake_copy_pixels(ms,
8341141cc406Sopenharmony_ci                                             from,
8342141cc406Sopenharmony_ci                                             ms->ppl,
8343141cc406Sopenharmony_ci                                             (uint8_t) threshold,
8344141cc406Sopenharmony_ci                                             right_to_left,
8345141cc406Sopenharmony_ci                                             ms->fp);
8346141cc406Sopenharmony_ci          }
8347141cc406Sopenharmony_ci        *temp_current = NULL;
8348141cc406Sopenharmony_ci      }
8349141cc406Sopenharmony_ci
8350141cc406Sopenharmony_ci    return status;
8351141cc406Sopenharmony_ci}
8352141cc406Sopenharmony_ci
8353141cc406Sopenharmony_ci/*-------------- get_cshading_values -----------------------------------------*/
8354141cc406Sopenharmony_ci
8355141cc406Sopenharmony_cistatic SANE_Status
8356141cc406Sopenharmony_ciget_cshading_values(Microtek2_Scanner *ms,
8357141cc406Sopenharmony_ci                    uint8_t color,
8358141cc406Sopenharmony_ci                    uint32_t pixel,
8359141cc406Sopenharmony_ci                    float shading_factor,
8360141cc406Sopenharmony_ci                    int right_to_left,
8361141cc406Sopenharmony_ci                    float *s_d,
8362141cc406Sopenharmony_ci                    float *s_w)
8363141cc406Sopenharmony_ci{
8364141cc406Sopenharmony_ci  Microtek2_Device *md;
8365141cc406Sopenharmony_ci  uint32_t csh_offset;
8366141cc406Sopenharmony_ci
8367141cc406Sopenharmony_ci  md = ms->dev;
8368141cc406Sopenharmony_ci
8369141cc406Sopenharmony_ci  if ( right_to_left == 1 )
8370141cc406Sopenharmony_ci    csh_offset = (color + 1) * ms->ppl - 1 - pixel;
8371141cc406Sopenharmony_ci  else
8372141cc406Sopenharmony_ci    csh_offset = color * ms->ppl + pixel;
8373141cc406Sopenharmony_ci
8374141cc406Sopenharmony_ci  if ( ( md->shading_depth > 8 ) && ( ms->lut_entry_size == 2) )
8375141cc406Sopenharmony_ci    /* condensed shading is 2 byte color data */
8376141cc406Sopenharmony_ci    {
8377141cc406Sopenharmony_ci      if ( ms->condensed_shading_d != NULL )
8378141cc406Sopenharmony_ci          *s_d = (float) *( (uint16_t *)ms->condensed_shading_d
8379141cc406Sopenharmony_ci                                         + csh_offset );
8380141cc406Sopenharmony_ci      else
8381141cc406Sopenharmony_ci          *s_d = 0.0;
8382141cc406Sopenharmony_ci
8383141cc406Sopenharmony_ci      *s_w = (float) *( (uint16_t *)ms->condensed_shading_w
8384141cc406Sopenharmony_ci                                     + csh_offset );
8385141cc406Sopenharmony_ci      *s_w /= shading_factor;
8386141cc406Sopenharmony_ci      *s_d /= shading_factor;
8387141cc406Sopenharmony_ci    }
8388141cc406Sopenharmony_ci
8389141cc406Sopenharmony_ci  else
8390141cc406Sopenharmony_ci    /* condensed shading is 8 bit data */
8391141cc406Sopenharmony_ci    {
8392141cc406Sopenharmony_ci      *s_w = (float) *( ms->condensed_shading_w + csh_offset );
8393141cc406Sopenharmony_ci      if ( ms->condensed_shading_d != NULL )
8394141cc406Sopenharmony_ci        *s_d = (float) *( ms->condensed_shading_d + csh_offset );
8395141cc406Sopenharmony_ci      else
8396141cc406Sopenharmony_ci        *s_d = 0.0;
8397141cc406Sopenharmony_ci    }
8398141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
8399141cc406Sopenharmony_ci}
8400