1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 1997-2005, 2013 Franck Schnefra, Michel Roelofs,
4141cc406Sopenharmony_ci   Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller,
5141cc406Sopenharmony_ci   Simon Munton, Petter Reinholdtsen, Gary Plewa, Sebastien Sable,
6141cc406Sopenharmony_ci   Mikael Magnusson, Max Ushakov, Andrew Goodbody, Oliver Schwartz
7141cc406Sopenharmony_ci   and Kevin Charter
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   This file is a component of the implementation of a backend for many
46141cc406Sopenharmony_ci   of the AGFA SnapScan and Acer Vuego/Prisa flatbed scanners.
47141cc406Sopenharmony_ci*/
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci/*
50141cc406Sopenharmony_ci   SANE SnapScan backend
51141cc406Sopenharmony_ci*/
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci#include "../include/sane/config.h"
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#include <errno.h>
56141cc406Sopenharmony_ci#include <fcntl.h>
57141cc406Sopenharmony_ci#include <limits.h>
58141cc406Sopenharmony_ci#include <math.h>
59141cc406Sopenharmony_ci#include <signal.h>
60141cc406Sopenharmony_ci#include <stdio.h>
61141cc406Sopenharmony_ci#include <stdlib.h>
62141cc406Sopenharmony_ci#include <string.h>
63141cc406Sopenharmony_ci#include <unistd.h>
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci#include <sys/stat.h>
66141cc406Sopenharmony_ci#include <sys/time.h>
67141cc406Sopenharmony_ci#include <sys/types.h>
68141cc406Sopenharmony_ci#include <sys/wait.h>
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci#include "../include/sane/sane.h"
71141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_scsi.h"
73141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
74141cc406Sopenharmony_ci#include "../include/sane/sanei_thread.h"
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci#ifndef PATH_MAX
77141cc406Sopenharmony_ci#define PATH_MAX        1024
78141cc406Sopenharmony_ci#endif
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci#define MINOR_VERSION        4
81141cc406Sopenharmony_ci#define BUILD               53
82141cc406Sopenharmony_ci#define BACKEND_NAME snapscan
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
85141cc406Sopenharmony_ci#include "../include/sane/saneopts.h"
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_ci#include "snapscan.h"
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci#define MIN(x,y) ((x)<(y) ? (x) : (y))
90141cc406Sopenharmony_ci#define MAX(x,y) ((x)>(y) ? (x) : (y))
91141cc406Sopenharmony_ci#define LIMIT(x,min,max) MIN(MAX(x, min), max)
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_ci#ifdef INOPERATIVE
94141cc406Sopenharmony_ci#define P_200_TO_255(per) SANE_UNFIX(255.0*((per + 100)/200.0))
95141cc406Sopenharmony_ci#endif
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
98141cc406Sopenharmony_ci
99141cc406Sopenharmony_ci/* debug levels */
100141cc406Sopenharmony_ci#define DL_INFO         10
101141cc406Sopenharmony_ci#define DL_MINOR_INFO   15
102141cc406Sopenharmony_ci#define DL_MAJOR_ERROR  1
103141cc406Sopenharmony_ci#define DL_MINOR_ERROR  2
104141cc406Sopenharmony_ci#define DL_DATA_TRACE   50
105141cc406Sopenharmony_ci#define DL_OPTION_TRACE 70
106141cc406Sopenharmony_ci#define DL_CALL_TRACE   30
107141cc406Sopenharmony_ci#define DL_VERBOSE      20
108141cc406Sopenharmony_ci
109141cc406Sopenharmony_ci#define CHECK_STATUS(s,caller,cmd) \
110141cc406Sopenharmony_ciif ((s) != SANE_STATUS_GOOD) { DBG(DL_MAJOR_ERROR, "%s: %s command failed: %s\n", caller, (cmd), sane_strstatus(s)); return s; }
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci/*----- internal scanner operations -----*/
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci/* hardware configuration byte masks */
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci#define HCFG_ADC         0x80         /* AD converter 1 ==> 10bit, 0 ==> 8bit */
117141cc406Sopenharmony_ci#define HCFG_ADF         0x40         /* automatic document feeder */
118141cc406Sopenharmony_ci#define HCFG_TPO         0x20         /* transparency option */
119141cc406Sopenharmony_ci#define HCFG_RB          0x10         /* ring buffer */
120141cc406Sopenharmony_ci#define HCFG_HT16        0x08         /* 16x16 halftone matrices */
121141cc406Sopenharmony_ci#define HCFG_HT8         0x04         /* 8x8 halftone matrices */
122141cc406Sopenharmony_ci#define HCFG_SRA         0x02         /* scanline row average (high-speed colour) */
123141cc406Sopenharmony_ci#define HCFG_CAL_ALLOWED 0x01         /* 1 ==> calibration allowed */
124141cc406Sopenharmony_ci
125141cc406Sopenharmony_ci#define HCFG_HT   0x0C                /* support halftone matrices at all */
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ci#define MM_PER_IN 25.4                /* # millimetres per inch */
128141cc406Sopenharmony_ci#define IN_PER_MM 0.03937        /* # inches per millimetre  */
129141cc406Sopenharmony_ci
130141cc406Sopenharmony_ci#define GAMMA_8BIT	0
131141cc406Sopenharmony_ci#define GAMMA_16BIT	1
132141cc406Sopenharmony_ci#define GAMMA_12_16BIT	2
133141cc406Sopenharmony_ci
134141cc406Sopenharmony_ci#ifndef SANE_I18N
135141cc406Sopenharmony_ci#define SANE_I18N(text) text
136141cc406Sopenharmony_ci#endif
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci/* authorization stuff */
139141cc406Sopenharmony_cistatic SANE_Auth_Callback auth = NULL;
140141cc406Sopenharmony_ci#if UNUSED
141141cc406Sopenharmony_cistatic SANE_Char username[SANE_MAX_USERNAME_LEN];
142141cc406Sopenharmony_cistatic SANE_Char password[SANE_MAX_PASSWORD_LEN];
143141cc406Sopenharmony_ci#endif
144141cc406Sopenharmony_ci
145141cc406Sopenharmony_ci/* function prototypes */
146141cc406Sopenharmony_ci
147141cc406Sopenharmony_cistatic void gamma_n (double gamma, int brightness, int contrast,
148141cc406Sopenharmony_ci                     u_char *buf, int length, int gamma_mode);
149141cc406Sopenharmony_cistatic void gamma_to_sane (int length, u_char *in, SANE_Int *out);
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_cistatic size_t max_string_size(SANE_String_Const strings[]);
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci/* inline functions */
154141cc406Sopenharmony_cistatic inline SnapScan_Mode actual_mode (SnapScan_Scanner *pss)
155141cc406Sopenharmony_ci{
156141cc406Sopenharmony_ci    if (pss->preview == SANE_TRUE)
157141cc406Sopenharmony_ci        return pss->preview_mode;
158141cc406Sopenharmony_ci    return pss->mode;
159141cc406Sopenharmony_ci}
160141cc406Sopenharmony_ci
161141cc406Sopenharmony_cistatic inline int is_colour_mode (SnapScan_Mode m)
162141cc406Sopenharmony_ci{
163141cc406Sopenharmony_ci    return (m == MD_COLOUR) || (m == MD_BILEVELCOLOUR);
164141cc406Sopenharmony_ci}
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_cistatic inline int calibration_line_length(SnapScan_Scanner *pss)
167141cc406Sopenharmony_ci{
168141cc406Sopenharmony_ci    int pos_factor;
169141cc406Sopenharmony_ci    int pixel_length;
170141cc406Sopenharmony_ci
171141cc406Sopenharmony_ci    switch (pss->pdev->model)
172141cc406Sopenharmony_ci    {
173141cc406Sopenharmony_ci    case STYLUS_CX1500:
174141cc406Sopenharmony_ci    case PRISA5000E:
175141cc406Sopenharmony_ci    case PRISA5000:
176141cc406Sopenharmony_ci    case PRISA5150:
177141cc406Sopenharmony_ci    case PERFECTION1270:
178141cc406Sopenharmony_ci    case PERFECTION1670:
179141cc406Sopenharmony_ci    case PERFECTION2480:
180141cc406Sopenharmony_ci    case PERFECTION3490:
181141cc406Sopenharmony_ci        pos_factor = pss->actual_res / 2;
182141cc406Sopenharmony_ci        pixel_length = pos_factor * 8.5;
183141cc406Sopenharmony_ci        break;
184141cc406Sopenharmony_ci    case SCANWIT2720S:
185141cc406Sopenharmony_ci        pixel_length = 2550;
186141cc406Sopenharmony_ci        break;
187141cc406Sopenharmony_ci    default:
188141cc406Sopenharmony_ci        pos_factor = pss->actual_res;
189141cc406Sopenharmony_ci        pixel_length = pos_factor * 8.5;
190141cc406Sopenharmony_ci        break;
191141cc406Sopenharmony_ci    }
192141cc406Sopenharmony_ci
193141cc406Sopenharmony_ci    if(is_colour_mode(actual_mode(pss))) {
194141cc406Sopenharmony_ci        return 3 * pixel_length;
195141cc406Sopenharmony_ci    } else {
196141cc406Sopenharmony_ci        return pixel_length;
197141cc406Sopenharmony_ci    }
198141cc406Sopenharmony_ci}
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci/*----- global data structures and access utilities -----*/
201141cc406Sopenharmony_ci
202141cc406Sopenharmony_ci/* available device list */
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_cistatic SnapScan_Device *first_device = NULL;        /* device list head */
205141cc406Sopenharmony_cistatic SANE_Int n_devices = 0;                           /* the device count */
206141cc406Sopenharmony_cistatic SANE_Char *default_firmware_filename;
207141cc406Sopenharmony_cistatic SANE_Bool cancelRead;
208141cc406Sopenharmony_ci
209141cc406Sopenharmony_ci/* list returned from sane_get_devices() */
210141cc406Sopenharmony_cistatic const SANE_Device **get_devices_list = NULL;
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci/* external routines */
213141cc406Sopenharmony_ci#include "snapscan-scsi.c"
214141cc406Sopenharmony_ci#include "snapscan-sources.c"
215141cc406Sopenharmony_ci#include "snapscan-usb.c"
216141cc406Sopenharmony_ci#include "snapscan-options.c"
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci/* Initialize gamma tables */
219141cc406Sopenharmony_cistatic SANE_Status alloc_gamma_tables(SnapScan_Scanner * ps)
220141cc406Sopenharmony_ci{
221141cc406Sopenharmony_ci    static const char me[] = "alloc_gamma_tables";
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci    ps->gamma_length = 1 << ps->bpp;
224141cc406Sopenharmony_ci    DBG (DL_MINOR_INFO, "%s: using 4*%d bytes for gamma table\n",
225141cc406Sopenharmony_ci         me,
226141cc406Sopenharmony_ci         ps->gamma_length);
227141cc406Sopenharmony_ci
228141cc406Sopenharmony_ci    ps->gamma_tables =
229141cc406Sopenharmony_ci        (SANE_Int *) malloc(4 * ps->gamma_length * sizeof(SANE_Int));
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci    if (!ps->gamma_tables)
232141cc406Sopenharmony_ci    {
233141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
234141cc406Sopenharmony_ci    }
235141cc406Sopenharmony_ci
236141cc406Sopenharmony_ci    ps->gamma_table_gs = &ps->gamma_tables[0 * ps->gamma_length];
237141cc406Sopenharmony_ci    ps->gamma_table_r = &ps->gamma_tables[1 * ps->gamma_length];
238141cc406Sopenharmony_ci    ps->gamma_table_g = &ps->gamma_tables[2 * ps->gamma_length];
239141cc406Sopenharmony_ci    ps->gamma_table_b = &ps->gamma_tables[3 * ps->gamma_length];
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
242141cc406Sopenharmony_ci}
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_cistatic SANE_Status init_gamma(SnapScan_Scanner * ps)
245141cc406Sopenharmony_ci{
246141cc406Sopenharmony_ci    u_char *gamma;
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci    gamma = (u_char*) malloc(ps->gamma_length * sizeof(u_char) * 2);
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci    if (!gamma)
251141cc406Sopenharmony_ci    {
252141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
253141cc406Sopenharmony_ci    }
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci    /* Default tables */
256141cc406Sopenharmony_ci    gamma_n (SANE_UNFIX(ps->gamma_gs), ps->bright, ps->contrast, gamma, ps->bpp, 1);
257141cc406Sopenharmony_ci    gamma_to_sane (ps->gamma_length, gamma, ps->gamma_table_gs);
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci    gamma_n (SANE_UNFIX(ps->gamma_r), ps->bright, ps->contrast, gamma, ps->bpp, 1);
260141cc406Sopenharmony_ci    gamma_to_sane (ps->gamma_length, gamma, ps->gamma_table_r);
261141cc406Sopenharmony_ci
262141cc406Sopenharmony_ci    gamma_n (SANE_UNFIX(ps->gamma_g), ps->bright, ps->contrast, gamma, ps->bpp, 1);
263141cc406Sopenharmony_ci    gamma_to_sane (ps->gamma_length, gamma, ps->gamma_table_g);
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ci    gamma_n (SANE_UNFIX(ps->gamma_b), ps->bright, ps->contrast, gamma, ps->bpp, 1);
266141cc406Sopenharmony_ci    gamma_to_sane (ps->gamma_length, gamma, ps->gamma_table_b);
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci    free (gamma);
269141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
270141cc406Sopenharmony_ci}
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_ci/* Max string size */
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_cistatic size_t max_string_size (SANE_String_Const strings[])
275141cc406Sopenharmony_ci{
276141cc406Sopenharmony_ci    size_t size;
277141cc406Sopenharmony_ci    size_t max_size = 0;
278141cc406Sopenharmony_ci    int i;
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_ci    for (i = 0;  strings[i];  ++i)
281141cc406Sopenharmony_ci    {
282141cc406Sopenharmony_ci        size = strlen (strings[i]) + 1;
283141cc406Sopenharmony_ci        if (size > max_size)
284141cc406Sopenharmony_ci            max_size = size;
285141cc406Sopenharmony_ci    }
286141cc406Sopenharmony_ci    return max_size;
287141cc406Sopenharmony_ci}
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci/* gamma table computation */
290141cc406Sopenharmony_cistatic void gamma_n (double gamma, int brightness, int contrast,
291141cc406Sopenharmony_ci                      u_char *buf, int bpp, int gamma_mode)
292141cc406Sopenharmony_ci{
293141cc406Sopenharmony_ci    int i;
294141cc406Sopenharmony_ci    double i_gamma = 1.0/gamma;
295141cc406Sopenharmony_ci    int length = 1 << bpp;
296141cc406Sopenharmony_ci    int max = length - 1;
297141cc406Sopenharmony_ci    double mid = max / 2.0;
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci    for (i = 0;  i < length;  i++)
300141cc406Sopenharmony_ci    {
301141cc406Sopenharmony_ci        int x;
302141cc406Sopenharmony_ci        double val = (i - mid) * (1.0 + contrast / 100.0)
303141cc406Sopenharmony_ci            + (1.0 + brightness / 100.0) * mid;
304141cc406Sopenharmony_ci        val = LIMIT(val, 0, max);
305141cc406Sopenharmony_ci        switch (gamma_mode)
306141cc406Sopenharmony_ci        {
307141cc406Sopenharmony_ci        case GAMMA_16BIT:
308141cc406Sopenharmony_ci            x = LIMIT(65535*pow ((double) val/max, i_gamma) + 0.5, 0, 65535);
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci            buf[2*i] = (u_char) x;
311141cc406Sopenharmony_ci            buf[2*i + 1] = (u_char) (x >> 8);
312141cc406Sopenharmony_ci            break;
313141cc406Sopenharmony_ci        case GAMMA_12_16BIT:
314141cc406Sopenharmony_ci            buf[2*i] = (u_char) i;
315141cc406Sopenharmony_ci            buf[2*i + 1] = (u_char) (i >> 8);
316141cc406Sopenharmony_ci            break;
317141cc406Sopenharmony_ci        case GAMMA_8BIT:
318141cc406Sopenharmony_ci            buf[i] =
319141cc406Sopenharmony_ci                (u_char) LIMIT(255*pow ((double) val/max, i_gamma) + 0.5, 0, 255);
320141cc406Sopenharmony_ci            break;
321141cc406Sopenharmony_ci        default:
322141cc406Sopenharmony_ci            break;
323141cc406Sopenharmony_ci        }
324141cc406Sopenharmony_ci    }
325141cc406Sopenharmony_ci}
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_cistatic void gamma_from_sane (int length, SANE_Int *in, u_char *out, int gamma_mode)
328141cc406Sopenharmony_ci{
329141cc406Sopenharmony_ci    int i;
330141cc406Sopenharmony_ci    for (i = 0; i < length; i++)
331141cc406Sopenharmony_ci        if (gamma_mode != GAMMA_8BIT)
332141cc406Sopenharmony_ci        {
333141cc406Sopenharmony_ci            out[2*i] = (u_char) LIMIT(in[i], 0, 65535);
334141cc406Sopenharmony_ci            out[2*i + 1] = (u_char) (LIMIT(in[i], 0, 65535) >> 8);
335141cc406Sopenharmony_ci        }
336141cc406Sopenharmony_ci        else
337141cc406Sopenharmony_ci            out[i] = (u_char) LIMIT(in[i] / 256, 0, 255);
338141cc406Sopenharmony_ci}
339141cc406Sopenharmony_ci
340141cc406Sopenharmony_cistatic void gamma_to_sane (int length, u_char *in, SANE_Int *out)
341141cc406Sopenharmony_ci{
342141cc406Sopenharmony_ci    int i;
343141cc406Sopenharmony_ci    for (i = 0; i < length; i++)
344141cc406Sopenharmony_ci        out[i] = in[2*i] + 256 * in[2*i + 1];
345141cc406Sopenharmony_ci}
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci/* dispersed-dot dither matrices; this is discussed in Foley, Van Dam,
348141cc406Sopenharmony_ci   Feiner and Hughes: Computer Graphics: principles and practice,
349141cc406Sopenharmony_ci   2nd ed. (Addison-Wesley), pp 570-571.
350141cc406Sopenharmony_ci
351141cc406Sopenharmony_ci   The function mfDn computes the nth dispersed-dot dither matrix Dn
352141cc406Sopenharmony_ci   given D(n/2) and n; n is presumed to be a power of 2. D8 and D16
353141cc406Sopenharmony_ci   are the matrices of interest to us, since the SnapScan supports
354141cc406Sopenharmony_ci   only 8x8 and 16x16 dither matrices. */
355141cc406Sopenharmony_ci
356141cc406Sopenharmony_cistatic u_char D2[] ={0, 2, 3, 1};
357141cc406Sopenharmony_ci
358141cc406Sopenharmony_cistatic u_char D4[16], D8[64], D16[256];
359141cc406Sopenharmony_ci
360141cc406Sopenharmony_cistatic void mkDn (u_char *Dn, u_char *Dn_half, unsigned n)
361141cc406Sopenharmony_ci{
362141cc406Sopenharmony_ci    unsigned int x, y;
363141cc406Sopenharmony_ci    for (y = 0; y < n; y++) {
364141cc406Sopenharmony_ci        for (x = 0; x < n; x++) {
365141cc406Sopenharmony_ci            /* Dn(x,y) = D2(2*x/n, 2*y/n) +4*Dn_half(x%(n/2), y%(n/2)) */
366141cc406Sopenharmony_ci            Dn[y*n + x] = D2[((int)(2*y/n))*2 + (int)(2*x/n)]
367141cc406Sopenharmony_ci                          + 4*Dn_half[(y%(n/2))*(n/2) + x%(n/2)];
368141cc406Sopenharmony_ci        }
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci}
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_cistatic SANE_Bool device_already_in_list (SnapScan_Device *current,
373141cc406Sopenharmony_ci                                         SANE_String_Const name)
374141cc406Sopenharmony_ci{
375141cc406Sopenharmony_ci    for (  ;  NULL != current;  current = current->pnext)
376141cc406Sopenharmony_ci    {
377141cc406Sopenharmony_ci        if (0 == strcmp (name, current->dev.name))
378141cc406Sopenharmony_ci            return SANE_TRUE;
379141cc406Sopenharmony_ci    }
380141cc406Sopenharmony_ci    return SANE_FALSE;
381141cc406Sopenharmony_ci}
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_cistatic SANE_Char* get_driver_name(SnapScan_Model model_num) {
384141cc406Sopenharmony_ci    SANE_Int i;
385141cc406Sopenharmony_ci    for (i=0; i<known_drivers; i++) {
386141cc406Sopenharmony_ci        if (drivers[i].id == model_num) break;
387141cc406Sopenharmony_ci    }
388141cc406Sopenharmony_ci    if (i == known_drivers) {
389141cc406Sopenharmony_ci        DBG(0, "Implementation error: Driver name not found\n");
390141cc406Sopenharmony_ci        return ("Unknown");
391141cc406Sopenharmony_ci    }
392141cc406Sopenharmony_ci    return (drivers[i].driver_name);
393141cc406Sopenharmony_ci}
394141cc406Sopenharmony_ci
395141cc406Sopenharmony_cistatic SANE_Status snapscani_check_device(
396141cc406Sopenharmony_ci    int fd,
397141cc406Sopenharmony_ci    SnapScan_Bus bus_type,
398141cc406Sopenharmony_ci    char* vendor,
399141cc406Sopenharmony_ci    char* model,
400141cc406Sopenharmony_ci    SnapScan_Model* model_num
401141cc406Sopenharmony_ci) {
402141cc406Sopenharmony_ci    static const char me[] = "snapscani_check_device";
403141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
404141cc406Sopenharmony_ci    int supported_vendor = 0;
405141cc406Sopenharmony_ci    int i;
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s()\n", me);
408141cc406Sopenharmony_ci
409141cc406Sopenharmony_ci    /* check that the device is legitimate */
410141cc406Sopenharmony_ci    if ((status = mini_inquiry (bus_type, fd, vendor, model)) != SANE_STATUS_GOOD)
411141cc406Sopenharmony_ci    {
412141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
413141cc406Sopenharmony_ci             "%s: mini_inquiry failed with %s.\n",
414141cc406Sopenharmony_ci             me,
415141cc406Sopenharmony_ci             sane_strstatus (status));
416141cc406Sopenharmony_ci        return status;
417141cc406Sopenharmony_ci    }
418141cc406Sopenharmony_ci
419141cc406Sopenharmony_ci    DBG (DL_VERBOSE,
420141cc406Sopenharmony_ci         "%s: Is vendor \"%s\" model \"%s\" a supported scanner?\n",
421141cc406Sopenharmony_ci         me,
422141cc406Sopenharmony_ci         vendor,
423141cc406Sopenharmony_ci         model);
424141cc406Sopenharmony_ci
425141cc406Sopenharmony_ci    /* check if this is one of our supported vendors */
426141cc406Sopenharmony_ci    for (i = 0;  i < known_vendors;  i++)
427141cc406Sopenharmony_ci    {
428141cc406Sopenharmony_ci        if (0 == strcasecmp (vendor, vendors[i]))
429141cc406Sopenharmony_ci        {
430141cc406Sopenharmony_ci            supported_vendor = 1;
431141cc406Sopenharmony_ci            break;
432141cc406Sopenharmony_ci        }
433141cc406Sopenharmony_ci    }
434141cc406Sopenharmony_ci    if (supported_vendor)
435141cc406Sopenharmony_ci    {
436141cc406Sopenharmony_ci        /* Known vendor.  Check if it is one of our supported models */
437141cc406Sopenharmony_ci        *model_num = snapscani_get_model_id(model, fd, bus_type);
438141cc406Sopenharmony_ci    }
439141cc406Sopenharmony_ci    if (!supported_vendor  ||  UNKNOWN == model_num)
440141cc406Sopenharmony_ci    {
441141cc406Sopenharmony_ci        DBG (DL_MINOR_ERROR,
442141cc406Sopenharmony_ci             "%s: \"%s %s\" is not one of %s\n",
443141cc406Sopenharmony_ci             me,
444141cc406Sopenharmony_ci             vendor,
445141cc406Sopenharmony_ci             model,
446141cc406Sopenharmony_ci             "AGFA SnapScan 300, 310, 600, 1212, 1236, e10, e20, e25, e26, "
447141cc406Sopenharmony_ci             "e40, e42, e50, e52 or e60\n"
448141cc406Sopenharmony_ci             "Acer 300, 310, 610, 610+, "
449141cc406Sopenharmony_ci             "620, 620+, 640, 1240, 3300, 4300 or 5300\n"
450141cc406Sopenharmony_ci             "Guillemot MaxiScan A4 Deluxe");
451141cc406Sopenharmony_ci        status = SANE_STATUS_INVAL;
452141cc406Sopenharmony_ci    } else {
453141cc406Sopenharmony_ci        DBG(DL_VERBOSE, "%s: Autodetected driver: %s\n", me, get_driver_name(*model_num));
454141cc406Sopenharmony_ci    }
455141cc406Sopenharmony_ci    return status;
456141cc406Sopenharmony_ci}
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_cistatic SANE_Status snapscani_init_device_structure(
459141cc406Sopenharmony_ci    SnapScan_Device **pd,
460141cc406Sopenharmony_ci    const SnapScan_Bus bus_type,
461141cc406Sopenharmony_ci    SANE_String_Const name,
462141cc406Sopenharmony_ci    const char* vendor,
463141cc406Sopenharmony_ci    const char* model,
464141cc406Sopenharmony_ci    const SnapScan_Model model_num
465141cc406Sopenharmony_ci) {
466141cc406Sopenharmony_ci    static const char me[] = "snapscani_init_device_structure";
467141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;;
468141cc406Sopenharmony_ci
469141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s()\n", me);
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci    (*pd) = (SnapScan_Device *) malloc (sizeof (SnapScan_Device));
472141cc406Sopenharmony_ci    if (!(*pd))
473141cc406Sopenharmony_ci    {
474141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR, "%s: out of memory allocating device.", me);
475141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
476141cc406Sopenharmony_ci    }
477141cc406Sopenharmony_ci    (*pd)->dev.name = strdup (name);
478141cc406Sopenharmony_ci    if (strcmp(vendor, "Color") == 0) {
479141cc406Sopenharmony_ci        (*pd)->dev.vendor = strdup ("Acer");
480141cc406Sopenharmony_ci    } else {
481141cc406Sopenharmony_ci        (*pd)->dev.vendor = strdup (vendor);
482141cc406Sopenharmony_ci    }
483141cc406Sopenharmony_ci    (*pd)->dev.model = strdup (model);
484141cc406Sopenharmony_ci    if (model_num == SCANWIT2720S)
485141cc406Sopenharmony_ci    {
486141cc406Sopenharmony_ci        (*pd)->dev.type = strdup (SNAPSCAN_FS_TYPE);
487141cc406Sopenharmony_ci    }
488141cc406Sopenharmony_ci    else
489141cc406Sopenharmony_ci    {
490141cc406Sopenharmony_ci        (*pd)->dev.type = strdup (SNAPSCAN_TYPE);
491141cc406Sopenharmony_ci    }
492141cc406Sopenharmony_ci    (*pd)->bus = bus_type;
493141cc406Sopenharmony_ci    (*pd)->model = model_num;
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci    if (!(*pd)->dev.name  ||  !(*pd)->dev.vendor  ||  !(*pd)->dev.model  ||  !(*pd)->dev.type)
496141cc406Sopenharmony_ci    {
497141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
498141cc406Sopenharmony_ci             "%s: out of memory allocating device descriptor strings.\n",
499141cc406Sopenharmony_ci             me);
500141cc406Sopenharmony_ci        free (*pd);
501141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
502141cc406Sopenharmony_ci    }
503141cc406Sopenharmony_ci    (*pd)->x_range.min = x_range_fb.min;
504141cc406Sopenharmony_ci    (*pd)->x_range.quant = x_range_fb.quant;
505141cc406Sopenharmony_ci    (*pd)->x_range.max = x_range_fb.max;
506141cc406Sopenharmony_ci    (*pd)->y_range.min = y_range_fb.min;
507141cc406Sopenharmony_ci    (*pd)->y_range.quant = y_range_fb.quant;
508141cc406Sopenharmony_ci    (*pd)->y_range.max = y_range_fb.max;
509141cc406Sopenharmony_ci    (*pd)->firmware_filename = NULL;
510141cc406Sopenharmony_ci
511141cc406Sopenharmony_ci    (*pd)->pnext = first_device;
512141cc406Sopenharmony_ci    first_device = (*pd);
513141cc406Sopenharmony_ci    n_devices++;
514141cc406Sopenharmony_ci    return status;
515141cc406Sopenharmony_ci}
516141cc406Sopenharmony_ci
517141cc406Sopenharmony_cistatic SANE_Status add_scsi_device (SANE_String_Const full_name)
518141cc406Sopenharmony_ci{
519141cc406Sopenharmony_ci    int fd;
520141cc406Sopenharmony_ci    static const char me[] = "add_scsi_device";
521141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
522141cc406Sopenharmony_ci    SnapScan_Device *pd;
523141cc406Sopenharmony_ci    SnapScan_Model model_num = UNKNOWN;
524141cc406Sopenharmony_ci    SnapScan_Bus bus_type = SCSI;
525141cc406Sopenharmony_ci    char vendor[8];
526141cc406Sopenharmony_ci    char model[17];
527141cc406Sopenharmony_ci    SANE_Char *name = NULL;
528141cc406Sopenharmony_ci
529141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s(%s)\n", me, full_name);
530141cc406Sopenharmony_ci
531141cc406Sopenharmony_ci    sanei_config_get_string(full_name, &name);
532141cc406Sopenharmony_ci    if (!name)
533141cc406Sopenharmony_ci    {
534141cc406Sopenharmony_ci    	return SANE_STATUS_INVAL;
535141cc406Sopenharmony_ci    }
536141cc406Sopenharmony_ci    /* Avoid adding the same device more then once */
537141cc406Sopenharmony_ci    if (device_already_in_list (first_device, name)) {
538141cc406Sopenharmony_ci        free(name);
539141cc406Sopenharmony_ci        name = 0;
540141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
541141cc406Sopenharmony_ci    }
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci    vendor[0] = model[0] = '\0';
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci    DBG (DL_VERBOSE, "%s: Detected (kind of) a SCSI device\n", me);
546141cc406Sopenharmony_ci
547141cc406Sopenharmony_ci    status = sanei_scsi_open (name, &fd, sense_handler, NULL);
548141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
549141cc406Sopenharmony_ci    {
550141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
551141cc406Sopenharmony_ci            "%s: error opening device %s: %s\n",
552141cc406Sopenharmony_ci            me,
553141cc406Sopenharmony_ci            name,
554141cc406Sopenharmony_ci            sane_strstatus (status));
555141cc406Sopenharmony_ci    } else {
556141cc406Sopenharmony_ci        status = snapscani_check_device(fd, bus_type, vendor, model, &model_num);
557141cc406Sopenharmony_ci        sanei_scsi_close(fd);
558141cc406Sopenharmony_ci    }
559141cc406Sopenharmony_ci    if (status == SANE_STATUS_GOOD) {
560141cc406Sopenharmony_ci        status = snapscani_init_device_structure(
561141cc406Sopenharmony_ci            &pd,
562141cc406Sopenharmony_ci            bus_type,
563141cc406Sopenharmony_ci            name,
564141cc406Sopenharmony_ci            vendor,
565141cc406Sopenharmony_ci            model,
566141cc406Sopenharmony_ci            model_num
567141cc406Sopenharmony_ci        );
568141cc406Sopenharmony_ci    }
569141cc406Sopenharmony_ci    free(name);
570141cc406Sopenharmony_ci    name = 0;
571141cc406Sopenharmony_ci    return status;
572141cc406Sopenharmony_ci}
573141cc406Sopenharmony_ci
574141cc406Sopenharmony_cistatic SANE_Status add_usb_device (SANE_String_Const full_name) {
575141cc406Sopenharmony_ci    static const char me[] = "add_usb_device";
576141cc406Sopenharmony_ci    int fd;
577141cc406Sopenharmony_ci    SnapScan_Device *pd;
578141cc406Sopenharmony_ci    SnapScan_Model model_num = UNKNOWN;
579141cc406Sopenharmony_ci    SANE_Word vendor_id, product_id;
580141cc406Sopenharmony_ci    int supported_usb_vendor = 0;
581141cc406Sopenharmony_ci    char vendor[8];
582141cc406Sopenharmony_ci    char model[17];
583141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
584141cc406Sopenharmony_ci    SnapScan_Bus bus_type = USB;
585141cc406Sopenharmony_ci    int i;
586141cc406Sopenharmony_ci    SANE_Char *name = NULL;
587141cc406Sopenharmony_ci
588141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s(%s)\n", me, full_name);
589141cc406Sopenharmony_ci    sanei_config_get_string(full_name, &name);
590141cc406Sopenharmony_ci    if (!name)
591141cc406Sopenharmony_ci    {
592141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
593141cc406Sopenharmony_ci    }
594141cc406Sopenharmony_ci    /* Avoid adding the same device more then once */
595141cc406Sopenharmony_ci    if (device_already_in_list (first_device, name)) {
596141cc406Sopenharmony_ci        free(name);
597141cc406Sopenharmony_ci        name = 0;
598141cc406Sopenharmony_ci        return SANE_STATUS_GOOD;
599141cc406Sopenharmony_ci    }
600141cc406Sopenharmony_ci
601141cc406Sopenharmony_ci    vendor[0] = model[0] = '\0';
602141cc406Sopenharmony_ci
603141cc406Sopenharmony_ci    DBG (DL_VERBOSE, "%s: Detected (kind of) an USB device\n", me);
604141cc406Sopenharmony_ci    bus_type = USB;
605141cc406Sopenharmony_ci    status = snapscani_usb_shm_init();
606141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
607141cc406Sopenharmony_ci    {
608141cc406Sopenharmony_ci        return status;
609141cc406Sopenharmony_ci    }
610141cc406Sopenharmony_ci    status = snapscani_usb_open (name, &fd, sense_handler, NULL);
611141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
612141cc406Sopenharmony_ci    {
613141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
614141cc406Sopenharmony_ci            "%s: error opening device %s: %s\n",
615141cc406Sopenharmony_ci            me,
616141cc406Sopenharmony_ci            name,
617141cc406Sopenharmony_ci            sane_strstatus (status));
618141cc406Sopenharmony_ci    } else {
619141cc406Sopenharmony_ci        if (sanei_usb_get_vendor_product(fd, &vendor_id, &product_id) ==
620141cc406Sopenharmony_ci                SANE_STATUS_GOOD)
621141cc406Sopenharmony_ci        {
622141cc406Sopenharmony_ci            /* check for known USB vendors to avoid hanging scanners by
623141cc406Sopenharmony_ci               inquiry-command.
624141cc406Sopenharmony_ci            */
625141cc406Sopenharmony_ci            DBG(DL_INFO, "%s: Checking if 0x%04x is a supported USB vendor ID\n",
626141cc406Sopenharmony_ci                me, vendor_id);
627141cc406Sopenharmony_ci            for (i = 0; i < known_usb_vendor_ids; i++) {
628141cc406Sopenharmony_ci                if (vendor_id == usb_vendor_ids[i]) {
629141cc406Sopenharmony_ci                    supported_usb_vendor = 1;
630141cc406Sopenharmony_ci                }
631141cc406Sopenharmony_ci            }
632141cc406Sopenharmony_ci            if (!supported_usb_vendor) {
633141cc406Sopenharmony_ci                DBG(DL_MINOR_ERROR,
634141cc406Sopenharmony_ci                    "%s: USB vendor ID 0x%04x is currently NOT supported by the snapscan backend.\n",
635141cc406Sopenharmony_ci                    me, vendor_id);
636141cc406Sopenharmony_ci                status=SANE_STATUS_INVAL;
637141cc406Sopenharmony_ci                snapscani_usb_close(fd);
638141cc406Sopenharmony_ci            }
639141cc406Sopenharmony_ci        }
640141cc406Sopenharmony_ci    }
641141cc406Sopenharmony_ci    if (status == SANE_STATUS_GOOD) {
642141cc406Sopenharmony_ci        status = snapscani_check_device(fd, bus_type, vendor, model, &model_num);
643141cc406Sopenharmony_ci        snapscani_usb_close(fd);
644141cc406Sopenharmony_ci    }
645141cc406Sopenharmony_ci    /* deinit shared memory, will be initialized again in open_scanner */
646141cc406Sopenharmony_ci    snapscani_usb_shm_exit();
647141cc406Sopenharmony_ci    if (status == SANE_STATUS_GOOD) {
648141cc406Sopenharmony_ci        status = snapscani_init_device_structure(
649141cc406Sopenharmony_ci            &pd,
650141cc406Sopenharmony_ci            bus_type,
651141cc406Sopenharmony_ci            name,
652141cc406Sopenharmony_ci            vendor,
653141cc406Sopenharmony_ci            model,
654141cc406Sopenharmony_ci            model_num
655141cc406Sopenharmony_ci        );
656141cc406Sopenharmony_ci    }
657141cc406Sopenharmony_ci    free(name);
658141cc406Sopenharmony_ci    name = 0;
659141cc406Sopenharmony_ci    return status;
660141cc406Sopenharmony_ci}
661141cc406Sopenharmony_ci
662141cc406Sopenharmony_ci/* find_device: find a device in the available list by name
663141cc406Sopenharmony_ci
664141cc406Sopenharmony_ci   ARG: the device name
665141cc406Sopenharmony_ci
666141cc406Sopenharmony_ci   RET: a pointer to the corresponding device record, or NULL if there
667141cc406Sopenharmony_ci   is no such device */
668141cc406Sopenharmony_ci
669141cc406Sopenharmony_cistatic SnapScan_Device *find_device (SANE_String_Const name)
670141cc406Sopenharmony_ci{
671141cc406Sopenharmony_ci    static char me[] = "find_device";
672141cc406Sopenharmony_ci    SnapScan_Device *psd;
673141cc406Sopenharmony_ci
674141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
675141cc406Sopenharmony_ci
676141cc406Sopenharmony_ci    for (psd = first_device;  psd;  psd = psd->pnext)
677141cc406Sopenharmony_ci    {
678141cc406Sopenharmony_ci        if (strcmp (psd->dev.name, name) == 0)
679141cc406Sopenharmony_ci            return psd;
680141cc406Sopenharmony_ci    }
681141cc406Sopenharmony_ci    return NULL;
682141cc406Sopenharmony_ci}
683141cc406Sopenharmony_ci
684141cc406Sopenharmony_ci/*----- functions in the scanner interface -----*/
685141cc406Sopenharmony_ci
686141cc406Sopenharmony_ciSANE_Status sane_init (SANE_Int *version_code,
687141cc406Sopenharmony_ci                       SANE_Auth_Callback authorize)
688141cc406Sopenharmony_ci{
689141cc406Sopenharmony_ci    static const char me[] = "sane_snapscan_init";
690141cc406Sopenharmony_ci    char dev_name[PATH_MAX];
691141cc406Sopenharmony_ci    size_t len;
692141cc406Sopenharmony_ci    FILE *fp;
693141cc406Sopenharmony_ci    SANE_Status status;
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci    DBG_INIT ();
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
698141cc406Sopenharmony_ci    DBG (DL_VERBOSE, "%s: Snapscan backend version %d.%d.%d\n",
699141cc406Sopenharmony_ci        me,
700141cc406Sopenharmony_ci        SANE_CURRENT_MAJOR, MINOR_VERSION, BUILD);
701141cc406Sopenharmony_ci
702141cc406Sopenharmony_ci    if (version_code != NULL)
703141cc406Sopenharmony_ci    {
704141cc406Sopenharmony_ci        *version_code =
705141cc406Sopenharmony_ci            SANE_VERSION_CODE (SANE_CURRENT_MAJOR, MINOR_VERSION, BUILD);
706141cc406Sopenharmony_ci    }
707141cc406Sopenharmony_ci
708141cc406Sopenharmony_ci    auth = authorize;
709141cc406Sopenharmony_ci    /* Initialize data structures */
710141cc406Sopenharmony_ci    default_firmware_filename = NULL;
711141cc406Sopenharmony_ci    first_device = NULL;
712141cc406Sopenharmony_ci    n_devices = 0;
713141cc406Sopenharmony_ci
714141cc406Sopenharmony_ci    sanei_usb_init();
715141cc406Sopenharmony_ci    sanei_thread_init();
716141cc406Sopenharmony_ci    /* build a device structure */
717141cc406Sopenharmony_ci    fp = sanei_config_open (SNAPSCAN_CONFIG_FILE);
718141cc406Sopenharmony_ci    if (!fp)
719141cc406Sopenharmony_ci    {
720141cc406Sopenharmony_ci        /* default to DEFAULT_DEVICE instead of insisting on config file */
721141cc406Sopenharmony_ci        DBG (DL_INFO,
722141cc406Sopenharmony_ci             "%s: configuration file not found, defaulting to %s.\n",
723141cc406Sopenharmony_ci             me,
724141cc406Sopenharmony_ci             DEFAULT_DEVICE);
725141cc406Sopenharmony_ci        status = add_scsi_device (DEFAULT_DEVICE);
726141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
727141cc406Sopenharmony_ci        {
728141cc406Sopenharmony_ci            DBG (DL_MINOR_ERROR,
729141cc406Sopenharmony_ci                 "%s: failed to add device \"%s\"\n",
730141cc406Sopenharmony_ci                 me,
731141cc406Sopenharmony_ci                 dev_name);
732141cc406Sopenharmony_ci        }
733141cc406Sopenharmony_ci    }
734141cc406Sopenharmony_ci    else
735141cc406Sopenharmony_ci    {
736141cc406Sopenharmony_ci        while (sanei_config_read (dev_name, sizeof (dev_name), fp))
737141cc406Sopenharmony_ci        {
738141cc406Sopenharmony_ci            len = strlen (dev_name);
739141cc406Sopenharmony_ci            if (!len)
740141cc406Sopenharmony_ci                continue;                /* ignore empty lines */
741141cc406Sopenharmony_ci            if (dev_name[0] == '#')        /* ignore line comments */
742141cc406Sopenharmony_ci                continue;
743141cc406Sopenharmony_ci            if (strncasecmp(dev_name, FIRMWARE_KW, strlen(FIRMWARE_KW)) == 0) {
744141cc406Sopenharmony_ci                if (!default_firmware_filename) {
745141cc406Sopenharmony_ci                    sanei_config_get_string(dev_name + strlen(FIRMWARE_KW), &default_firmware_filename);
746141cc406Sopenharmony_ci                    if (default_firmware_filename == NULL) {
747141cc406Sopenharmony_ci                        DBG (0, "%s: Illegal firmware entry %s.\n", me, dev_name);
748141cc406Sopenharmony_ci                    }
749141cc406Sopenharmony_ci                }
750141cc406Sopenharmony_ci            }
751141cc406Sopenharmony_ci            else if (strncasecmp(dev_name, OPTIONS_KW, strlen(OPTIONS_KW)) == 0)
752141cc406Sopenharmony_ci                continue;                   /* ignore options lines */
753141cc406Sopenharmony_ci
754141cc406Sopenharmony_ci            else if (strncmp(dev_name, "usb", 3) == 0) {
755141cc406Sopenharmony_ci                sanei_usb_attach_matching_devices (dev_name, add_usb_device);
756141cc406Sopenharmony_ci            }
757141cc406Sopenharmony_ci            else if (strncmp(dev_name, "scsi", 4) == 0) {
758141cc406Sopenharmony_ci                sanei_config_attach_matching_devices (dev_name, add_scsi_device);
759141cc406Sopenharmony_ci            }
760141cc406Sopenharmony_ci            else if (strstr (dev_name, "usb")) {
761141cc406Sopenharmony_ci                add_usb_device(dev_name);
762141cc406Sopenharmony_ci            }
763141cc406Sopenharmony_ci            else {
764141cc406Sopenharmony_ci                add_scsi_device(dev_name);
765141cc406Sopenharmony_ci            }
766141cc406Sopenharmony_ci        }
767141cc406Sopenharmony_ci        fclose (fp);
768141cc406Sopenharmony_ci    }
769141cc406Sopenharmony_ci
770141cc406Sopenharmony_ci    /* compute the dither matrices */
771141cc406Sopenharmony_ci
772141cc406Sopenharmony_ci    mkDn (D4, D2, 4);
773141cc406Sopenharmony_ci    mkDn (D8, D4, 8);
774141cc406Sopenharmony_ci    mkDn (D16, D8, 16);
775141cc406Sopenharmony_ci    /* scale the D8 matrix from 0..63 to 0..255 */
776141cc406Sopenharmony_ci    {
777141cc406Sopenharmony_ci        u_char i;
778141cc406Sopenharmony_ci        for (i = 0;  i < 64;  i++)
779141cc406Sopenharmony_ci            D8[i] = (u_char) (4 * D8[i] + 2);
780141cc406Sopenharmony_ci    }
781141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
782141cc406Sopenharmony_ci}
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_cistatic void free_device_list(SnapScan_Device *psd) {
785141cc406Sopenharmony_ci    if (psd->pnext != NULL) {
786141cc406Sopenharmony_ci        free_device_list(psd->pnext);
787141cc406Sopenharmony_ci    }
788141cc406Sopenharmony_ci    free(psd);
789141cc406Sopenharmony_ci}
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_civoid sane_exit (void)
792141cc406Sopenharmony_ci{
793141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "sane_snapscan_exit\n");
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci    if (get_devices_list)
796141cc406Sopenharmony_ci        free (get_devices_list);
797141cc406Sopenharmony_ci    get_devices_list = NULL;
798141cc406Sopenharmony_ci
799141cc406Sopenharmony_ci    /* just for safety, reset things to known values */
800141cc406Sopenharmony_ci    auth = NULL;
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci    if (first_device) {
803141cc406Sopenharmony_ci        free_device_list(first_device);
804141cc406Sopenharmony_ci        first_device = NULL;
805141cc406Sopenharmony_ci    }
806141cc406Sopenharmony_ci    n_devices = 0;
807141cc406Sopenharmony_ci}
808141cc406Sopenharmony_ci
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ciSANE_Status sane_get_devices (const SANE_Device ***device_list,
811141cc406Sopenharmony_ci                              SANE_Bool local_only)
812141cc406Sopenharmony_ci{
813141cc406Sopenharmony_ci    static const char *me = "sane_snapscan_get_devices";
814141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE,
815141cc406Sopenharmony_ci         "%s (%p, %ld)\n",
816141cc406Sopenharmony_ci         me,
817141cc406Sopenharmony_ci         (const void *) device_list,
818141cc406Sopenharmony_ci         (long) local_only);
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_ci    /* Waste the last list returned from this function */
821141cc406Sopenharmony_ci    if (NULL != get_devices_list)
822141cc406Sopenharmony_ci        free (get_devices_list);
823141cc406Sopenharmony_ci
824141cc406Sopenharmony_ci    *device_list =
825141cc406Sopenharmony_ci        (const SANE_Device **) malloc ((n_devices + 1) * sizeof (SANE_Device *));
826141cc406Sopenharmony_ci
827141cc406Sopenharmony_ci    if (*device_list)
828141cc406Sopenharmony_ci    {
829141cc406Sopenharmony_ci        int i;
830141cc406Sopenharmony_ci        SnapScan_Device *pdev;
831141cc406Sopenharmony_ci        for (i = 0, pdev = first_device;  pdev;  i++, pdev = pdev->pnext)
832141cc406Sopenharmony_ci            (*device_list)[i] = &(pdev->dev);
833141cc406Sopenharmony_ci        (*device_list)[i] = 0x0000 /*NULL */;
834141cc406Sopenharmony_ci    }
835141cc406Sopenharmony_ci    else
836141cc406Sopenharmony_ci    {
837141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR, "%s: out of memory\n", me);
838141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
839141cc406Sopenharmony_ci    }
840141cc406Sopenharmony_ci
841141cc406Sopenharmony_ci    get_devices_list = *device_list;
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
844141cc406Sopenharmony_ci}
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ciSANE_Status sane_open (SANE_String_Const name, SANE_Handle * h)
847141cc406Sopenharmony_ci{
848141cc406Sopenharmony_ci    static const char *me = "sane_snapscan_open";
849141cc406Sopenharmony_ci    SnapScan_Device *psd;
850141cc406Sopenharmony_ci    SANE_Status status;
851141cc406Sopenharmony_ci
852141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s (%s, %p)\n", me, name, (void *) h);
853141cc406Sopenharmony_ci
854141cc406Sopenharmony_ci    /* possible authorization required */
855141cc406Sopenharmony_ci
856141cc406Sopenharmony_ci    /* no device name: use first device */
857141cc406Sopenharmony_ci    if ((strlen(name) == 0) && (first_device != NULL))
858141cc406Sopenharmony_ci    {
859141cc406Sopenharmony_ci        name = first_device->dev.name;
860141cc406Sopenharmony_ci    }
861141cc406Sopenharmony_ci
862141cc406Sopenharmony_ci    /* device exists? */
863141cc406Sopenharmony_ci    psd = find_device (name);
864141cc406Sopenharmony_ci    if (!psd)
865141cc406Sopenharmony_ci    {
866141cc406Sopenharmony_ci        DBG (DL_MINOR_ERROR,
867141cc406Sopenharmony_ci             "%s: device \"%s\" not in current device list.\n",
868141cc406Sopenharmony_ci             me,
869141cc406Sopenharmony_ci             name);
870141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
871141cc406Sopenharmony_ci    }
872141cc406Sopenharmony_ci
873141cc406Sopenharmony_ci    /* create and initialize the scanner structure */
874141cc406Sopenharmony_ci
875141cc406Sopenharmony_ci    *h = (SnapScan_Scanner *) calloc (sizeof (SnapScan_Scanner), 1);
876141cc406Sopenharmony_ci    if (!*h)
877141cc406Sopenharmony_ci    {
878141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
879141cc406Sopenharmony_ci             "%s: out of memory creating scanner structure.\n",
880141cc406Sopenharmony_ci             me);
881141cc406Sopenharmony_ci        return SANE_STATUS_NO_MEM;
882141cc406Sopenharmony_ci    }
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci    {
885141cc406Sopenharmony_ci        SnapScan_Scanner *pss = *(SnapScan_Scanner **) h;
886141cc406Sopenharmony_ci
887141cc406Sopenharmony_ci        {
888141cc406Sopenharmony_ci            pss->devname = strdup (name);
889141cc406Sopenharmony_ci            if (!pss->devname)
890141cc406Sopenharmony_ci            {
891141cc406Sopenharmony_ci                free (*h);
892141cc406Sopenharmony_ci                DBG (DL_MAJOR_ERROR,
893141cc406Sopenharmony_ci                     "%s: out of memory copying device name.\n",
894141cc406Sopenharmony_ci                     me);
895141cc406Sopenharmony_ci                return SANE_STATUS_NO_MEM;
896141cc406Sopenharmony_ci            }
897141cc406Sopenharmony_ci            pss->pdev = psd;
898141cc406Sopenharmony_ci            pss->opens = 0;
899141cc406Sopenharmony_ci            pss->sense_str = NULL;
900141cc406Sopenharmony_ci            pss->as_str = NULL;
901141cc406Sopenharmony_ci            pss->phys_buf_sz = DEFAULT_SCANNER_BUF_SZ;
902141cc406Sopenharmony_ci            if ((pss->pdev->model == PERFECTION2480) || (pss->pdev->model == PERFECTION3490))
903141cc406Sopenharmony_ci                pss->phys_buf_sz *= 2;
904141cc406Sopenharmony_ci            if (psd->bus == SCSI) {
905141cc406Sopenharmony_ci                pss->phys_buf_sz = sanei_scsi_max_request_size;
906141cc406Sopenharmony_ci            }
907141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE,
908141cc406Sopenharmony_ci                "%s: Allocating %lu bytes as scanner buffer.\n",
909141cc406Sopenharmony_ci                me, (u_long) pss->phys_buf_sz);
910141cc406Sopenharmony_ci            pss->buf = (u_char *) malloc(pss->phys_buf_sz);
911141cc406Sopenharmony_ci            if (!pss->buf) {
912141cc406Sopenharmony_ci                DBG (DL_MAJOR_ERROR,
913141cc406Sopenharmony_ci                "%s: out of memory creating scanner buffer.\n",
914141cc406Sopenharmony_ci                me);
915141cc406Sopenharmony_ci                return SANE_STATUS_NO_MEM;
916141cc406Sopenharmony_ci            }
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci            DBG (DL_VERBOSE,
919141cc406Sopenharmony_ci                 "%s: allocated scanner structure at %p\n",
920141cc406Sopenharmony_ci                 me,
921141cc406Sopenharmony_ci                 (void *) pss);
922141cc406Sopenharmony_ci        }
923141cc406Sopenharmony_ci        status = snapscani_usb_shm_init();
924141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
925141cc406Sopenharmony_ci        {
926141cc406Sopenharmony_ci            return status;
927141cc406Sopenharmony_ci        }
928141cc406Sopenharmony_ci        status = open_scanner (pss);
929141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
930141cc406Sopenharmony_ci        {
931141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
932141cc406Sopenharmony_ci                 "%s: open_scanner failed, status: %s\n",
933141cc406Sopenharmony_ci                 me,
934141cc406Sopenharmony_ci                 sane_strstatus (status));
935141cc406Sopenharmony_ci            free (pss);
936141cc406Sopenharmony_ci            return SANE_STATUS_ACCESS_DENIED;
937141cc406Sopenharmony_ci        }
938141cc406Sopenharmony_ci
939141cc406Sopenharmony_ci        DBG (DL_MINOR_INFO, "%s: waiting for scanner to warm up.\n", me);
940141cc406Sopenharmony_ci        status = wait_scanner_ready (pss);
941141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
942141cc406Sopenharmony_ci        {
943141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
944141cc406Sopenharmony_ci                "%s: error waiting for scanner to warm up: %s\n",
945141cc406Sopenharmony_ci                me,
946141cc406Sopenharmony_ci                sane_strstatus(status));
947141cc406Sopenharmony_ci            free (pss);
948141cc406Sopenharmony_ci            return status;
949141cc406Sopenharmony_ci        }
950141cc406Sopenharmony_ci        DBG (DL_MINOR_INFO, "%s: performing scanner self test.\n", me);
951141cc406Sopenharmony_ci        status = send_diagnostic (pss);
952141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
953141cc406Sopenharmony_ci        {
954141cc406Sopenharmony_ci            DBG (DL_MINOR_INFO, "%s: send_diagnostic reports %s\n",
955141cc406Sopenharmony_ci                 me, sane_strstatus (status));
956141cc406Sopenharmony_ci            free (pss);
957141cc406Sopenharmony_ci            return status;
958141cc406Sopenharmony_ci        }
959141cc406Sopenharmony_ci        DBG (DL_MINOR_INFO, "%s: self test passed.\n", me);
960141cc406Sopenharmony_ci
961141cc406Sopenharmony_ci        /* option initialization depends on getting the hardware configuration
962141cc406Sopenharmony_ci           byte */
963141cc406Sopenharmony_ci        status = inquiry (pss);
964141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
965141cc406Sopenharmony_ci        {
966141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
967141cc406Sopenharmony_ci                    "%s: error in inquiry command: %s\n",
968141cc406Sopenharmony_ci                me,
969141cc406Sopenharmony_ci                        sane_strstatus (status));
970141cc406Sopenharmony_ci            free (pss);
971141cc406Sopenharmony_ci            return status;
972141cc406Sopenharmony_ci        }
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci		if (pss->pdev->bus == USB)
975141cc406Sopenharmony_ci		{
976141cc406Sopenharmony_ci			if (sanei_usb_get_vendor_product(pss->fd, &pss->usb_vendor, &pss->usb_product) != SANE_STATUS_GOOD)
977141cc406Sopenharmony_ci			{
978141cc406Sopenharmony_ci				pss->usb_vendor = 0;
979141cc406Sopenharmony_ci				pss->usb_product = 0;
980141cc406Sopenharmony_ci			}
981141cc406Sopenharmony_ci	        /* Download Firmware for USB scanners */
982141cc406Sopenharmony_ci	        if (pss->hwst & 0x02)
983141cc406Sopenharmony_ci	        {
984141cc406Sopenharmony_ci	            char vendor[8];
985141cc406Sopenharmony_ci	            char model[17];
986141cc406Sopenharmony_ci
987141cc406Sopenharmony_ci	            status = download_firmware(pss);
988141cc406Sopenharmony_ci	            CHECK_STATUS (status, me, "download_firmware");
989141cc406Sopenharmony_ci	            /* send inquiry command again, wait for scanner to initialize */
990141cc406Sopenharmony_ci	            status = wait_scanner_ready(pss);
991141cc406Sopenharmony_ci	            CHECK_STATUS (status, me, "wait_scanner_ready after firmware upload");
992141cc406Sopenharmony_ci	            status =  mini_inquiry (pss->pdev->bus, pss->fd, vendor, model);
993141cc406Sopenharmony_ci	            CHECK_STATUS (status, me, "mini_inquiry after firmware upload");
994141cc406Sopenharmony_ci	            /* The model identifier may change after firmware upload */
995141cc406Sopenharmony_ci	            DBG (DL_INFO,
996141cc406Sopenharmony_ci	                "%s (after firmware upload): Checking if \"%s\" is a supported scanner\n",
997141cc406Sopenharmony_ci	                me,
998141cc406Sopenharmony_ci	                model);
999141cc406Sopenharmony_ci	            /* Check if it is one of our supported models */
1000141cc406Sopenharmony_ci	            pss->pdev->model = snapscani_get_model_id(model, pss->fd, pss->pdev->bus);
1001141cc406Sopenharmony_ci
1002141cc406Sopenharmony_ci	            if (pss->pdev->model == UNKNOWN) {
1003141cc406Sopenharmony_ci	                DBG (DL_MINOR_ERROR,
1004141cc406Sopenharmony_ci	                    "%s (after firmware upload): \"%s\" is not a supported scanner\n",
1005141cc406Sopenharmony_ci	                    me,
1006141cc406Sopenharmony_ci	                    model);
1007141cc406Sopenharmony_ci	            }
1008141cc406Sopenharmony_ci	            /* run "real" inquiry command once again for option initialization */
1009141cc406Sopenharmony_ci	            status = inquiry (pss);
1010141cc406Sopenharmony_ci	            CHECK_STATUS (status, me, "inquiry after firmware upload");
1011141cc406Sopenharmony_ci	        }
1012141cc406Sopenharmony_ci		}
1013141cc406Sopenharmony_ci        close_scanner(pss);
1014141cc406Sopenharmony_ci
1015141cc406Sopenharmony_ci        status = alloc_gamma_tables (pss);
1016141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1017141cc406Sopenharmony_ci        {
1018141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
1019141cc406Sopenharmony_ci                 "%s: error in alloc_gamma_tables: %s\n",
1020141cc406Sopenharmony_ci                 me,
1021141cc406Sopenharmony_ci                 sane_strstatus (status));
1022141cc406Sopenharmony_ci            free (pss);
1023141cc406Sopenharmony_ci            return status;
1024141cc406Sopenharmony_ci        }
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci        init_options (pss);
1027141cc406Sopenharmony_ci        status = init_gamma (pss);
1028141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1029141cc406Sopenharmony_ci        {
1030141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
1031141cc406Sopenharmony_ci                 "%s: error in init_gamma: %s\n",
1032141cc406Sopenharmony_ci                 me,
1033141cc406Sopenharmony_ci                 sane_strstatus (status));
1034141cc406Sopenharmony_ci            free (pss);
1035141cc406Sopenharmony_ci            return status;
1036141cc406Sopenharmony_ci        }
1037141cc406Sopenharmony_ci
1038141cc406Sopenharmony_ci        pss->state = ST_IDLE;
1039141cc406Sopenharmony_ci    }
1040141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1041141cc406Sopenharmony_ci}
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_civoid sane_close (SANE_Handle h)
1044141cc406Sopenharmony_ci{
1045141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1046141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "sane_snapscan_close (%p)\n", (void *) h);
1047141cc406Sopenharmony_ci    switch (pss->state)
1048141cc406Sopenharmony_ci    {
1049141cc406Sopenharmony_ci    case ST_SCAN_INIT:
1050141cc406Sopenharmony_ci    case ST_SCANNING:
1051141cc406Sopenharmony_ci        release_unit (pss);
1052141cc406Sopenharmony_ci        break;
1053141cc406Sopenharmony_ci    default:
1054141cc406Sopenharmony_ci        break;
1055141cc406Sopenharmony_ci    }
1056141cc406Sopenharmony_ci    close_scanner (pss);
1057141cc406Sopenharmony_ci    snapscani_usb_shm_exit();
1058141cc406Sopenharmony_ci    free (pss->gamma_tables);
1059141cc406Sopenharmony_ci    free (pss->buf);
1060141cc406Sopenharmony_ci    free (pss);
1061141cc406Sopenharmony_ci}
1062141cc406Sopenharmony_ci
1063141cc406Sopenharmony_ci
1064141cc406Sopenharmony_ci
1065141cc406Sopenharmony_ciSANE_Status sane_get_parameters (SANE_Handle h,
1066141cc406Sopenharmony_ci                                 SANE_Parameters *p)
1067141cc406Sopenharmony_ci{
1068141cc406Sopenharmony_ci    static const char *me = "sane_snapscan_get_parameters";
1069141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1070141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1071141cc406Sopenharmony_ci    SnapScan_Mode mode = actual_mode(pss);
1072141cc406Sopenharmony_ci
1073141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s (%p, %p)\n", me, (void *) h, (void *) p);
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci    p->last_frame = SANE_TRUE;        /* we always do only one frame */
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci    if ((pss->state == ST_SCAN_INIT) || (pss->state == ST_SCANNING))
1078141cc406Sopenharmony_ci    {
1079141cc406Sopenharmony_ci        /* we are in the middle of a scan, so we can use the data
1080141cc406Sopenharmony_ci           that the scanner has reported */
1081141cc406Sopenharmony_ci        if (pss->psrc != NULL)
1082141cc406Sopenharmony_ci        {
1083141cc406Sopenharmony_ci            DBG(DL_DATA_TRACE, "%s: Using source chain data\n", me);
1084141cc406Sopenharmony_ci            /* use what the source chain says */
1085141cc406Sopenharmony_ci            p->pixels_per_line = pss->psrc->pixelsPerLine(pss->psrc);
1086141cc406Sopenharmony_ci            p->bytes_per_line = pss->psrc->bytesPerLine(pss->psrc);
1087141cc406Sopenharmony_ci            /* p->lines = pss->psrc->remaining(pss->psrc)/p->bytes_per_line; */
1088141cc406Sopenharmony_ci            p->lines = pss->lines;
1089141cc406Sopenharmony_ci        }
1090141cc406Sopenharmony_ci        else
1091141cc406Sopenharmony_ci        {
1092141cc406Sopenharmony_ci            DBG(DL_DATA_TRACE, "%s: Using current data\n", me);
1093141cc406Sopenharmony_ci            /* estimate based on current data */
1094141cc406Sopenharmony_ci            p->pixels_per_line = pss->pixels_per_line;
1095141cc406Sopenharmony_ci            p->bytes_per_line = pss->bytes_per_line;
1096141cc406Sopenharmony_ci            p->lines = pss->lines;
1097141cc406Sopenharmony_ci            if (mode == MD_BILEVELCOLOUR)
1098141cc406Sopenharmony_ci                p->bytes_per_line = p->pixels_per_line*3;
1099141cc406Sopenharmony_ci        }
1100141cc406Sopenharmony_ci    }
1101141cc406Sopenharmony_ci    else
1102141cc406Sopenharmony_ci    {
1103141cc406Sopenharmony_ci        /* no scan in progress. The scanner data may not be up to date.
1104141cc406Sopenharmony_ci           we have to calculate an estimate. */
1105141cc406Sopenharmony_ci        double width, height;
1106141cc406Sopenharmony_ci        int dpi;
1107141cc406Sopenharmony_ci        double dots_per_mm;
1108141cc406Sopenharmony_ci
1109141cc406Sopenharmony_ci        DBG(DL_DATA_TRACE, "%s: Using estimated data\n", me);
1110141cc406Sopenharmony_ci        width = SANE_UNFIX (pss->brx - pss->tlx);
1111141cc406Sopenharmony_ci        height = SANE_UNFIX (pss->bry - pss->tly);
1112141cc406Sopenharmony_ci        dpi = pss->res;
1113141cc406Sopenharmony_ci        dots_per_mm = dpi / MM_PER_IN;
1114141cc406Sopenharmony_ci        p->pixels_per_line = width * dots_per_mm;
1115141cc406Sopenharmony_ci        p->lines = height * dots_per_mm;
1116141cc406Sopenharmony_ci        switch (mode)
1117141cc406Sopenharmony_ci        {
1118141cc406Sopenharmony_ci        case MD_COLOUR:
1119141cc406Sopenharmony_ci        case MD_BILEVELCOLOUR:
1120141cc406Sopenharmony_ci            p->bytes_per_line = 3 * p->pixels_per_line * ((pss->bpp_scan+7)/8);
1121141cc406Sopenharmony_ci            break;
1122141cc406Sopenharmony_ci        case MD_LINEART:
1123141cc406Sopenharmony_ci            p->bytes_per_line = (p->pixels_per_line + 7) / 8;
1124141cc406Sopenharmony_ci            break;
1125141cc406Sopenharmony_ci        default:
1126141cc406Sopenharmony_ci            /* greyscale */
1127141cc406Sopenharmony_ci            p->bytes_per_line = p->pixels_per_line * ((pss->bpp_scan+7)/8);
1128141cc406Sopenharmony_ci            break;
1129141cc406Sopenharmony_ci        }
1130141cc406Sopenharmony_ci    }
1131141cc406Sopenharmony_ci    p->format = (is_colour_mode(mode)) ? SANE_FRAME_RGB : SANE_FRAME_GRAY;
1132141cc406Sopenharmony_ci    if (mode == MD_LINEART)
1133141cc406Sopenharmony_ci        p->depth = 1;
1134141cc406Sopenharmony_ci    else if (pss->pdev->model == SCANWIT2720S)
1135141cc406Sopenharmony_ci        p->depth = 16;
1136141cc406Sopenharmony_ci    else if (pss->preview)
1137141cc406Sopenharmony_ci        p->depth = 8;
1138141cc406Sopenharmony_ci    else
1139141cc406Sopenharmony_ci        p->depth = pss->val[OPT_BIT_DEPTH].w;
1140141cc406Sopenharmony_ci
1141141cc406Sopenharmony_ci    DBG (DL_DATA_TRACE, "%s: depth = %ld\n", me, (long) p->depth);
1142141cc406Sopenharmony_ci    DBG (DL_DATA_TRACE, "%s: lines = %ld\n", me, (long) p->lines);
1143141cc406Sopenharmony_ci    DBG (DL_DATA_TRACE,
1144141cc406Sopenharmony_ci         "%s: pixels per line = %ld\n",
1145141cc406Sopenharmony_ci         me,
1146141cc406Sopenharmony_ci         (long) p->pixels_per_line);
1147141cc406Sopenharmony_ci    DBG (DL_DATA_TRACE,
1148141cc406Sopenharmony_ci         "%s: bytes per line = %ld\n",
1149141cc406Sopenharmony_ci         me,
1150141cc406Sopenharmony_ci         (long) p->bytes_per_line);
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci    return status;
1153141cc406Sopenharmony_ci}
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci/* scan data reader routine for child process */
1156141cc406Sopenharmony_ci
1157141cc406Sopenharmony_ci#define READER_WRITE_SIZE 4096
1158141cc406Sopenharmony_ci
1159141cc406Sopenharmony_cistatic void reader (SnapScan_Scanner *pss)
1160141cc406Sopenharmony_ci{
1161141cc406Sopenharmony_ci    static char me[] = "Child reader process";
1162141cc406Sopenharmony_ci    SANE_Status status;
1163141cc406Sopenharmony_ci    SANE_Byte *wbuf = NULL;
1164141cc406Sopenharmony_ci
1165141cc406Sopenharmony_ci
1166141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci    wbuf = (SANE_Byte*) malloc(READER_WRITE_SIZE);
1169141cc406Sopenharmony_ci    if (wbuf == NULL)
1170141cc406Sopenharmony_ci    {
1171141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR, "%s: failed to allocate write buffer.\n", me);
1172141cc406Sopenharmony_ci        return;
1173141cc406Sopenharmony_ci    }
1174141cc406Sopenharmony_ci
1175141cc406Sopenharmony_ci    while ((pss->preadersrc->remaining(pss->preadersrc) > 0) && !cancelRead)
1176141cc406Sopenharmony_ci    {
1177141cc406Sopenharmony_ci        SANE_Int ndata = READER_WRITE_SIZE;
1178141cc406Sopenharmony_ci        status = pss->preadersrc->get(pss->preadersrc, wbuf, &ndata);
1179141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1180141cc406Sopenharmony_ci        {
1181141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
1182141cc406Sopenharmony_ci                 "%s: %s on read.\n",
1183141cc406Sopenharmony_ci                 me,
1184141cc406Sopenharmony_ci                 sane_strstatus (status));
1185141cc406Sopenharmony_ci            return;
1186141cc406Sopenharmony_ci        }
1187141cc406Sopenharmony_ci        {
1188141cc406Sopenharmony_ci            SANE_Byte *buf = wbuf;
1189141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE, "READ %d BYTES (%d)\n", ndata, cancelRead);
1190141cc406Sopenharmony_ci            while (ndata > 0)
1191141cc406Sopenharmony_ci            {
1192141cc406Sopenharmony_ci                int written = write (pss->rpipe[1], buf, ndata);
1193141cc406Sopenharmony_ci                DBG (DL_DATA_TRACE, "WROTE %d BYTES\n", written);
1194141cc406Sopenharmony_ci                if (written == -1)
1195141cc406Sopenharmony_ci                {
1196141cc406Sopenharmony_ci                    DBG (DL_MAJOR_ERROR,
1197141cc406Sopenharmony_ci                         "%s: error writing scan data on parent pipe.\n",
1198141cc406Sopenharmony_ci                         me);
1199141cc406Sopenharmony_ci                    perror ("pipe error: ");
1200141cc406Sopenharmony_ci                }
1201141cc406Sopenharmony_ci                else
1202141cc406Sopenharmony_ci                {
1203141cc406Sopenharmony_ci                    ndata -= written;
1204141cc406Sopenharmony_ci                    buf += written;
1205141cc406Sopenharmony_ci                }
1206141cc406Sopenharmony_ci            }
1207141cc406Sopenharmony_ci        }
1208141cc406Sopenharmony_ci    }
1209141cc406Sopenharmony_ci}
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci/** signal handler to kill the child process
1212141cc406Sopenharmony_ci */
1213141cc406Sopenharmony_cistatic void usb_reader_process_sigterm_handler( int signo )
1214141cc406Sopenharmony_ci{
1215141cc406Sopenharmony_ci    DBG( DL_INFO, "(SIG) reader_process: terminated by signal %d\n", signo );
1216141cc406Sopenharmony_ci    cancelRead = SANE_TRUE;
1217141cc406Sopenharmony_ci}
1218141cc406Sopenharmony_ci
1219141cc406Sopenharmony_cistatic void sigalarm_handler( int signo __sane_unused__)
1220141cc406Sopenharmony_ci{
1221141cc406Sopenharmony_ci    DBG( DL_INFO, "ALARM!!!\n" );
1222141cc406Sopenharmony_ci}
1223141cc406Sopenharmony_ci
1224141cc406Sopenharmony_ci/** executed as a child process
1225141cc406Sopenharmony_ci * read the data from the driver and send them to the parent process
1226141cc406Sopenharmony_ci */
1227141cc406Sopenharmony_cistatic int reader_process( void *args )
1228141cc406Sopenharmony_ci{
1229141cc406Sopenharmony_ci    SANE_Status      status;
1230141cc406Sopenharmony_ci    struct SIGACTION act;
1231141cc406Sopenharmony_ci    sigset_t         ignore_set;
1232141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) args;
1233141cc406Sopenharmony_ci
1234141cc406Sopenharmony_ci    if( sanei_thread_is_forked()) {
1235141cc406Sopenharmony_ci        DBG( DL_MINOR_INFO, "reader_process started (forked)\n" );
1236141cc406Sopenharmony_ci        /* child process - close read side, make stdout the write side of the pipe */
1237141cc406Sopenharmony_ci        close( pss->rpipe[0] );
1238141cc406Sopenharmony_ci        pss->rpipe[0] = -1;
1239141cc406Sopenharmony_ci    } else {
1240141cc406Sopenharmony_ci        DBG( DL_MINOR_INFO, "reader_process started (as thread)\n" );
1241141cc406Sopenharmony_ci    }
1242141cc406Sopenharmony_ci
1243141cc406Sopenharmony_ci    sigfillset ( &ignore_set );
1244141cc406Sopenharmony_ci    sigdelset  ( &ignore_set, SIGUSR1 );
1245141cc406Sopenharmony_ci    sigprocmask( SIG_SETMASK, &ignore_set, 0 );
1246141cc406Sopenharmony_ci
1247141cc406Sopenharmony_ci    memset   ( &act, 0, sizeof (act));
1248141cc406Sopenharmony_ci    sigaction( SIGTERM, &act, 0 );
1249141cc406Sopenharmony_ci
1250141cc406Sopenharmony_ci    cancelRead = SANE_FALSE;
1251141cc406Sopenharmony_ci
1252141cc406Sopenharmony_ci    /* install the signal handler */
1253141cc406Sopenharmony_ci    sigemptyset(&(act.sa_mask));
1254141cc406Sopenharmony_ci    act.sa_flags = 0;
1255141cc406Sopenharmony_ci
1256141cc406Sopenharmony_ci    act.sa_handler = usb_reader_process_sigterm_handler;
1257141cc406Sopenharmony_ci    sigaction( SIGUSR1, &act, 0 );
1258141cc406Sopenharmony_ci
1259141cc406Sopenharmony_ci    status = create_base_source (pss, SCSI_SRC, &(pss->preadersrc));
1260141cc406Sopenharmony_ci    if (status == SANE_STATUS_GOOD)
1261141cc406Sopenharmony_ci    {
1262141cc406Sopenharmony_ci        reader (pss);
1263141cc406Sopenharmony_ci    }
1264141cc406Sopenharmony_ci    else
1265141cc406Sopenharmony_ci    {
1266141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
1267141cc406Sopenharmony_ci                "Reader process: failed to create SCSISource.\n");
1268141cc406Sopenharmony_ci    }
1269141cc406Sopenharmony_ci    pss->preadersrc->done(pss->preadersrc);
1270141cc406Sopenharmony_ci    free(pss->preadersrc);
1271141cc406Sopenharmony_ci    pss->preadersrc = 0;
1272141cc406Sopenharmony_ci    close( pss->rpipe[1] );
1273141cc406Sopenharmony_ci    pss->rpipe[1] = -1;
1274141cc406Sopenharmony_ci    DBG( DL_MINOR_INFO, "reader_process: finished reading data\n" );
1275141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1276141cc406Sopenharmony_ci}
1277141cc406Sopenharmony_ci
1278141cc406Sopenharmony_ci
1279141cc406Sopenharmony_cistatic SANE_Status start_reader (SnapScan_Scanner *pss)
1280141cc406Sopenharmony_ci{
1281141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1282141cc406Sopenharmony_ci    static char me[] = "start_reader";
1283141cc406Sopenharmony_ci
1284141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1285141cc406Sopenharmony_ci
1286141cc406Sopenharmony_ci    pss->nonblocking = SANE_FALSE;
1287141cc406Sopenharmony_ci    pss->rpipe[0] = pss->rpipe[1] = -1;
1288141cc406Sopenharmony_ci    sanei_thread_initialize (pss->child);
1289141cc406Sopenharmony_ci
1290141cc406Sopenharmony_ci    if (pipe (pss->rpipe) != -1)
1291141cc406Sopenharmony_ci    {
1292141cc406Sopenharmony_ci        pss->orig_rpipe_flags = fcntl (pss->rpipe[0], F_GETFL, 0);
1293141cc406Sopenharmony_ci        pss->child =  sanei_thread_begin(reader_process, (void *) pss);
1294141cc406Sopenharmony_ci
1295141cc406Sopenharmony_ci        cancelRead = SANE_FALSE;
1296141cc406Sopenharmony_ci
1297141cc406Sopenharmony_ci        if (!sanei_thread_is_valid (pss->child))
1298141cc406Sopenharmony_ci        {
1299141cc406Sopenharmony_ci            /* we'll have to read in blocking mode */
1300141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR,
1301141cc406Sopenharmony_ci                 "%s: Error while calling sanei_thread_begin; must read in blocking mode.\n",
1302141cc406Sopenharmony_ci                 me);
1303141cc406Sopenharmony_ci            close (pss->rpipe[0]);
1304141cc406Sopenharmony_ci            close (pss->rpipe[1]);
1305141cc406Sopenharmony_ci            status = SANE_STATUS_UNSUPPORTED;
1306141cc406Sopenharmony_ci        }
1307141cc406Sopenharmony_ci        if (sanei_thread_is_forked())
1308141cc406Sopenharmony_ci        {
1309141cc406Sopenharmony_ci            /* parent; close write side */
1310141cc406Sopenharmony_ci            close (pss->rpipe[1]);
1311141cc406Sopenharmony_ci            pss->rpipe[1] = -1;
1312141cc406Sopenharmony_ci        }
1313141cc406Sopenharmony_ci        pss->nonblocking = SANE_TRUE;
1314141cc406Sopenharmony_ci    }
1315141cc406Sopenharmony_ci    return status;
1316141cc406Sopenharmony_ci}
1317141cc406Sopenharmony_ci
1318141cc406Sopenharmony_cistatic SANE_Status send_gamma_table (SnapScan_Scanner *pss, u_char dtc, u_char dtcq)
1319141cc406Sopenharmony_ci{
1320141cc406Sopenharmony_ci    static char me[] = "send_gamma_table";
1321141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1322141cc406Sopenharmony_ci    status = send (pss, dtc, dtcq);
1323141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "send");
1324141cc406Sopenharmony_ci    switch (pss->pdev->model)
1325141cc406Sopenharmony_ci    {
1326141cc406Sopenharmony_ci        case PERFECTION1270:
1327141cc406Sopenharmony_ci        case PERFECTION1670:
1328141cc406Sopenharmony_ci        case PERFECTION2480:
1329141cc406Sopenharmony_ci        case PERFECTION3490:
1330141cc406Sopenharmony_ci            /* Some epson scanners need the gamma table twice */
1331141cc406Sopenharmony_ci            status = send (pss, dtc, dtcq);
1332141cc406Sopenharmony_ci            CHECK_STATUS (status, me, "2nd send");
1333141cc406Sopenharmony_ci            break;
1334141cc406Sopenharmony_ci        case PRISA5150:
1335141cc406Sopenharmony_ci            /* 5150 needs the gamma table twice, with dtc = 0x04 for the second one */
1336141cc406Sopenharmony_ci            status = send (pss, DTC_GAMMA2, dtcq);
1337141cc406Sopenharmony_ci            CHECK_STATUS (status, me, "2nd send");
1338141cc406Sopenharmony_ci            break;
1339141cc406Sopenharmony_ci        default:
1340141cc406Sopenharmony_ci            break;
1341141cc406Sopenharmony_ci    }
1342141cc406Sopenharmony_ci    return status;
1343141cc406Sopenharmony_ci}
1344141cc406Sopenharmony_ci
1345141cc406Sopenharmony_cistatic SANE_Status download_gamma_tables (SnapScan_Scanner *pss)
1346141cc406Sopenharmony_ci{
1347141cc406Sopenharmony_ci    static char me[] = "download_gamma_tables";
1348141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1349141cc406Sopenharmony_ci    double gamma_gs = SANE_UNFIX (pss->gamma_gs);
1350141cc406Sopenharmony_ci    double gamma_r = SANE_UNFIX (pss->gamma_r);
1351141cc406Sopenharmony_ci    double gamma_g = SANE_UNFIX (pss->gamma_g);
1352141cc406Sopenharmony_ci    double gamma_b = SANE_UNFIX (pss->gamma_b);
1353141cc406Sopenharmony_ci    SnapScan_Mode mode = actual_mode (pss);
1354141cc406Sopenharmony_ci    int dtcq_gamma_gray;
1355141cc406Sopenharmony_ci    int dtcq_gamma_red;
1356141cc406Sopenharmony_ci    int dtcq_gamma_green;
1357141cc406Sopenharmony_ci    int dtcq_gamma_blue;
1358141cc406Sopenharmony_ci    int gamma_mode = GAMMA_8BIT;
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1361141cc406Sopenharmony_ci    switch (mode)
1362141cc406Sopenharmony_ci    {
1363141cc406Sopenharmony_ci    case MD_COLOUR:
1364141cc406Sopenharmony_ci        break;
1365141cc406Sopenharmony_ci    case MD_BILEVELCOLOUR:
1366141cc406Sopenharmony_ci        if (!pss->halftone)
1367141cc406Sopenharmony_ci        {
1368141cc406Sopenharmony_ci            gamma_r =
1369141cc406Sopenharmony_ci            gamma_g =
1370141cc406Sopenharmony_ci            gamma_b = 1.0;
1371141cc406Sopenharmony_ci        }
1372141cc406Sopenharmony_ci        break;
1373141cc406Sopenharmony_ci    case MD_LINEART:
1374141cc406Sopenharmony_ci        if (!pss->halftone)
1375141cc406Sopenharmony_ci            gamma_gs = 1.0;
1376141cc406Sopenharmony_ci        break;
1377141cc406Sopenharmony_ci    default:
1378141cc406Sopenharmony_ci        /* no further action for greyscale */
1379141cc406Sopenharmony_ci        break;
1380141cc406Sopenharmony_ci    }
1381141cc406Sopenharmony_ci
1382141cc406Sopenharmony_ci    switch (pss->bpp)
1383141cc406Sopenharmony_ci    {
1384141cc406Sopenharmony_ci    case 10:
1385141cc406Sopenharmony_ci        DBG (DL_DATA_TRACE, "%s: Sending 8bit gamma table for %d bpp\n", me, pss->bpp);
1386141cc406Sopenharmony_ci        dtcq_gamma_gray = DTCQ_GAMMA_GRAY10;
1387141cc406Sopenharmony_ci        dtcq_gamma_red = DTCQ_GAMMA_RED10;
1388141cc406Sopenharmony_ci        dtcq_gamma_green = DTCQ_GAMMA_GREEN10;
1389141cc406Sopenharmony_ci        dtcq_gamma_blue = DTCQ_GAMMA_BLUE10;
1390141cc406Sopenharmony_ci        break;
1391141cc406Sopenharmony_ci    case 12:
1392141cc406Sopenharmony_ci        if (pss->pdev->model == SCANWIT2720S)
1393141cc406Sopenharmony_ci        {
1394141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE, "%s: Sending 16bit gamma table for %d bpp\n", me, pss->bpp);
1395141cc406Sopenharmony_ci            dtcq_gamma_gray = DTCQ_GAMMA_GRAY12_16BIT;
1396141cc406Sopenharmony_ci            dtcq_gamma_red = DTCQ_GAMMA_RED12_16BIT;
1397141cc406Sopenharmony_ci            dtcq_gamma_green = DTCQ_GAMMA_GREEN12_16BIT;
1398141cc406Sopenharmony_ci            dtcq_gamma_blue = DTCQ_GAMMA_BLUE12_16BIT;
1399141cc406Sopenharmony_ci            gamma_mode = GAMMA_12_16BIT;
1400141cc406Sopenharmony_ci        }
1401141cc406Sopenharmony_ci        else
1402141cc406Sopenharmony_ci        {
1403141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE, "%s: Sending 8bit gamma table for %d bpp\n", me, pss->bpp);
1404141cc406Sopenharmony_ci            dtcq_gamma_gray = DTCQ_GAMMA_GRAY12;
1405141cc406Sopenharmony_ci            dtcq_gamma_red = DTCQ_GAMMA_RED12;
1406141cc406Sopenharmony_ci            dtcq_gamma_green = DTCQ_GAMMA_GREEN12;
1407141cc406Sopenharmony_ci            dtcq_gamma_blue = DTCQ_GAMMA_BLUE12;
1408141cc406Sopenharmony_ci        }
1409141cc406Sopenharmony_ci        break;
1410141cc406Sopenharmony_ci    case 14:
1411141cc406Sopenharmony_ci        if (pss->bpp_scan == 16)
1412141cc406Sopenharmony_ci        {
1413141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE, "%s: Sending 16bit gamma table for %d bpp\n", me, pss->bpp);
1414141cc406Sopenharmony_ci            dtcq_gamma_gray = DTCQ_GAMMA_GRAY14_16BIT;
1415141cc406Sopenharmony_ci            dtcq_gamma_red = DTCQ_GAMMA_RED14_16BIT;
1416141cc406Sopenharmony_ci            dtcq_gamma_green = DTCQ_GAMMA_GREEN14_16BIT;
1417141cc406Sopenharmony_ci            dtcq_gamma_blue = DTCQ_GAMMA_BLUE14_16BIT;
1418141cc406Sopenharmony_ci            gamma_mode = GAMMA_16BIT;
1419141cc406Sopenharmony_ci        }
1420141cc406Sopenharmony_ci        else
1421141cc406Sopenharmony_ci        {
1422141cc406Sopenharmony_ci            DBG (DL_DATA_TRACE, "%s: Sending 8bit gamma table for %d bpp\n", me, pss->bpp);
1423141cc406Sopenharmony_ci            dtcq_gamma_gray = DTCQ_GAMMA_GRAY14;
1424141cc406Sopenharmony_ci            dtcq_gamma_red = DTCQ_GAMMA_RED14;
1425141cc406Sopenharmony_ci            dtcq_gamma_green = DTCQ_GAMMA_GREEN14;
1426141cc406Sopenharmony_ci            dtcq_gamma_blue = DTCQ_GAMMA_BLUE14;
1427141cc406Sopenharmony_ci        }
1428141cc406Sopenharmony_ci        break;
1429141cc406Sopenharmony_ci    default:
1430141cc406Sopenharmony_ci        DBG (DL_DATA_TRACE, "%s: Sending 8bit gamma table for %d bpp\n", me, pss->bpp);
1431141cc406Sopenharmony_ci        dtcq_gamma_gray = DTCQ_GAMMA_GRAY8;
1432141cc406Sopenharmony_ci        dtcq_gamma_red = DTCQ_GAMMA_RED8;
1433141cc406Sopenharmony_ci        dtcq_gamma_green = DTCQ_GAMMA_GREEN8;
1434141cc406Sopenharmony_ci        dtcq_gamma_blue = DTCQ_GAMMA_BLUE8;
1435141cc406Sopenharmony_ci        break;
1436141cc406Sopenharmony_ci    }
1437141cc406Sopenharmony_ci
1438141cc406Sopenharmony_ci    if (is_colour_mode(mode))
1439141cc406Sopenharmony_ci    {
1440141cc406Sopenharmony_ci        if (pss->val[OPT_CUSTOM_GAMMA].b)
1441141cc406Sopenharmony_ci        {
1442141cc406Sopenharmony_ci            if (pss->val[OPT_GAMMA_BIND].b)
1443141cc406Sopenharmony_ci            {
1444141cc406Sopenharmony_ci                /* Use greyscale gamma for all rgb channels */
1445141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_gs,
1446141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1447141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_red);
1448141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_gs,
1451141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1452141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_green);
1453141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1454141cc406Sopenharmony_ci
1455141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_gs,
1456141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1457141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_blue);
1458141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1459141cc406Sopenharmony_ci            }
1460141cc406Sopenharmony_ci            else
1461141cc406Sopenharmony_ci            {
1462141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_r,
1463141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1464141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_red);
1465141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1466141cc406Sopenharmony_ci
1467141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_g,
1468141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1469141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_green);
1470141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci                gamma_from_sane (pss->gamma_length, pss->gamma_table_b,
1473141cc406Sopenharmony_ci                                 pss->buf + SEND_LENGTH, gamma_mode);
1474141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_blue);
1475141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1476141cc406Sopenharmony_ci            }
1477141cc406Sopenharmony_ci        }
1478141cc406Sopenharmony_ci        else
1479141cc406Sopenharmony_ci        {
1480141cc406Sopenharmony_ci            if (pss->val[OPT_GAMMA_BIND].b)
1481141cc406Sopenharmony_ci            {
1482141cc406Sopenharmony_ci                /* Use greyscale gamma for all rgb channels */
1483141cc406Sopenharmony_ci                gamma_n (gamma_gs, pss->bright, pss->contrast,
1484141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1485141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_red);
1486141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci                gamma_n (gamma_gs, pss->bright, pss->contrast,
1489141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1490141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_green);
1491141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1492141cc406Sopenharmony_ci
1493141cc406Sopenharmony_ci                gamma_n (gamma_gs, pss->bright, pss->contrast,
1494141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1495141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_blue);
1496141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1497141cc406Sopenharmony_ci            }
1498141cc406Sopenharmony_ci            else
1499141cc406Sopenharmony_ci            {
1500141cc406Sopenharmony_ci                gamma_n (gamma_r, pss->bright, pss->contrast,
1501141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1502141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_red);
1503141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1504141cc406Sopenharmony_ci
1505141cc406Sopenharmony_ci                gamma_n (gamma_g, pss->bright, pss->contrast,
1506141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1507141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_green);
1508141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1509141cc406Sopenharmony_ci
1510141cc406Sopenharmony_ci                gamma_n (gamma_b, pss->bright, pss->contrast,
1511141cc406Sopenharmony_ci                         pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1512141cc406Sopenharmony_ci                status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_blue);
1513141cc406Sopenharmony_ci                CHECK_STATUS (status, me, "send");
1514141cc406Sopenharmony_ci            }
1515141cc406Sopenharmony_ci        }
1516141cc406Sopenharmony_ci    }
1517141cc406Sopenharmony_ci    else
1518141cc406Sopenharmony_ci    {
1519141cc406Sopenharmony_ci        if(pss->val[OPT_CUSTOM_GAMMA].b)
1520141cc406Sopenharmony_ci        {
1521141cc406Sopenharmony_ci            gamma_from_sane (pss->gamma_length, pss->gamma_table_gs,
1522141cc406Sopenharmony_ci                             pss->buf + SEND_LENGTH, gamma_mode);
1523141cc406Sopenharmony_ci            status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_gray);
1524141cc406Sopenharmony_ci            CHECK_STATUS (status, me, "send");
1525141cc406Sopenharmony_ci        }
1526141cc406Sopenharmony_ci        else
1527141cc406Sopenharmony_ci        {
1528141cc406Sopenharmony_ci            gamma_n (gamma_gs, pss->bright, pss->contrast,
1529141cc406Sopenharmony_ci                     pss->buf + SEND_LENGTH, pss->bpp, gamma_mode);
1530141cc406Sopenharmony_ci            status = send_gamma_table(pss, DTC_GAMMA, dtcq_gamma_gray);
1531141cc406Sopenharmony_ci            CHECK_STATUS (status, me, "send");
1532141cc406Sopenharmony_ci        }
1533141cc406Sopenharmony_ci    }
1534141cc406Sopenharmony_ci    return status;
1535141cc406Sopenharmony_ci}
1536141cc406Sopenharmony_ci
1537141cc406Sopenharmony_cistatic SANE_Status download_halftone_matrices (SnapScan_Scanner *pss)
1538141cc406Sopenharmony_ci{
1539141cc406Sopenharmony_ci    static char me[] = "download_halftone_matrices";
1540141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1541141cc406Sopenharmony_ci    if ((pss->halftone) &&
1542141cc406Sopenharmony_ci        ((actual_mode(pss) == MD_LINEART) || (actual_mode(pss) == MD_BILEVELCOLOUR)))
1543141cc406Sopenharmony_ci    {
1544141cc406Sopenharmony_ci        u_char *matrix;
1545141cc406Sopenharmony_ci        size_t matrix_sz;
1546141cc406Sopenharmony_ci        u_char dtcq;
1547141cc406Sopenharmony_ci
1548141cc406Sopenharmony_ci        if (pss->dither_matrix == dm_dd8x8)
1549141cc406Sopenharmony_ci        {
1550141cc406Sopenharmony_ci            matrix = D8;
1551141cc406Sopenharmony_ci            matrix_sz = sizeof (D8);
1552141cc406Sopenharmony_ci        }
1553141cc406Sopenharmony_ci        else
1554141cc406Sopenharmony_ci        {
1555141cc406Sopenharmony_ci            matrix = D16;
1556141cc406Sopenharmony_ci            matrix_sz = sizeof (D16);
1557141cc406Sopenharmony_ci        }
1558141cc406Sopenharmony_ci
1559141cc406Sopenharmony_ci        memcpy (pss->buf + SEND_LENGTH, matrix, matrix_sz);
1560141cc406Sopenharmony_ci
1561141cc406Sopenharmony_ci        if (is_colour_mode(actual_mode(pss)))
1562141cc406Sopenharmony_ci        {
1563141cc406Sopenharmony_ci            if (matrix_sz == sizeof (D8))
1564141cc406Sopenharmony_ci                dtcq = DTCQ_HALFTONE_COLOR8;
1565141cc406Sopenharmony_ci            else
1566141cc406Sopenharmony_ci                dtcq = DTCQ_HALFTONE_COLOR16;
1567141cc406Sopenharmony_ci
1568141cc406Sopenharmony_ci            /* need copies for green and blue bands */
1569141cc406Sopenharmony_ci            memcpy (pss->buf + SEND_LENGTH + matrix_sz,
1570141cc406Sopenharmony_ci                    matrix,
1571141cc406Sopenharmony_ci                    matrix_sz);
1572141cc406Sopenharmony_ci            memcpy (pss->buf + SEND_LENGTH + 2 * matrix_sz,
1573141cc406Sopenharmony_ci                    matrix,
1574141cc406Sopenharmony_ci                    matrix_sz);
1575141cc406Sopenharmony_ci        }
1576141cc406Sopenharmony_ci        else
1577141cc406Sopenharmony_ci        {
1578141cc406Sopenharmony_ci            if (matrix_sz == sizeof (D8))
1579141cc406Sopenharmony_ci                dtcq = DTCQ_HALFTONE_BW8;
1580141cc406Sopenharmony_ci            else
1581141cc406Sopenharmony_ci                dtcq = DTCQ_HALFTONE_BW16;
1582141cc406Sopenharmony_ci        }
1583141cc406Sopenharmony_ci
1584141cc406Sopenharmony_ci        status = send (pss, DTC_HALFTONE, dtcq);
1585141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "send");
1586141cc406Sopenharmony_ci    }
1587141cc406Sopenharmony_ci    return status;
1588141cc406Sopenharmony_ci}
1589141cc406Sopenharmony_ci
1590141cc406Sopenharmony_cistatic SANE_Status measure_transfer_rate (SnapScan_Scanner *pss)
1591141cc406Sopenharmony_ci{
1592141cc406Sopenharmony_ci    static char me[] = "measure_transfer_rate";
1593141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1594141cc406Sopenharmony_ci
1595141cc406Sopenharmony_ci    if (pss->hconfig & HCFG_RB)
1596141cc406Sopenharmony_ci    {
1597141cc406Sopenharmony_ci        /* We have a ring buffer. We simulate one round of a read-store
1598141cc406Sopenharmony_ci           cycle on the size of buffer we will be using. For this read only,
1599141cc406Sopenharmony_ci           the buffer size must be rounded to a 128-byte boundary. */
1600141cc406Sopenharmony_ci
1601141cc406Sopenharmony_ci        DBG (DL_VERBOSE, "%s: have ring buffer\n", me);
1602141cc406Sopenharmony_ci	if ((pss->pdev->model == PERFECTION2480) || (pss->pdev->model == PERFECTION3490))
1603141cc406Sopenharmony_ci	{
1604141cc406Sopenharmony_ci	    /* Epson 2480: read a multiple of bytes per line, limit to less than 0xfff0 */
1605141cc406Sopenharmony_ci	    if (pss->bytes_per_line > 0xfff0)
1606141cc406Sopenharmony_ci        	pss->expected_read_bytes = 0xfff0;
1607141cc406Sopenharmony_ci	    else
1608141cc406Sopenharmony_ci                pss->expected_read_bytes = (0xfff0 / pss->bytes_per_line) * pss->bytes_per_line;
1609141cc406Sopenharmony_ci	}
1610141cc406Sopenharmony_ci	else
1611141cc406Sopenharmony_ci            pss->expected_read_bytes =
1612141cc406Sopenharmony_ci                (pss->buf_sz%128)  ?  (pss->buf_sz/128 + 1)*128  :  pss->buf_sz;
1613141cc406Sopenharmony_ci
1614141cc406Sopenharmony_ci        status = scsi_read (pss, READ_TRANSTIME);
1615141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "scsi_read");
1616141cc406Sopenharmony_ci        pss->expected_read_bytes = 0;
1617141cc406Sopenharmony_ci        status = scsi_read (pss, READ_TRANSTIME);
1618141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "scsi_read");
1619141cc406Sopenharmony_ci    }
1620141cc406Sopenharmony_ci    else
1621141cc406Sopenharmony_ci    {
1622141cc406Sopenharmony_ci        /* we don't have a ring buffer. The test requires transferring one
1623141cc406Sopenharmony_ci           scan line of data (rounded up to next 128 byte boundary). */
1624141cc406Sopenharmony_ci
1625141cc406Sopenharmony_ci        DBG (DL_VERBOSE, "%s: we don't have a ring buffer.\n", me);
1626141cc406Sopenharmony_ci        pss->expected_read_bytes = pss->bytes_per_line;
1627141cc406Sopenharmony_ci
1628141cc406Sopenharmony_ci        if (pss->expected_read_bytes%128)
1629141cc406Sopenharmony_ci        {
1630141cc406Sopenharmony_ci            pss->expected_read_bytes =
1631141cc406Sopenharmony_ci                (pss->expected_read_bytes/128 + 1)*128;
1632141cc406Sopenharmony_ci        }
1633141cc406Sopenharmony_ci        status = scsi_read (pss, READ_TRANSTIME);
1634141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "scsi_read");
1635141cc406Sopenharmony_ci        DBG (DL_VERBOSE, "%s: read %ld bytes.\n", me, (long) pss->read_bytes);
1636141cc406Sopenharmony_ci    }
1637141cc406Sopenharmony_ci
1638141cc406Sopenharmony_ci    pss->expected_read_bytes = 0;
1639141cc406Sopenharmony_ci    status = scsi_read (pss, READ_TRANSTIME);
1640141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
1641141cc406Sopenharmony_ci    {
1642141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR, "%s: test read failed.\n", me);
1643141cc406Sopenharmony_ci        return status;
1644141cc406Sopenharmony_ci    }
1645141cc406Sopenharmony_ci
1646141cc406Sopenharmony_ci    DBG (DL_VERBOSE, "%s: successfully calibrated transfer rate.\n", me);
1647141cc406Sopenharmony_ci    return status;
1648141cc406Sopenharmony_ci}
1649141cc406Sopenharmony_ci
1650141cc406Sopenharmony_ci
1651141cc406Sopenharmony_ciSANE_Status sane_start (SANE_Handle h)
1652141cc406Sopenharmony_ci{
1653141cc406Sopenharmony_ci    static const char *me = "sane_snapscan_start";
1654141cc406Sopenharmony_ci    SANE_Status status;
1655141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1656141cc406Sopenharmony_ci
1657141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s (%p)\n", me, (void *) h);
1658141cc406Sopenharmony_ci
1659141cc406Sopenharmony_ci    /* possible authorization required */
1660141cc406Sopenharmony_ci
1661141cc406Sopenharmony_ci    status = open_scanner (pss);
1662141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "open_scanner");
1663141cc406Sopenharmony_ci
1664141cc406Sopenharmony_ci    status = wait_scanner_ready (pss);
1665141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "wait_scanner_ready");
1666141cc406Sopenharmony_ci
1667141cc406Sopenharmony_ci    /* start scanning; reserve the unit first, because a release_unit is
1668141cc406Sopenharmony_ci       necessary to abort a scan in progress */
1669141cc406Sopenharmony_ci
1670141cc406Sopenharmony_ci    pss->state = ST_SCAN_INIT;
1671141cc406Sopenharmony_ci
1672141cc406Sopenharmony_ci    if ((pss->pdev->model == SCANWIT2720S) && (pss->focus_mode == MD_AUTO))
1673141cc406Sopenharmony_ci    {
1674141cc406Sopenharmony_ci        status = get_focus(pss);
1675141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "get_focus");
1676141cc406Sopenharmony_ci    }
1677141cc406Sopenharmony_ci
1678141cc406Sopenharmony_ci    reserve_unit(pss);
1679141cc406Sopenharmony_ci
1680141cc406Sopenharmony_ci    if (pss->pdev->model == SCANWIT2720S)
1681141cc406Sopenharmony_ci    {
1682141cc406Sopenharmony_ci        status = set_frame(pss, 0);
1683141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "set_frame");
1684141cc406Sopenharmony_ci        status = set_focus(pss, pss->focus);
1685141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "set_focus");
1686141cc406Sopenharmony_ci    }
1687141cc406Sopenharmony_ci
1688141cc406Sopenharmony_ci    /* set up the window and fetch the resulting scanner parameters */
1689141cc406Sopenharmony_ci    status = set_window(pss);
1690141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "set_window");
1691141cc406Sopenharmony_ci
1692141cc406Sopenharmony_ci    status = inquiry(pss);
1693141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "inquiry");
1694141cc406Sopenharmony_ci
1695141cc406Sopenharmony_ci    /* download the gamma and halftone tables */
1696141cc406Sopenharmony_ci
1697141cc406Sopenharmony_ci    status = download_gamma_tables(pss);
1698141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "download_gamma_tables");
1699141cc406Sopenharmony_ci
1700141cc406Sopenharmony_ci    status = download_halftone_matrices(pss);
1701141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "download_halftone_matrices");
1702141cc406Sopenharmony_ci
1703141cc406Sopenharmony_ci    if (pss->val[OPT_QUALITY_CAL].b && (pss->usb_vendor == USB_VENDOR_EPSON))
1704141cc406Sopenharmony_ci    {
1705141cc406Sopenharmony_ci        status = calibrate(pss);
1706141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1707141cc406Sopenharmony_ci        {
1708141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR, "%s: calibration failed.\n", me);
1709141cc406Sopenharmony_ci            release_unit (pss);
1710141cc406Sopenharmony_ci            return status;
1711141cc406Sopenharmony_ci        }
1712141cc406Sopenharmony_ci    }
1713141cc406Sopenharmony_ci
1714141cc406Sopenharmony_ci    /* we must measure the data transfer rate between the host and the
1715141cc406Sopenharmony_ci       scanner, and the method varies depending on whether there is a
1716141cc406Sopenharmony_ci       ring buffer or not. */
1717141cc406Sopenharmony_ci
1718141cc406Sopenharmony_ci    status = measure_transfer_rate(pss);
1719141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "measure_transfer_rate");
1720141cc406Sopenharmony_ci
1721141cc406Sopenharmony_ci    /* now perform an inquiry again to retrieve the scan speed */
1722141cc406Sopenharmony_ci    status = inquiry(pss);
1723141cc406Sopenharmony_ci    CHECK_STATUS (status, me, "inquiry");
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci    DBG (DL_DATA_TRACE,
1726141cc406Sopenharmony_ci         "%s: after measuring speed:\n\t%lu bytes per scan line\n"
1727141cc406Sopenharmony_ci         "\t%f milliseconds per scan line.\n\t==>%f bytes per millisecond\n",
1728141cc406Sopenharmony_ci         me,
1729141cc406Sopenharmony_ci         (u_long) pss->bytes_per_line,
1730141cc406Sopenharmony_ci         pss->ms_per_line,
1731141cc406Sopenharmony_ci         pss->bytes_per_line/pss->ms_per_line);
1732141cc406Sopenharmony_ci
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci    if (pss->val[OPT_QUALITY_CAL].b && (pss->usb_vendor != USB_VENDOR_EPSON))
1735141cc406Sopenharmony_ci    {
1736141cc406Sopenharmony_ci        status = calibrate(pss);
1737141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1738141cc406Sopenharmony_ci        {
1739141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR, "%s: calibration failed.\n", me);
1740141cc406Sopenharmony_ci            release_unit (pss);
1741141cc406Sopenharmony_ci            return status;
1742141cc406Sopenharmony_ci        }
1743141cc406Sopenharmony_ci    }
1744141cc406Sopenharmony_ci
1745141cc406Sopenharmony_ci    status = scan(pss);
1746141cc406Sopenharmony_ci    if (status != SANE_STATUS_GOOD)
1747141cc406Sopenharmony_ci    {
1748141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR, "%s: scan command failed: %s.\n", me, sane_strstatus(status));
1749141cc406Sopenharmony_ci        release_unit (pss);
1750141cc406Sopenharmony_ci        return status;
1751141cc406Sopenharmony_ci    }
1752141cc406Sopenharmony_ci
1753141cc406Sopenharmony_ci    if (pss->pdev->model == SCANWIT2720S)
1754141cc406Sopenharmony_ci    {
1755141cc406Sopenharmony_ci        status = set_frame(pss, pss->frame_no);
1756141cc406Sopenharmony_ci        CHECK_STATUS (status, me, "set_frame");
1757141cc406Sopenharmony_ci    }
1758141cc406Sopenharmony_ci
1759141cc406Sopenharmony_ci    if (pss->source == SRC_ADF)
1760141cc406Sopenharmony_ci    {
1761141cc406Sopenharmony_ci        /* Wait for scanner ready again (e.g. until paper is loaded from an ADF) */
1762141cc406Sopenharmony_ci        /* Maybe replace with get_data_buffer_status()? */
1763141cc406Sopenharmony_ci        status = wait_scanner_ready (pss);
1764141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1765141cc406Sopenharmony_ci        {
1766141cc406Sopenharmony_ci            DBG (DL_MAJOR_ERROR, "%s: scan command failed while waiting for scanner: %s.\n", me, sane_strstatus(status));
1767141cc406Sopenharmony_ci            release_unit (pss);
1768141cc406Sopenharmony_ci            return status;
1769141cc406Sopenharmony_ci        }
1770141cc406Sopenharmony_ci    }
1771141cc406Sopenharmony_ci
1772141cc406Sopenharmony_ci    DBG (DL_MINOR_INFO, "%s: starting the reader process.\n", me);
1773141cc406Sopenharmony_ci    status = start_reader(pss);
1774141cc406Sopenharmony_ci    {
1775141cc406Sopenharmony_ci        BaseSourceType st = FD_SRC;
1776141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD)
1777141cc406Sopenharmony_ci            st = SCSI_SRC;
1778141cc406Sopenharmony_ci        status = create_source_chain (pss, st, &(pss->psrc));
1779141cc406Sopenharmony_ci    }
1780141cc406Sopenharmony_ci
1781141cc406Sopenharmony_ci    return status;
1782141cc406Sopenharmony_ci}
1783141cc406Sopenharmony_ci
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ciSANE_Status sane_read (SANE_Handle h,
1786141cc406Sopenharmony_ci                       SANE_Byte *buf,
1787141cc406Sopenharmony_ci                       SANE_Int maxlen,
1788141cc406Sopenharmony_ci                       SANE_Int *plen)
1789141cc406Sopenharmony_ci{
1790141cc406Sopenharmony_ci    static const char *me = "sane_snapscan_read";
1791141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1792141cc406Sopenharmony_ci    SANE_Status status = SANE_STATUS_GOOD;
1793141cc406Sopenharmony_ci
1794141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE,
1795141cc406Sopenharmony_ci        "%s (%p, %p, %ld, %p)\n",
1796141cc406Sopenharmony_ci        me,
1797141cc406Sopenharmony_ci        (void *) h,
1798141cc406Sopenharmony_ci        (void *) buf,
1799141cc406Sopenharmony_ci        (long) maxlen,
1800141cc406Sopenharmony_ci        (void *) plen);
1801141cc406Sopenharmony_ci
1802141cc406Sopenharmony_ci    *plen = 0;
1803141cc406Sopenharmony_ci
1804141cc406Sopenharmony_ci    if (pss->state == ST_CANCEL_INIT) {
1805141cc406Sopenharmony_ci        pss->state = ST_IDLE;
1806141cc406Sopenharmony_ci        return SANE_STATUS_CANCELLED;
1807141cc406Sopenharmony_ci    }
1808141cc406Sopenharmony_ci
1809141cc406Sopenharmony_ci    if (pss->psrc == NULL  ||  pss->psrc->remaining(pss->psrc) == 0)
1810141cc406Sopenharmony_ci    {
1811141cc406Sopenharmony_ci      if (sanei_thread_is_valid (pss->child))
1812141cc406Sopenharmony_ci        {
1813141cc406Sopenharmony_ci            sanei_thread_waitpid (pss->child, 0);        /* ensure no zombies */
1814141cc406Sopenharmony_ci            sanei_thread_invalidate (pss->child);
1815141cc406Sopenharmony_ci        }
1816141cc406Sopenharmony_ci        release_unit (pss);
1817141cc406Sopenharmony_ci        close_scanner (pss);
1818141cc406Sopenharmony_ci        if (pss->psrc != NULL)
1819141cc406Sopenharmony_ci        {
1820141cc406Sopenharmony_ci            pss->psrc->done(pss->psrc);
1821141cc406Sopenharmony_ci            free(pss->psrc);
1822141cc406Sopenharmony_ci            pss->psrc = NULL;
1823141cc406Sopenharmony_ci        }
1824141cc406Sopenharmony_ci        pss->state = ST_IDLE;
1825141cc406Sopenharmony_ci        return SANE_STATUS_EOF;
1826141cc406Sopenharmony_ci    }
1827141cc406Sopenharmony_ci
1828141cc406Sopenharmony_ci    *plen = maxlen;
1829141cc406Sopenharmony_ci    status = pss->psrc->get(pss->psrc, buf, plen);
1830141cc406Sopenharmony_ci
1831141cc406Sopenharmony_ci    switch (pss->state)
1832141cc406Sopenharmony_ci    {
1833141cc406Sopenharmony_ci    case ST_IDLE:
1834141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
1835141cc406Sopenharmony_ci            "%s: weird error: scanner state should not be idle on call to "
1836141cc406Sopenharmony_ci            "sane_read.\n",
1837141cc406Sopenharmony_ci            me);
1838141cc406Sopenharmony_ci        break;
1839141cc406Sopenharmony_ci    case ST_SCAN_INIT:
1840141cc406Sopenharmony_ci        /* we've read some data */
1841141cc406Sopenharmony_ci        pss->state = ST_SCANNING;
1842141cc406Sopenharmony_ci        break;
1843141cc406Sopenharmony_ci    case ST_CANCEL_INIT:
1844141cc406Sopenharmony_ci        /* stop scanning */
1845141cc406Sopenharmony_ci        status = SANE_STATUS_CANCELLED;
1846141cc406Sopenharmony_ci        break;
1847141cc406Sopenharmony_ci    default:
1848141cc406Sopenharmony_ci        break;
1849141cc406Sopenharmony_ci    }
1850141cc406Sopenharmony_ci
1851141cc406Sopenharmony_ci    return status;
1852141cc406Sopenharmony_ci}
1853141cc406Sopenharmony_ci
1854141cc406Sopenharmony_civoid sane_cancel (SANE_Handle h)
1855141cc406Sopenharmony_ci{
1856141cc406Sopenharmony_ci    char *me = "sane_snapscan_cancel";
1857141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1858141cc406Sopenharmony_ci    struct SIGACTION act;
1859141cc406Sopenharmony_ci    SANE_Pid         res;
1860141cc406Sopenharmony_ci
1861141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1862141cc406Sopenharmony_ci    switch (pss->state)
1863141cc406Sopenharmony_ci    {
1864141cc406Sopenharmony_ci    case ST_IDLE:
1865141cc406Sopenharmony_ci        break;
1866141cc406Sopenharmony_ci    case ST_SCAN_INIT:
1867141cc406Sopenharmony_ci    case ST_SCANNING:
1868141cc406Sopenharmony_ci        /* signal a cancellation has occurred */
1869141cc406Sopenharmony_ci        pss->state = ST_CANCEL_INIT;
1870141cc406Sopenharmony_ci        /* signal the reader, if any */
1871141cc406Sopenharmony_ci        if (sanei_thread_is_valid (pss->child))
1872141cc406Sopenharmony_ci        {
1873141cc406Sopenharmony_ci            DBG( DL_INFO, "---- killing reader_process ----\n" );
1874141cc406Sopenharmony_ci
1875141cc406Sopenharmony_ci            sigemptyset(&(act.sa_mask));
1876141cc406Sopenharmony_ci            act.sa_flags = 0;
1877141cc406Sopenharmony_ci
1878141cc406Sopenharmony_ci            act.sa_handler = sigalarm_handler;
1879141cc406Sopenharmony_ci            sigaction( SIGALRM, &act, 0 );
1880141cc406Sopenharmony_ci
1881141cc406Sopenharmony_ci            if (sanei_thread_is_forked())
1882141cc406Sopenharmony_ci            {
1883141cc406Sopenharmony_ci                /* use SIGUSR1 to set cancelRead in child process */
1884141cc406Sopenharmony_ci                sanei_thread_sendsig( pss->child, SIGUSR1 );
1885141cc406Sopenharmony_ci            }
1886141cc406Sopenharmony_ci            else
1887141cc406Sopenharmony_ci            {
1888141cc406Sopenharmony_ci                cancelRead = SANE_TRUE;
1889141cc406Sopenharmony_ci            }
1890141cc406Sopenharmony_ci
1891141cc406Sopenharmony_ci            /* give'em 10 seconds 'til done...*/
1892141cc406Sopenharmony_ci            alarm(10);
1893141cc406Sopenharmony_ci            res = sanei_thread_waitpid( pss->child, 0 );
1894141cc406Sopenharmony_ci            alarm(0);
1895141cc406Sopenharmony_ci
1896141cc406Sopenharmony_ci            if( res != pss->child ) {
1897141cc406Sopenharmony_ci                DBG( DL_MINOR_ERROR,"sanei_thread_waitpid() failed !\n");
1898141cc406Sopenharmony_ci
1899141cc406Sopenharmony_ci                /* do it the hard way...*/
1900141cc406Sopenharmony_ci#ifdef USE_PTHREAD
1901141cc406Sopenharmony_ci                sanei_thread_kill( pss->child );
1902141cc406Sopenharmony_ci#else
1903141cc406Sopenharmony_ci                sanei_thread_sendsig( pss->child, SIGKILL );
1904141cc406Sopenharmony_ci#endif
1905141cc406Sopenharmony_ci            }
1906141cc406Sopenharmony_ci            sanei_thread_invalidate( pss->child );
1907141cc406Sopenharmony_ci            DBG( DL_INFO,"reader_process killed\n");
1908141cc406Sopenharmony_ci        }
1909141cc406Sopenharmony_ci        release_unit (pss);
1910141cc406Sopenharmony_ci        close_scanner (pss);
1911141cc406Sopenharmony_ci        break;
1912141cc406Sopenharmony_ci    case ST_CANCEL_INIT:
1913141cc406Sopenharmony_ci        DBG (DL_INFO, "%s: cancellation already initiated.\n", me);
1914141cc406Sopenharmony_ci        break;
1915141cc406Sopenharmony_ci    default:
1916141cc406Sopenharmony_ci        DBG (DL_MAJOR_ERROR,
1917141cc406Sopenharmony_ci             "%s: weird error: invalid scanner state (%ld).\n",
1918141cc406Sopenharmony_ci             me,
1919141cc406Sopenharmony_ci             (long) pss->state);
1920141cc406Sopenharmony_ci        break;
1921141cc406Sopenharmony_ci    }
1922141cc406Sopenharmony_ci}
1923141cc406Sopenharmony_ci
1924141cc406Sopenharmony_ciSANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool m)
1925141cc406Sopenharmony_ci{
1926141cc406Sopenharmony_ci    static char me[] = "sane_snapscan_set_io_mode";
1927141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1928141cc406Sopenharmony_ci    char *op;
1929141cc406Sopenharmony_ci
1930141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1931141cc406Sopenharmony_ci
1932141cc406Sopenharmony_ci    if (pss->state != ST_SCAN_INIT)
1933141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
1934141cc406Sopenharmony_ci
1935141cc406Sopenharmony_ci    if (m)
1936141cc406Sopenharmony_ci    {
1937141cc406Sopenharmony_ci      if (!sanei_thread_is_valid (pss->child))
1938141cc406Sopenharmony_ci        {
1939141cc406Sopenharmony_ci            DBG (DL_MINOR_INFO,
1940141cc406Sopenharmony_ci                 "%s: no reader child; must use blocking mode.\n",
1941141cc406Sopenharmony_ci                 me);
1942141cc406Sopenharmony_ci            return SANE_STATUS_UNSUPPORTED;
1943141cc406Sopenharmony_ci        }
1944141cc406Sopenharmony_ci        op = "ON";
1945141cc406Sopenharmony_ci        fcntl (pss->rpipe[0], F_SETFL, O_NONBLOCK | pss->orig_rpipe_flags);
1946141cc406Sopenharmony_ci    }
1947141cc406Sopenharmony_ci    else
1948141cc406Sopenharmony_ci    {
1949141cc406Sopenharmony_ci        op = "OFF";
1950141cc406Sopenharmony_ci        fcntl (pss->rpipe[0], F_SETFL, pss->orig_rpipe_flags);
1951141cc406Sopenharmony_ci    }
1952141cc406Sopenharmony_ci    DBG (DL_MINOR_INFO, "%s: turning nonblocking mode %s.\n", me, op);
1953141cc406Sopenharmony_ci    pss->nonblocking = m;
1954141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1955141cc406Sopenharmony_ci}
1956141cc406Sopenharmony_ci
1957141cc406Sopenharmony_ciSANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int * fd)
1958141cc406Sopenharmony_ci{
1959141cc406Sopenharmony_ci    static char me[] = "sane_snapscan_get_select_fd";
1960141cc406Sopenharmony_ci    SnapScan_Scanner *pss = (SnapScan_Scanner *) h;
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci    DBG (DL_CALL_TRACE, "%s\n", me);
1963141cc406Sopenharmony_ci
1964141cc406Sopenharmony_ci    if (pss->state != ST_SCAN_INIT)
1965141cc406Sopenharmony_ci        return SANE_STATUS_INVAL;
1966141cc406Sopenharmony_ci
1967141cc406Sopenharmony_ci    if (!sanei_thread_is_valid (pss->child))
1968141cc406Sopenharmony_ci    {
1969141cc406Sopenharmony_ci        DBG (DL_MINOR_INFO,
1970141cc406Sopenharmony_ci             "%s: no reader child; cannot provide select file descriptor.\n",
1971141cc406Sopenharmony_ci             me);
1972141cc406Sopenharmony_ci        return SANE_STATUS_UNSUPPORTED;
1973141cc406Sopenharmony_ci    }
1974141cc406Sopenharmony_ci    *fd = pss->rpipe[0];
1975141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
1976141cc406Sopenharmony_ci}
1977141cc406Sopenharmony_ci
1978141cc406Sopenharmony_ci/*
1979141cc406Sopenharmony_ci * Revision 1.73  2008/11/26 21:21:29  kitno-guest
1980141cc406Sopenharmony_ci * * backend/ *.[ch]: nearly every backend used V_MAJOR
1981141cc406Sopenharmony_ci * instead of SANE_CURRENT_MAJOR in sane_init()
1982141cc406Sopenharmony_ci * * backend/snapscan.c: remove EXPECTED_VERSION check
1983141cc406Sopenharmony_ci * since new SANE standard is forward compatible
1984141cc406Sopenharmony_ci *
1985141cc406Sopenharmony_ci * Revision 1.72  2008-05-15 12:50:24  ellert-guest
1986141cc406Sopenharmony_ci * Fix for bug #306751: sanei-thread with pthreads on 64 bit
1987141cc406Sopenharmony_ci *
1988141cc406Sopenharmony_ci * Revision 1.71  2008-01-29 17:48:42  kitno-guest
1989141cc406Sopenharmony_ci * fix snapscan bug, add LiDE 600F
1990141cc406Sopenharmony_ci *
1991141cc406Sopenharmony_ci * Revision 1.70  2007-11-18 10:59:18  ellert-guest
1992141cc406Sopenharmony_ci * Fix handling of valid "negative" PIDs
1993141cc406Sopenharmony_ci *
1994141cc406Sopenharmony_ci * Revision 1.69  2007-11-16 08:04:02  ellert-guest
1995141cc406Sopenharmony_ci * Correct the test of the return value from sanei_thread_begin
1996141cc406Sopenharmony_ci *
1997141cc406Sopenharmony_ci * Revision 1.68  2006-09-03 10:00:11  oliver-guest
1998141cc406Sopenharmony_ci * Bugfix for firmware download by Paul Smedley
1999141cc406Sopenharmony_ci *
2000141cc406Sopenharmony_ci * Revision 1.67  2006/01/10 19:32:16  oliver-guest
2001141cc406Sopenharmony_ci * Added 12 bit gamma tables for Epson Stylus CX-1500
2002141cc406Sopenharmony_ci *
2003141cc406Sopenharmony_ci * Revision 1.66  2006/01/06 20:59:17  oliver-guest
2004141cc406Sopenharmony_ci * Some fixes for the Epson Stylus CX 1500
2005141cc406Sopenharmony_ci *
2006141cc406Sopenharmony_ci * Revision 1.65  2006/01/01 23:02:55  oliver-guest
2007141cc406Sopenharmony_ci * Added snapscan-data.c to Makefile.in
2008141cc406Sopenharmony_ci *
2009141cc406Sopenharmony_ci * Revision 1.64  2005/12/05 20:38:23  oliver-guest
2010141cc406Sopenharmony_ci * Small bugfix for Benq 5150
2011141cc406Sopenharmony_ci *
2012141cc406Sopenharmony_ci * Revision 1.63  2005/12/04 15:03:00  oliver-guest
2013141cc406Sopenharmony_ci * Some fixes for Benq 5150
2014141cc406Sopenharmony_ci *
2015141cc406Sopenharmony_ci * Revision 1.62  2005/12/02 19:15:42  oliver-guest
2016141cc406Sopenharmony_ci * Change SnapScan version number to 1.4.50
2017141cc406Sopenharmony_ci *
2018141cc406Sopenharmony_ci * Revision 1.61  2005/11/15 20:11:19  oliver-guest
2019141cc406Sopenharmony_ci * Enabled quality calibration for the Epson 3490
2020141cc406Sopenharmony_ci *
2021141cc406Sopenharmony_ci * Revision 1.60  2005/11/10 19:42:02  oliver-guest
2022141cc406Sopenharmony_ci * Added deinterlacing for Epson 3490
2023141cc406Sopenharmony_ci *
2024141cc406Sopenharmony_ci * Revision 1.59  2005/11/02 22:12:54  oliver-guest
2025141cc406Sopenharmony_ci * Correct cut'n'paste error
2026141cc406Sopenharmony_ci *
2027141cc406Sopenharmony_ci * Revision 1.58  2005/11/02 19:22:06  oliver-guest
2028141cc406Sopenharmony_ci * Fixes for Benq 5000
2029141cc406Sopenharmony_ci *
2030141cc406Sopenharmony_ci * Revision 1.57  2005/10/31 21:08:47  oliver-guest
2031141cc406Sopenharmony_ci * Distinguish between Benq 5000/5000E/5000U
2032141cc406Sopenharmony_ci *
2033141cc406Sopenharmony_ci * Revision 1.56  2005/10/24 19:46:40  oliver-guest
2034141cc406Sopenharmony_ci * Preview and range fix for Epson 2480/2580
2035141cc406Sopenharmony_ci *
2036141cc406Sopenharmony_ci * Revision 1.55  2005/10/23 21:28:58  oliver-guest
2037141cc406Sopenharmony_ci * Fix for buffer size in high res modes, fixes for delay code
2038141cc406Sopenharmony_ci *
2039141cc406Sopenharmony_ci * Revision 1.54  2005/10/13 22:43:30  oliver-guest
2040141cc406Sopenharmony_ci * Fixes for 16 bit scan mode from Simon Munton
2041141cc406Sopenharmony_ci *
2042141cc406Sopenharmony_ci * Revision 1.53  2005/10/11 18:47:07  oliver-guest
2043141cc406Sopenharmony_ci * Fixes for Epson 3490 and 16 bit scan mode
2044141cc406Sopenharmony_ci *
2045141cc406Sopenharmony_ci * Revision 1.52  2005/09/28 21:33:11  oliver-guest
2046141cc406Sopenharmony_ci * Added 16 bit option for Epson scanners (untested)
2047141cc406Sopenharmony_ci *
2048141cc406Sopenharmony_ci * Revision 1.51  2005/08/15 18:56:55  oliver-guest
2049141cc406Sopenharmony_ci * Added temporary debug code for 2480/2580 distinction
2050141cc406Sopenharmony_ci *
2051141cc406Sopenharmony_ci * Revision 1.50  2005/08/15 18:06:37  oliver-guest
2052141cc406Sopenharmony_ci * Added support for Epson 3490/3590 (thanks to Matt Judge)
2053141cc406Sopenharmony_ci *
2054141cc406Sopenharmony_ci * Revision 1.49  2005/08/07 12:37:29  oliver-guest
2055141cc406Sopenharmony_ci * Use first known device if no device is specified
2056141cc406Sopenharmony_ci *
2057141cc406Sopenharmony_ci * Revision 1.48  2004/12/09 23:21:48  oliver-guest
2058141cc406Sopenharmony_ci * Added quality calibration for Epson 2480 (by Simon Munton)
2059141cc406Sopenharmony_ci *
2060141cc406Sopenharmony_ci * Revision 1.47  2004/12/01 22:49:14  oliver-guest
2061141cc406Sopenharmony_ci * Fix for allocation of gamma tables by Simon Munton
2062141cc406Sopenharmony_ci *
2063141cc406Sopenharmony_ci * Revision 1.46  2004/12/01 22:12:03  oliver-guest
2064141cc406Sopenharmony_ci * Added support for Epson 1270
2065141cc406Sopenharmony_ci *
2066141cc406Sopenharmony_ci * Revision 1.45  2004/10/03 17:34:36  hmg-guest
2067141cc406Sopenharmony_ci * 64 bit platform fixes (bug #300799).
2068141cc406Sopenharmony_ci *
2069141cc406Sopenharmony_ci * Revision 1.44  2004/09/02 20:59:12  oliver-guest
2070141cc406Sopenharmony_ci * Added support for Epson 2480
2071141cc406Sopenharmony_ci *
2072141cc406Sopenharmony_ci * Revision 1.43  2004/06/16 19:52:26  oliver-guest
2073141cc406Sopenharmony_ci * Don't enforce even number of URB packages on 1212u_2. Fixes bug #300753.
2074141cc406Sopenharmony_ci *
2075141cc406Sopenharmony_ci * Revision 1.42  2004/06/15 12:17:37  hmg-guest
2076141cc406Sopenharmony_ci * Only use __attribute__ if gcc is used for compilation. Some other compilers
2077141cc406Sopenharmony_ci * don't know __attribute__ and therefore can't compile sane-backends without this
2078141cc406Sopenharmony_ci * fix. See bug #300803.
2079141cc406Sopenharmony_ci *
2080141cc406Sopenharmony_ci * Revision 1.41  2004/05/26 22:37:01  oliver-guest
2081141cc406Sopenharmony_ci * Use shared memory for urb counters in snapscan backend
2082141cc406Sopenharmony_ci *
2083141cc406Sopenharmony_ci * Revision 1.40  2004/04/09 11:59:02  oliver-guest
2084141cc406Sopenharmony_ci * Fixes for pthread implementation
2085141cc406Sopenharmony_ci *
2086141cc406Sopenharmony_ci * Revision 1.39  2004/04/08 21:53:10  oliver-guest
2087141cc406Sopenharmony_ci * Use sanei_thread in snapscan backend
2088141cc406Sopenharmony_ci *
2089141cc406Sopenharmony_ci * Revision 1.37  2003/11/27 23:11:32  oliver-guest
2090141cc406Sopenharmony_ci * Send gamma table twice for Epson Perfection 1670
2091141cc406Sopenharmony_ci *
2092141cc406Sopenharmony_ci * Revision 1.36  2003/11/09 21:43:45  oliver-guest
2093141cc406Sopenharmony_ci * Disabled quality calibration for Epson Perfection 1670
2094141cc406Sopenharmony_ci *
2095141cc406Sopenharmony_ci * Revision 1.35  2003/11/07 23:26:49  oliver-guest
2096141cc406Sopenharmony_ci * Final bugfixes for bascic support of Epson 1670
2097141cc406Sopenharmony_ci *
2098141cc406Sopenharmony_ci * Revision 1.34  2003/10/21 20:43:25  oliver-guest
2099141cc406Sopenharmony_ci * Bugfixes for SnapScan backend
2100141cc406Sopenharmony_ci *
2101141cc406Sopenharmony_ci * Revision 1.33  2003/10/07 18:29:20  oliver-guest
2102141cc406Sopenharmony_ci * Initial support for Epson 1670, minor bugfix
2103141cc406Sopenharmony_ci *
2104141cc406Sopenharmony_ci * Revision 1.32  2003/09/24 18:05:39  oliver-guest
2105141cc406Sopenharmony_ci * Bug #300198: Check second argument of sanei_config_get_string
2106141cc406Sopenharmony_ci *
2107141cc406Sopenharmony_ci * Revision 1.31  2003/09/12 16:10:33  hmg-guest
2108141cc406Sopenharmony_ci * Moved union Option_Value from backend header files to sanei_backend.h. No need
2109141cc406Sopenharmony_ci * to copy it over and over again. Changed header inclusion order in backend
2110141cc406Sopenharmony_ci * files to include backend.h after sanei_backend.h. Based on a patch from stef
2111141cc406Sopenharmony_ci * <stef-listes@wanadoo.fr>.
2112141cc406Sopenharmony_ci *
2113141cc406Sopenharmony_ci * Revision 1.30  2003/08/19 21:05:08  oliverschwartz
2114141cc406Sopenharmony_ci * Scanner ID cleanup
2115141cc406Sopenharmony_ci *
2116141cc406Sopenharmony_ci * Revision 1.29  2003/04/30 20:49:40  oliverschwartz
2117141cc406Sopenharmony_ci * SnapScan backend 1.4.26
2118141cc406Sopenharmony_ci *
2119141cc406Sopenharmony_ci * Revision 1.58  2003/04/30 20:43:07  oliverschwartz
2120141cc406Sopenharmony_ci * Set backend version number to 1.4.26
2121141cc406Sopenharmony_ci *
2122141cc406Sopenharmony_ci * Revision 1.57  2003/04/02 21:17:14  oliverschwartz
2123141cc406Sopenharmony_ci * Fix for 1200 DPI with Acer 5000
2124141cc406Sopenharmony_ci *
2125141cc406Sopenharmony_ci * Revision 1.56  2003/02/08 10:45:09  oliverschwartz
2126141cc406Sopenharmony_ci * Use 600 DPI as optical resolution for Benq 5000
2127141cc406Sopenharmony_ci *
2128141cc406Sopenharmony_ci * Revision 1.55  2003/01/08 21:16:17  oliverschwartz
2129141cc406Sopenharmony_ci * Added support for Acer / Benq 310U
2130141cc406Sopenharmony_ci *
2131141cc406Sopenharmony_ci * Revision 1.54  2002/12/10 20:14:12  oliverschwartz
2132141cc406Sopenharmony_ci * Enable color offset correction for SnapScan300
2133141cc406Sopenharmony_ci *
2134141cc406Sopenharmony_ci * Revision 1.53  2002/10/31 19:29:41  oliverschwartz
2135141cc406Sopenharmony_ci * Set version to 1.4.17
2136141cc406Sopenharmony_ci *
2137141cc406Sopenharmony_ci * Revision 1.52  2002/10/12 10:40:48  oliverschwartz
2138141cc406Sopenharmony_ci * Added support for Snapscan e10
2139141cc406Sopenharmony_ci *
2140141cc406Sopenharmony_ci * Revision 1.51  2002/09/26 19:27:44  oliverschwartz
2141141cc406Sopenharmony_ci * Version 1.4.16
2142141cc406Sopenharmony_ci *
2143141cc406Sopenharmony_ci * Revision 1.50  2002/09/24 16:07:44  oliverschwartz
2144141cc406Sopenharmony_ci * Added support for Benq 5000
2145141cc406Sopenharmony_ci *
2146141cc406Sopenharmony_ci * Revision 1.49  2002/07/12 22:53:54  oliverschwartz
2147141cc406Sopenharmony_ci * Version 1.4.15
2148141cc406Sopenharmony_ci *
2149141cc406Sopenharmony_ci * Revision 1.48  2002/07/12 22:53:16  oliverschwartz
2150141cc406Sopenharmony_ci * call sanei_usb_init() before sanei_usb_attach_matching_devices()
2151141cc406Sopenharmony_ci *
2152141cc406Sopenharmony_ci * Revision 1.47  2002/06/06 21:16:23  oliverschwartz
2153141cc406Sopenharmony_ci * Set backend version to 1.4.14
2154141cc406Sopenharmony_ci *
2155141cc406Sopenharmony_ci * Revision 1.46  2002/06/06 20:40:01  oliverschwartz
2156141cc406Sopenharmony_ci * Changed default scan area for transparency unit of SnapScan e50
2157141cc406Sopenharmony_ci *
2158141cc406Sopenharmony_ci * Revision 1.45  2002/05/02 18:29:34  oliverschwartz
2159141cc406Sopenharmony_ci * - Added ADF support
2160141cc406Sopenharmony_ci * - Fixed status handling after cancel
2161141cc406Sopenharmony_ci *
2162141cc406Sopenharmony_ci * Revision 1.44  2002/04/27 14:42:30  oliverschwartz
2163141cc406Sopenharmony_ci * Cleanup of debug logging
2164141cc406Sopenharmony_ci *
2165141cc406Sopenharmony_ci * Revision 1.43  2002/04/23 22:40:33  oliverschwartz
2166141cc406Sopenharmony_ci * Improve config file reading
2167141cc406Sopenharmony_ci *
2168141cc406Sopenharmony_ci * Revision 1.42  2002/04/10 21:00:09  oliverschwartz
2169141cc406Sopenharmony_ci * Check for NULL pointer before deleting device list
2170141cc406Sopenharmony_ci *
2171141cc406Sopenharmony_ci * Revision 1.41  2002/03/24 12:12:36  oliverschwartz
2172141cc406Sopenharmony_ci * - Moved option functions to snapscan-options.c
2173141cc406Sopenharmony_ci * - Autodetect USB scanners
2174141cc406Sopenharmony_ci * - Cleanup
2175141cc406Sopenharmony_ci *
2176141cc406Sopenharmony_ci * Revision 1.40  2002/02/09 14:55:23  oliverschwartz
2177141cc406Sopenharmony_ci * Added language translation support (SANE_I18N)
2178141cc406Sopenharmony_ci *
2179141cc406Sopenharmony_ci * Revision 1.39  2002/01/23 20:40:54  oliverschwartz
2180141cc406Sopenharmony_ci * Don't use quantization for scan area parameter
2181141cc406Sopenharmony_ci * Improve recognition of Acer 320U
2182141cc406Sopenharmony_ci * Version 1.4.7
2183141cc406Sopenharmony_ci *
2184141cc406Sopenharmony_ci * Revision 1.38  2002/01/14 21:11:56  oliverschwartz
2185141cc406Sopenharmony_ci * Add workaround for bug semctl() call in libc for PPC
2186141cc406Sopenharmony_ci *
2187141cc406Sopenharmony_ci * Revision 1.37  2002/01/10 21:33:12  oliverschwartz
2188141cc406Sopenharmony_ci * Set version number to 1.4.4
2189141cc406Sopenharmony_ci *
2190141cc406Sopenharmony_ci * Revision 1.36  2002/01/06 18:34:02  oliverschwartz
2191141cc406Sopenharmony_ci * Added support for Snapscan e42 thanks to Yari Ad� Petralanda
2192141cc406Sopenharmony_ci *
2193141cc406Sopenharmony_ci * Revision 1.35  2001/12/20 23:18:01  oliverschwartz
2194141cc406Sopenharmony_ci * Remove tmpfname
2195141cc406Sopenharmony_ci *
2196141cc406Sopenharmony_ci * Revision 1.34  2001/12/18 18:28:35  oliverschwartz
2197141cc406Sopenharmony_ci * Removed temporary file
2198141cc406Sopenharmony_ci *
2199141cc406Sopenharmony_ci * Revision 1.33  2001/12/12 19:43:30  oliverschwartz
2200141cc406Sopenharmony_ci * - Set version number to 1.4.3
2201141cc406Sopenharmony_ci * - Clean up CVS Log
2202141cc406Sopenharmony_ci *
2203141cc406Sopenharmony_ci * Revision 1.32  2001/12/09 23:06:45  oliverschwartz
2204141cc406Sopenharmony_ci * - use sense handler for USB if scanner reports CHECK_CONDITION
2205141cc406Sopenharmony_ci *
2206141cc406Sopenharmony_ci * Revision 1.31  2001/12/08 11:50:34  oliverschwartz
2207141cc406Sopenharmony_ci * Fix dither matrix computation
2208141cc406Sopenharmony_ci *
2209141cc406Sopenharmony_ci * Revision 1.30  2001/11/29 22:50:14  oliverschwartz
2210141cc406Sopenharmony_ci * Add support for SnapScan e52
2211141cc406Sopenharmony_ci *
2212141cc406Sopenharmony_ci * Revision 1.29  2001/11/27 23:16:17  oliverschwartz
2213141cc406Sopenharmony_ci * - Fix color alignment for SnapScan 600
2214141cc406Sopenharmony_ci * - Added documentation in snapscan-sources.c
2215141cc406Sopenharmony_ci * - Guard against TL_X < BR_X and TL_Y < BR_Y
2216141cc406Sopenharmony_ci *
2217141cc406Sopenharmony_ci * Revision 1.28  2001/11/25 18:51:41  oliverschwartz
2218141cc406Sopenharmony_ci * added support for SnapScan e52 thanks to Rui Lopes
2219141cc406Sopenharmony_ci *
2220141cc406Sopenharmony_ci * Revision 1.27  2001/11/16 20:28:35  oliverschwartz
2221141cc406Sopenharmony_ci * add support for Snapscan e26
2222141cc406Sopenharmony_ci *
2223141cc406Sopenharmony_ci * Revision 1.26  2001/11/16 20:23:16  oliverschwartz
2224141cc406Sopenharmony_ci * Merge with sane-1.0.6
2225141cc406Sopenharmony_ci *   - Check USB vendor IDs to avoid hanging scanners
2226141cc406Sopenharmony_ci *   - fix bug in dither matrix computation
2227141cc406Sopenharmony_ci *
2228141cc406Sopenharmony_ci * Revision 1.25  2001/10/25 11:06:22  oliverschwartz
2229141cc406Sopenharmony_ci * Change snapscan backend version number to 1.4.0
2230141cc406Sopenharmony_ci *
2231141cc406Sopenharmony_ci * Revision 1.24  2001/10/11 14:02:10  oliverschwartz
2232141cc406Sopenharmony_ci * Distinguish between e20/e25 and e40/e50
2233141cc406Sopenharmony_ci *
2234141cc406Sopenharmony_ci * Revision 1.23  2001/10/09 22:34:23  oliverschwartz
2235141cc406Sopenharmony_ci * fix compiler warnings
2236141cc406Sopenharmony_ci *
2237141cc406Sopenharmony_ci * Revision 1.22  2001/10/08 19:26:01  oliverschwartz
2238141cc406Sopenharmony_ci * - Disable quality calibration for scanners that do not support it
2239141cc406Sopenharmony_ci *
2240141cc406Sopenharmony_ci * Revision 1.21  2001/10/08 18:22:02  oliverschwartz
2241141cc406Sopenharmony_ci * - Disable quality calibration for Acer Vuego 310F
2242141cc406Sopenharmony_ci * - Use sanei_scsi_max_request_size as scanner buffer size
2243141cc406Sopenharmony_ci *   for SCSI devices
2244141cc406Sopenharmony_ci * - Added new devices to snapscan.desc
2245141cc406Sopenharmony_ci *
2246141cc406Sopenharmony_ci * Revision 1.20  2001/09/18 15:01:07  oliverschwartz
2247141cc406Sopenharmony_ci * - Read scanner id string again after firmware upload
2248141cc406Sopenharmony_ci *   to identify correct model
2249141cc406Sopenharmony_ci * - Make firmware upload work for AGFA scanners
2250141cc406Sopenharmony_ci * - Change copyright notice
2251141cc406Sopenharmony_ci *
2252141cc406Sopenharmony_ci * Revision 1.19  2001/09/17 10:01:08  sable
2253141cc406Sopenharmony_ci * Added model AGFA 1236U
2254141cc406Sopenharmony_ci *
2255141cc406Sopenharmony_ci * Revision 1.18  2001/09/10 10:16:32  oliverschwartz
2256141cc406Sopenharmony_ci * better USB / SCSI recognition, correct max scan area for 1236+TPO
2257141cc406Sopenharmony_ci *
2258141cc406Sopenharmony_ci * Revision 1.17  2001/09/09 18:06:32  oliverschwartz
2259141cc406Sopenharmony_ci * add changes from Acer (new models; automatic firmware upload for USB scanners); fix distorted colour scans after greyscale scans (call set_window only in sane_start); code cleanup
2260141cc406Sopenharmony_ci *
2261141cc406Sopenharmony_ci * Revision 1.16  2001/09/07 09:42:13  oliverschwartz
2262141cc406Sopenharmony_ci * Sync with Sane-1.0.5
2263141cc406Sopenharmony_ci *
2264141cc406Sopenharmony_ci * Revision 1.15  2001/05/15 20:51:14  oliverschwartz
2265141cc406Sopenharmony_ci * check for pss->devname instead of name in sane_open()
2266141cc406Sopenharmony_ci *
2267141cc406Sopenharmony_ci * Revision 1.14  2001/04/10 13:33:06  sable
2268141cc406Sopenharmony_ci * Transparency adapter bug and xsane crash corrections thanks to Oliver Schwartz
2269141cc406Sopenharmony_ci *
2270141cc406Sopenharmony_ci * Revision 1.13  2001/04/10 13:00:31  sable
2271141cc406Sopenharmony_ci * Moving sanei_usb_* to snapscani_usb*
2272141cc406Sopenharmony_ci *
2273141cc406Sopenharmony_ci * Revision 1.12  2001/04/10 11:04:31  sable
2274141cc406Sopenharmony_ci * Adding support for snapscan e40 an e50 thanks to Giuseppe Tanzilli
2275141cc406Sopenharmony_ci *
2276141cc406Sopenharmony_ci * Revision 1.11  2001/03/17 22:53:21  sable
2277141cc406Sopenharmony_ci * Applying Mikael Magnusson patch concerning Gamma correction
2278141cc406Sopenharmony_ci * Support for 1212U_2
2279141cc406Sopenharmony_ci *
2280141cc406Sopenharmony_ci * Revision 1.4  2001/03/04 16:50:53  mikael
2281141cc406Sopenharmony_ci * Added Scan Mode, Geometry, Enhancement and Advanced groups. Implemented brightness and contrast controls with gamma tables. Added Quality Calibration, Analog Gamma Bind, Custom Gamma and Gamma Vector GS,R,G,B options.
2282141cc406Sopenharmony_ci *
2283141cc406Sopenharmony_ci * Revision 1.3  2001/02/16 18:32:28  mikael
2284141cc406Sopenharmony_ci * impl calibration, signed position, increased buffer size
2285141cc406Sopenharmony_ci *
2286141cc406Sopenharmony_ci * Revision 1.2  2001/02/10 18:18:29  mikael
2287141cc406Sopenharmony_ci * Extended x and y ranges
2288141cc406Sopenharmony_ci *
2289141cc406Sopenharmony_ci * Revision 1.1.1.1  2001/02/10 17:09:29  mikael
2290141cc406Sopenharmony_ci * Imported from snapscan-11282000.tar.gz
2291141cc406Sopenharmony_ci *
2292141cc406Sopenharmony_ci * Revision 1.10  2000/11/10 01:01:59  sable
2293141cc406Sopenharmony_ci * USB (kind of) autodetection
2294141cc406Sopenharmony_ci *
2295141cc406Sopenharmony_ci * Revision 1.9  2000/11/01 01:26:43  sable
2296141cc406Sopenharmony_ci * Support for 1212U
2297141cc406Sopenharmony_ci *
2298141cc406Sopenharmony_ci * Revision 1.8  2000/10/30 22:31:13  sable
2299141cc406Sopenharmony_ci * Auto preview mode
2300141cc406Sopenharmony_ci *
2301141cc406Sopenharmony_ci * Revision 1.7  2000/10/28 14:16:10  sable
2302141cc406Sopenharmony_ci * Bug correction for SnapScan310
2303141cc406Sopenharmony_ci *
2304141cc406Sopenharmony_ci * Revision 1.6  2000/10/28 14:06:35  sable
2305141cc406Sopenharmony_ci * Add support for Acer300f
2306141cc406Sopenharmony_ci *
2307141cc406Sopenharmony_ci * Revision 1.5  2000/10/15 19:52:06  cbagwell
2308141cc406Sopenharmony_ci * Changed USB support to a 1 line modification instead of multi-file
2309141cc406Sopenharmony_ci * changes.
2310141cc406Sopenharmony_ci *
2311141cc406Sopenharmony_ci * Revision 1.4  2000/10/13 03:50:27  cbagwell
2312141cc406Sopenharmony_ci * Updating to source from SANE 1.0.3.  Calling this version 1.1
2313141cc406Sopenharmony_ci *
2314141cc406Sopenharmony_ci * Revision 1.3  2000/08/12 15:09:35  pere
2315141cc406Sopenharmony_ci * Merge devel (v1.0.3) into head branch.
2316141cc406Sopenharmony_ci *
2317141cc406Sopenharmony_ci * Revision 1.1.1.1.2.5  2000/07/29 16:04:33  hmg
2318141cc406Sopenharmony_ci * 2000-07-29  Henning Meier-Geinitz <hmg@gmx.de>
2319141cc406Sopenharmony_ci *
2320141cc406Sopenharmony_ci *         * backend/GUIDE: Added some comments about portability and
2321141cc406Sopenharmony_ci *           documentation.
2322141cc406Sopenharmony_ci *         * backend/abaton.c backend/agfafocus.c backend/apple.c
2323141cc406Sopenharmony_ci *           backend/canon.c backend/coolscan.c backend/dc210.c backend/dc25.c
2324141cc406Sopenharmony_ci *           backend/dll.c backend/dmc.c backend/microtek.c backend/microtek2.c
2325141cc406Sopenharmony_ci *            backend/microtek2.c backend/mustek_pp.c backend/net.c backend/pint.c
2326141cc406Sopenharmony_ci *           backend/pnm.c backend/qcam.c backend/ricoh.c backend/s9036.c
2327141cc406Sopenharmony_ci *           backend/sane_strstatus.c backend/sharp.c backend/snapscan.c
2328141cc406Sopenharmony_ci *           backend/st400.c backend/stubs.c backend/tamarack.c backend/v4l.c:
2329141cc406Sopenharmony_ci *           Changed include statements from #include <sane/...> to
2330141cc406Sopenharmony_ci *           #include "sane...".
2331141cc406Sopenharmony_ci *         * backend/avision.c backend/dc25.c: Use DBG(0, ...) instead of
2332141cc406Sopenharmony_ci *            fprintf (stderr, ...)
2333141cc406Sopenharmony_ci *         * backend/avision.c backend/canon-sane.c backend/coolscan.c
2334141cc406Sopenharmony_ci *           backend/dc25.c backend/microtek.c backend/microtek2.c
2335141cc406Sopenharmony_ci *            backend/st400.c: Use sanei_config_read() instead of fgets().
2336141cc406Sopenharmony_ci *         * backend/coolscan.desc backend/microtek.desc backend/microtek2.desc
2337141cc406Sopenharmony_ci *           backend/st400.desc: Added :interface and :manpage entries.
2338141cc406Sopenharmony_ci *         * backend/nec.desc: Status is beta now (was: new). Fixed typo.
2339141cc406Sopenharmony_ci *         * doc/canon.README: Removed, because the information is included in
2340141cc406Sopenharmony_ci *            the manpage now.
2341141cc406Sopenharmony_ci *         * doc/Makefile.in: Added sane-coolscan to list of mapages to install.
2342141cc406Sopenharmony_ci *         * README: Added Link to coolscan manpage.
2343141cc406Sopenharmony_ci *         * backend/mustek.*: Update to Mustek backend 1.0-94. Fixed the
2344141cc406Sopenharmony_ci *           #include <sane/...> bug.
2345141cc406Sopenharmony_ci *
2346141cc406Sopenharmony_ci * Revision 1.1.1.1.2.4  2000/07/25 21:47:43  hmg
2347141cc406Sopenharmony_ci * 2000-07-25  Henning Meier-Geinitz <hmg@gmx.de>
2348141cc406Sopenharmony_ci *
2349141cc406Sopenharmony_ci *         * backend/snapscan.c: Use DBG(0, ...) instead of fprintf (stderr, ...).
2350141cc406Sopenharmony_ci *         * backend/abaton.c backend/agfafocus.c backend/apple.c backend/dc210.c
2351141cc406Sopenharmony_ci *            backend/dll.c backend/dmc.c backend/microtek2.c backend/pint.c
2352141cc406Sopenharmony_ci *           backend/qcam.c backend/ricoh.c backend/s9036.c backend/snapscan.c
2353141cc406Sopenharmony_ci *           backend/tamarack.c: Use sanei_config_read instead of fgets.
2354141cc406Sopenharmony_ci *         * backend/dc210.c backend/microtek.c backend/pnm.c: Added
2355141cc406Sopenharmony_ci *           #include "../include/sane/config.h".
2356141cc406Sopenharmony_ci *         * backend/dc25.c backend/m3096.c  backend/sp15.c
2357141cc406Sopenharmony_ci *            backend/st400.c: Moved #include "../include/sane/config.h" to the beginning.
2358141cc406Sopenharmony_ci *         * AUTHORS: Changed agfa to agfafocus.
2359141cc406Sopenharmony_ci *
2360141cc406Sopenharmony_ci * Revision 1.1.1.1.2.3  2000/07/17 21:37:28  hmg
2361141cc406Sopenharmony_ci * 2000-07-17  Henning Meier-Geinitz <hmg@gmx.de>
2362141cc406Sopenharmony_ci *
2363141cc406Sopenharmony_ci *         * backend/snapscan.c backend/snapscan-scsi.c: Replace C++ comment
2364141cc406Sopenharmony_ci *           with C comment.
2365141cc406Sopenharmony_ci *
2366141cc406Sopenharmony_ci * Revision 1.1.1.1.2.2  2000/07/13 04:47:46  pere
2367141cc406Sopenharmony_ci * New snapscan backend version dated 20000514 from Steve Underwood.
2368141cc406Sopenharmony_ci *
2369141cc406Sopenharmony_ci * Revision 1.2  2000/05/14 13:30:20  coppice
2370141cc406Sopenharmony_ci * R, G and B images now merge correctly. Still some outstanding issues,
2371141cc406Sopenharmony_ci * but a lot more useful than before.
2372141cc406Sopenharmony_ci *
2373141cc406Sopenharmony_ci * Revision 1.2  2000/03/05 13:55:20  pere
2374141cc406Sopenharmony_ci * Merged main branch with current DEVEL_1_9.
2375141cc406Sopenharmony_ci *
2376141cc406Sopenharmony_ci * Revision 1.1.1.1.2.1  1999/09/15 18:20:44  charter
2377141cc406Sopenharmony_ci * Early version 1.0 snapscan.c
2378141cc406Sopenharmony_ci *
2379141cc406Sopenharmony_ci * Revision 2.2  1999/09/09 18:22:45  charter
2380141cc406Sopenharmony_ci * Checkpoint. Now using Sources for scanner data, and have removed
2381141cc406Sopenharmony_ci * references to the old snapscan-310.c stuff. This stuff must still
2382141cc406Sopenharmony_ci * be incorporated into the RGBRouter to get trilinear CCD SnapScan
2383141cc406Sopenharmony_ci * models working.
2384141cc406Sopenharmony_ci *
2385141cc406Sopenharmony_ci * Revision 2.1  1999/09/08 03:07:05  charter
2386141cc406Sopenharmony_ci * Start of branch 2; same as 1.47.
2387141cc406Sopenharmony_ci *
2388141cc406Sopenharmony_ci * Revision 1.47  1999/09/08 03:03:53  charter
2389141cc406Sopenharmony_ci * The actions for the scanner command options now use fprintf for
2390141cc406Sopenharmony_ci * printing, rather than DGB. I want the output to come out no matter
2391141cc406Sopenharmony_ci * what the value of the snapscan debug level.
2392141cc406Sopenharmony_ci *
2393141cc406Sopenharmony_ci * Revision 1.46  1999/09/07 20:53:41  charter
2394141cc406Sopenharmony_ci * Changed expected_data_len to bytes_remaining.
2395141cc406Sopenharmony_ci *
2396141cc406Sopenharmony_ci * Revision 1.45  1999/09/06 23:32:37  charter
2397141cc406Sopenharmony_ci * Split up sane_start() into sub-functions to improve readability (again).
2398141cc406Sopenharmony_ci * Introduced actual_mode() and is_colour_mode() (again).
2399141cc406Sopenharmony_ci * Fixed problems with cancellation. Works fine with my system now.
2400141cc406Sopenharmony_ci *
2401141cc406Sopenharmony_ci * Revision 1.44  1999/09/02 05:28:01  charter
2402141cc406Sopenharmony_ci * Added Gary Plewa's name to the list of copyrighted contributors.
2403141cc406Sopenharmony_ci *
2404141cc406Sopenharmony_ci * Revision 1.43  1999/09/02 05:23:54  charter
2405141cc406Sopenharmony_ci * Added Gary Plewa's patch for the Acer PRISA 620s.
2406141cc406Sopenharmony_ci *
2407141cc406Sopenharmony_ci * Revision 1.42  1999/09/02 02:05:34  charter
2408141cc406Sopenharmony_ci * Check-in of revision 1.42 (release 0.7 of the backend).
2409141cc406Sopenharmony_ci * This is part of the recovery from the great disk crash of Sept 1, 1999.
2410141cc406Sopenharmony_ci *
2411141cc406Sopenharmony_ci * Revision 1.42  1999/07/09 22:37:55  charter
2412141cc406Sopenharmony_ci * Potential bugfix for problems with sane_get_parameters() and
2413141cc406Sopenharmony_ci * the new generic scsi driver (suggested by Francois Desarmeni,
2414141cc406Sopenharmony_ci * Douglas Gilbert, Abel Deuring).
2415141cc406Sopenharmony_ci *
2416141cc406Sopenharmony_ci * Revision 1.41  1999/07/09 20:58:07  charter
2417141cc406Sopenharmony_ci * Changes to support SnapScan 1236s (Petter Reinholdsten).
2418141cc406Sopenharmony_ci *
2419141cc406Sopenharmony_ci * Revision 1.40  1998/12/16 18:43:06  charter
2420141cc406Sopenharmony_ci * Fixed major version problem precipitated by release of SANE-1.00.
2421141cc406Sopenharmony_ci *
2422141cc406Sopenharmony_ci * Revision 1.39  1998/09/07  06:09:26  charter
2423141cc406Sopenharmony_ci * Formatting (whitespace) changes.
2424141cc406Sopenharmony_ci *
2425141cc406Sopenharmony_ci * Revision 1.38  1998/09/07  06:06:01  charter
2426141cc406Sopenharmony_ci * Merged in Wolfgang Goeller's changes (Vuego 310S, bugfixes).
2427141cc406Sopenharmony_ci *
2428141cc406Sopenharmony_ci * Revision 1.37  1998/08/06  06:16:39  charter
2429141cc406Sopenharmony_ci * Now using sane_config_attach_matching_devices() in sane_snapscan_init().
2430141cc406Sopenharmony_ci * Change contributed by David Mosberger-Tang.
2431141cc406Sopenharmony_ci *
2432141cc406Sopenharmony_ci * Revision 1.36  1998/05/11  17:02:53  charter
2433141cc406Sopenharmony_ci * Added Mikko's threshold stuff.
2434141cc406Sopenharmony_ci *
2435141cc406Sopenharmony_ci * Revision 1.35  1998/03/10 23:43:23  eblot
2436141cc406Sopenharmony_ci * Bug correction
2437141cc406Sopenharmony_ci *
2438141cc406Sopenharmony_ci * Revision 0.72  1998/03/10 23:40:42  eblot
2439141cc406Sopenharmony_ci * More support for 310/600 models: color preview, large window
2440141cc406Sopenharmony_ci *
2441141cc406Sopenharmony_ci * Revision 1.35  1998/03/10  21:32:07  eblot
2442141cc406Sopenharmony_ci * Debugging
2443141cc406Sopenharmony_ci *
2444141cc406Sopenharmony_ci * Revision 1.34  1998/02/15  21:55:53  charter
2445141cc406Sopenharmony_ci * From Emmanuel Blot:
2446141cc406Sopenharmony_ci * First routines to support SnapScan 310 scanned data.
2447141cc406Sopenharmony_ci *
2448141cc406Sopenharmony_ci * Revision 1.33  1998/02/06  02:30:28  charter
2449141cc406Sopenharmony_ci * Now using a mode enum (instead of the static string pointers directly).
2450141cc406Sopenharmony_ci * Now check for the SnapScan 310 and 600 explicitly (start of support
2451141cc406Sopenharmony_ci * for these models).
2452141cc406Sopenharmony_ci *
2453141cc406Sopenharmony_ci * Revision 1.32  1998/02/01  21:56:48  charter
2454141cc406Sopenharmony_ci * Patches to fix compilation problems on Solaris supplied by
2455141cc406Sopenharmony_ci * Jim McBeath.
2456141cc406Sopenharmony_ci *
2457141cc406Sopenharmony_ci * Revision 1.31  1998/02/01  03:36:40  charter
2458141cc406Sopenharmony_ci * Now check for BRX < TLX and BRY < TLY and whether the area of the
2459141cc406Sopenharmony_ci * scanning window is approaching zero in set_window. I'm setting a
2460141cc406Sopenharmony_ci * minimum window size of 75x75 hardware pixels (0.25 inches a side).
2461141cc406Sopenharmony_ci * If the area falls to zero, the scanner seems to hang in the middle
2462141cc406Sopenharmony_ci * of the set_window command.
2463141cc406Sopenharmony_ci *
2464141cc406Sopenharmony_ci * Revision 1.30  1998/02/01  00:00:33  charter
2465141cc406Sopenharmony_ci * TLX, TLY, BRX and BRY are now lengths expressed in mm. The frontends
2466141cc406Sopenharmony_ci * can now allow changes in the units, and units that are more user-
2467141cc406Sopenharmony_ci * friendly.
2468141cc406Sopenharmony_ci *
2469141cc406Sopenharmony_ci * Revision 1.29  1998/01/31  21:09:19  charter
2470141cc406Sopenharmony_ci * Fixed another problem with add_device(): if mini_inquiry ends
2471141cc406Sopenharmony_ci * up indirectly invoking the sense handler, there'll be a segfault
2472141cc406Sopenharmony_ci * because the sense_handler isn't set. Had to fix sense_handler so
2473141cc406Sopenharmony_ci * it can handle a NULL pss pointer and then use the sanei_scsi stuff
2474141cc406Sopenharmony_ci * everywhere. This error is most likely to occur if the scanner is
2475141cc406Sopenharmony_ci * turned off.
2476141cc406Sopenharmony_ci *
2477141cc406Sopenharmony_ci * Revision 1.28  1998/01/31  18:45:22  charter
2478141cc406Sopenharmony_ci * Last fix botched, produced a compile error. Thought I'd already
2479141cc406Sopenharmony_ci * compiled successfully.
2480141cc406Sopenharmony_ci *
2481141cc406Sopenharmony_ci * Revision 1.27  1998/01/31  18:32:42  charter
2482141cc406Sopenharmony_ci * Fixed stupid bug in add_device that causes segfault when no snapscan
2483141cc406Sopenharmony_ci * found: closing a scsi fd opened with open() using sanei_scsi_close().
2484141cc406Sopenharmony_ci *
2485141cc406Sopenharmony_ci * Revision 1.26  1998/01/30  21:19:02  charter
2486141cc406Sopenharmony_ci * sane_snapscan_init() handles failure of add_device() in the same
2487141cc406Sopenharmony_ci * way when there is no snapscan.conf file available as when there is
2488141cc406Sopenharmony_ci * one.
2489141cc406Sopenharmony_ci *
2490141cc406Sopenharmony_ci * Revision 1.25  1998/01/30  19:41:11  charter
2491141cc406Sopenharmony_ci * Waiting for child process termination at regular end of scan (not
2492141cc406Sopenharmony_ci * just on cancellation); before I was getting zombies.
2493141cc406Sopenharmony_ci *
2494141cc406Sopenharmony_ci * Revision 1.24  1998/01/30  19:19:27  charter
2495141cc406Sopenharmony_ci * Changed from strncmp() to strncasecmp() to do vendor and model
2496141cc406Sopenharmony_ci * comparisons in sane_snapscan_init. There are some snapcsan models
2497141cc406Sopenharmony_ci * that use lower case.
2498141cc406Sopenharmony_ci * Now have debug level defines instead of raw numbers, and better debug
2499141cc406Sopenharmony_ci * information categories.
2500141cc406Sopenharmony_ci * Don't complain at debug level 0 when a snapscan isn't found on a
2501141cc406Sopenharmony_ci * requested device.
2502141cc406Sopenharmony_ci * Changed CHECK_STATUS to take caller parameter instead of always
2503141cc406Sopenharmony_ci * assuming an available string "me".
2504141cc406Sopenharmony_ci *
2505141cc406Sopenharmony_ci * Revision 1.23  1998/01/30  11:03:04  charter
2506141cc406Sopenharmony_ci * Fixed * vs [] operator precedence screwup in sane_snapscan_get_devices()
2507141cc406Sopenharmony_ci * that caused a segfault in scanimage -h.
2508141cc406Sopenharmony_ci * Fixed problem with not closing the scsi fd between certain commands
2509141cc406Sopenharmony_ci * that caused scanimage to hang; now using open_scanner() and close_scanner().
2510141cc406Sopenharmony_ci *
2511141cc406Sopenharmony_ci * Revision 1.22  1998/01/28  09:02:55  charter
2512141cc406Sopenharmony_ci * Fixed bug: zero allocation length in request sense command buffer
2513141cc406Sopenharmony_ci * was preventing sense information from being received. The
2514141cc406Sopenharmony_ci * backend now correctly waits for the scanner to warm up.
2515141cc406Sopenharmony_ci * Now using the hardware configuration byte to check whether
2516141cc406Sopenharmony_ci * both 8x8 and 16x16 halftoning should be made available.
2517141cc406Sopenharmony_ci *
2518141cc406Sopenharmony_ci * Revision 1.21  1998/01/25  09:57:57  charter
2519141cc406Sopenharmony_ci * Added more SCSI command buttons (and a group for them).
2520141cc406Sopenharmony_ci * Made the output of the Inquiry command a bit nicer.
2521141cc406Sopenharmony_ci *
2522141cc406Sopenharmony_ci * Revision 1.20  1998/01/25  08:53:14  charter
2523141cc406Sopenharmony_ci * Have added bi-level colour mode, with halftones too.
2524141cc406Sopenharmony_ci * Can now select preview mode (but it's an advanced option, since
2525141cc406Sopenharmony_ci * you usually don't want to do it).
2526141cc406Sopenharmony_ci *
2527141cc406Sopenharmony_ci * Revision 1.19  1998/01/25  02:25:02  charter
2528141cc406Sopenharmony_ci * Fixed bug: preview mode gives blank image at initial startup.
2529141cc406Sopenharmony_ci * Fixed bug: lineart mode goes weird after a preview or gs image.
2530141cc406Sopenharmony_ci * More changes to option relationships;
2531141cc406Sopenharmony_ci * now using test_unit_ready and send_diagnostic in sane_snapscan_open().
2532141cc406Sopenharmony_ci * Added negative option.
2533141cc406Sopenharmony_ci *
2534141cc406Sopenharmony_ci * Revision 1.18  1998/01/24  05:15:32  charter
2535141cc406Sopenharmony_ci * Now have RGB gamma correction and dispersed-dot dither halftoning
2536141cc406Sopenharmony_ci * for BW images. Cleaned up some spots in the code and have set up
2537141cc406Sopenharmony_ci * option interactions a bit better (e.g. halftoning and GS gamma
2538141cc406Sopenharmony_ci * correction made inactive in colour mode, etc). TL_[XY] and BR_[XY]
2539141cc406Sopenharmony_ci * now change in ten-pixel increments (I had problems with screwed-up
2540141cc406Sopenharmony_ci * scan lines when the dimensions were weird at low res... could be the
2541141cc406Sopenharmony_ci * problem).
2542141cc406Sopenharmony_ci *
2543141cc406Sopenharmony_ci * Revision 1.17  1998/01/23  13:03:17  charter
2544141cc406Sopenharmony_ci * Several changes, all aimed at getting scanning performance working
2545141cc406Sopenharmony_ci * correctly, and the progress/cancel window functioning. Cleaned up
2546141cc406Sopenharmony_ci * a few nasty things as well.
2547141cc406Sopenharmony_ci *
2548141cc406Sopenharmony_ci * Revision 1.16  1998/01/23  07:40:23  charter
2549141cc406Sopenharmony_ci * Reindented using GNU convention at David Mosberger-Tang's request.
2550141cc406Sopenharmony_ci * Also applied David's patch fixing problems on 64-bit architectures.
2551141cc406Sopenharmony_ci * Now using scanner's reported speed to gauge amount of data to request
2552141cc406Sopenharmony_ci * in a read on the scsi fd---nonblocking mode operates better now.
2553141cc406Sopenharmony_ci * Fixed stupid bug I introduced in preview mode data transfer.
2554141cc406Sopenharmony_ci *
2555141cc406Sopenharmony_ci * Revision 1.15  1998/01/22  06:18:57  charter
2556141cc406Sopenharmony_ci * Raised the priority of a couple of DBG messages in reserve_unit()
2557141cc406Sopenharmony_ci * and release_unit(), and got rid of some unnecessary ones.
2558141cc406Sopenharmony_ci *
2559141cc406Sopenharmony_ci * Revision 1.14  1998/01/22  05:15:35  charter
2560141cc406Sopenharmony_ci * Have replaced the bit depth option with a mode option; various
2561141cc406Sopenharmony_ci * changes associated with that.
2562141cc406Sopenharmony_ci * Also, I again close the STDERR_FILENO in the reader child and
2563141cc406Sopenharmony_ci * dup the STDOUT file descriptor onto it. This prevents an "X io"
2564141cc406Sopenharmony_ci * error when the child exits, while still allowing the use of
2565141cc406Sopenharmony_ci * DBG.
2566141cc406Sopenharmony_ci *
2567141cc406Sopenharmony_ci * Revision 1.13  1998/01/21  20:41:22  charter
2568141cc406Sopenharmony_ci * Added copyright info.
2569141cc406Sopenharmony_ci * Also now seem to have cancellation working. This requires using a
2570141cc406Sopenharmony_ci * new scanner state variable and checking in all the right places
2571141cc406Sopenharmony_ci * in the reader child and the sane_snapscan_read function. I've
2572141cc406Sopenharmony_ci * tested it using both blocking and nonblocking I/O and it seems
2573141cc406Sopenharmony_ci * to work both ways.
2574141cc406Sopenharmony_ci * I've also switched to GTK+-0.99.2 and sane-0.69, and the
2575141cc406Sopenharmony_ci * mysterious problems with the preview window have disappeared.
2576141cc406Sopenharmony_ci * Problems with scanimage doing weird things to options have also
2577141cc406Sopenharmony_ci * gone away and the frontends seem more stable.
2578141cc406Sopenharmony_ci *
2579141cc406Sopenharmony_ci * Revision 1.12  1998/01/21  11:05:53  charter
2580141cc406Sopenharmony_ci * Inoperative code largely #defined out; I had the preview window
2581141cc406Sopenharmony_ci * working correctly by having the window coordinates properly
2582141cc406Sopenharmony_ci * constrained, but now the preview window bombs with a floating-
2583141cc406Sopenharmony_ci * point error each time... I'm not sure yet what happened.
2584141cc406Sopenharmony_ci * I've also figured out that we need to use reserve_unit and
2585141cc406Sopenharmony_ci * release_unit in order to cancel scans in progress. This works
2586141cc406Sopenharmony_ci * under scanimage, but I can't seem to find a way to fit cancellation
2587141cc406Sopenharmony_ci * into xscanimage properly.
2588141cc406Sopenharmony_ci *
2589141cc406Sopenharmony_ci * Revision 1.11  1998/01/20  22:42:08  charter
2590141cc406Sopenharmony_ci * Applied Franck's patch from Dec 17; preview mode is now grayscale.
2591141cc406Sopenharmony_ci *
2592141cc406Sopenharmony_ci * Revision 1.10  1997/12/10  23:33:12  charter
2593141cc406Sopenharmony_ci * Slight change to some floating-point computations in the brightness
2594141cc406Sopenharmony_ci * and contrast stuff. The controls don't seem to do anything to the
2595141cc406Sopenharmony_ci * scanner though (I think these aren't actually supported in the
2596141cc406Sopenharmony_ci * SnapScan).
2597141cc406Sopenharmony_ci *
2598141cc406Sopenharmony_ci * Revision 1.9  1997/11/26  15:40:50  charter
2599141cc406Sopenharmony_ci * Brightness and contrast added by Michel.
2600141cc406Sopenharmony_ci *
2601141cc406Sopenharmony_ci * Revision 1.8  1997/11/12  12:55:40  charter
2602141cc406Sopenharmony_ci * No longer exec after forking to do nonblocking scanning; found how
2603141cc406Sopenharmony_ci * to fix the problems with SIGPIPEs from before.
2604141cc406Sopenharmony_ci * Now support a config file like the other scanner drivers, and
2605141cc406Sopenharmony_ci * can check whether a given device is an AGFA SnapScan (mini_inquiry()).
2606141cc406Sopenharmony_ci *
2607141cc406Sopenharmony_ci * Revision 1.7  1997/11/10  05:52:08  charter
2608141cc406Sopenharmony_ci * Now have the child reader process and pipe stuff working, and
2609141cc406Sopenharmony_ci * nonblocking mode. For large scans the nonblocking mode actually
2610141cc406Sopenharmony_ci * seems to cut down on cpu hogging (though there is still a hit).
2611141cc406Sopenharmony_ci *
2612141cc406Sopenharmony_ci * Revision 1.6  1997/11/03  07:45:54  charter
2613141cc406Sopenharmony_ci * Added the predef_window stuff. I've tried it with 6x4, and it seems
2614141cc406Sopenharmony_ci * to work; I think something gets inconsistent if a preview is
2615141cc406Sopenharmony_ci * performed though.
2616141cc406Sopenharmony_ci *
2617141cc406Sopenharmony_ci * Revision 1.5  1997/11/03  03:15:27  charter
2618141cc406Sopenharmony_ci * Global static variables have now become part of the scanner structure;
2619141cc406Sopenharmony_ci * the inquiry command automatically retrieves window parameters into
2620141cc406Sopenharmony_ci * scanner structure members. Things are a bit cleaned up.
2621141cc406Sopenharmony_ci *
2622141cc406Sopenharmony_ci * Revision 1.4  1997/11/02  23:35:28  charter
2623141cc406Sopenharmony_ci * After much grief.... I can finally scan reliably. Now it's a matter
2624141cc406Sopenharmony_ci * of getting the band arrangement sorted out.
2625141cc406Sopenharmony_ci *
2626141cc406Sopenharmony_ci * Revision 1.3  1997/10/30  07:36:37  charter
2627141cc406Sopenharmony_ci * Fixed a stupid bug in the #defines for the inquiry command, pointed out
2628141cc406Sopenharmony_ci * by Franck.
2629141cc406Sopenharmony_ci *
2630141cc406Sopenharmony_ci * Revision 1.2  1997/10/14  06:00:11  charter
2631141cc406Sopenharmony_ci * Option manipulation and some basic SCSI commands done; the basics
2632141cc406Sopenharmony_ci * for scanning are written but there are bugs. A full scan always hangs
2633141cc406Sopenharmony_ci * the SCSI driver, and preview mode scans complete but it isn't clear
2634141cc406Sopenharmony_ci * whether any meaningful data is received.
2635141cc406Sopenharmony_ci *
2636141cc406Sopenharmony_ci * Revision 1.1  1997/10/13  02:25:54  charter
2637141cc406Sopenharmony_ci * Initial revision
2638141cc406Sopenharmony_ci * */
2639